Skip to content

Commit 0f3ac49

Browse files
committed
cli(debug.zip): add fallback for Datadog multiline log upload request
We are relying on Datadog log API to upload logs and table data. We are receiving cryptic `Decompression error` with 4xx error code. We are suspecting due to request size >5MB post decompression on Datadog end. However, Datadog log API documentation has mentioned that log lines greater than 5MB will get truncated. To address this, we are introducing a fallback for Datadog multiline uplaod where will make Datadog API request for each line from the respective batch. Epic: None Part of: CRDB-51111 Release note: None
1 parent e90488e commit 0f3ac49

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

pkg/cli/zip_upload.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ func uploadZipTables(ctx context.Context, uploadID string, debugDirPath string)
720720
if _, err := uploadLogsToDatadog(
721721
chunk.payload, debugZipUploadOpts.ddAPIKey, debugZipUploadOpts.ddSite,
722722
); err != nil {
723-
fmt.Fprintf(os.Stderr, "failed to upload a part of %s: %s\n", chunk.tableName, err)
723+
uploadIndividualLogToDatadog(chunk)
724724
}
725725
}()
726726
}
@@ -748,6 +748,25 @@ func uploadZipTables(ctx context.Context, uploadID string, debugDirPath string)
748748
return nil
749749
}
750750

751+
// uploadIndividualLogToDatadog is a fallback function to upload the logs to datadog. We would receive cryptic "Decompression error"
752+
// errors from datadog. We are suspecting it is due to the logs being >5MB in size. So, we are uploading individual log
753+
// lines to datadog instead of the whole payload.
754+
func uploadIndividualLogToDatadog(chunk *tableDumpChunk) {
755+
logs, _ := getLogLinesFromPayload(chunk.payload)
756+
var stdErr error
757+
for _, logMap := range logs {
758+
logLine, _ := json.Marshal(logMap)
759+
if _, err := uploadLogsToDatadog(
760+
logLine, debugZipUploadOpts.ddAPIKey, debugZipUploadOpts.ddSite,
761+
); err != nil && stdErr == nil {
762+
stdErr = err
763+
}
764+
}
765+
if stdErr != nil {
766+
fmt.Fprintf(os.Stderr, "failed to upload a part of %s: %s\n", chunk.tableName, stdErr)
767+
}
768+
}
769+
751770
type ddArchivePayload struct {
752771
Type string `json:"type"`
753772
Attributes ddArchiveAttributes `json:"attributes"`
@@ -829,6 +848,7 @@ type logUploadSig struct {
829848
// number of lines and the size of the payload. But in case of CRDB logs, the
830849
// average size of 1000 lines is well within the limit (5MB). So, we are only
831850
// splitting based on the number of lines.
851+
// TODO(obs-india): consider log size in sig calculation
832852
func (s logUploadSig) split() []logUploadSig {
833853
var (
834854
noOfNewSignals = len(s.logLines)/datadogMaxLogLinesPerReq + 1
@@ -1232,6 +1252,15 @@ func makeDDMultiLineLogPayload(logLines [][]byte) []byte {
12321252
return buf.Bytes()
12331253
}
12341254

1255+
func getLogLinesFromPayload(payload []byte) ([]map[string]any, error) {
1256+
var logs []map[string]any
1257+
err := json.Unmarshal(payload, &logs)
1258+
if err != nil {
1259+
return nil, fmt.Errorf("failed to log lines: %w", err)
1260+
}
1261+
return logs, nil
1262+
}
1263+
12351264
// humanReadableSize converts the given number of bytes to a human readable
12361265
// format. Lowest unit is bytes and the highest unit is petabytes.
12371266
func humanReadableSize(bytes int) string {

0 commit comments

Comments
 (0)