diff --git a/CHANGELOG.md b/CHANGELOG.md index c6be29c5588..ee9e141f493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Expose `pcommon.NewSliceFromRaw` function (#5679) - `loggingexporter`: create the exporter's logger from the service's logger (#5677) - Add `otelcol_exporter_queue_capacity` metrics show the collector's exporter queue capacity (#5475) +- Add support to handle 402, 413, 414, 431 http error code as permanent errors in OTLP exporter (#5685) ### 🧰 Bug fixes 🧰 diff --git a/exporter/otlphttpexporter/otlp.go b/exporter/otlphttpexporter/otlp.go index 181ba978e48..4498a80e632 100644 --- a/exporter/otlphttpexporter/otlp.go +++ b/exporter/otlphttpexporter/otlp.go @@ -178,8 +178,8 @@ func (e *exporter) export(ctx context.Context, url string, request []byte) error return exporterhelper.NewThrottleRetry(formattedErr, time.Duration(retryAfter)*time.Second) } - if resp.StatusCode == http.StatusBadRequest { - // Report the failure as permanent if the server thinks the request is malformed. + if isPermanentClientFailure(resp.StatusCode) { + // Do not retry; report the failure as permanent if the server thinks the request is malformed. return consumererror.NewPermanent(formattedErr) } @@ -187,6 +187,25 @@ func (e *exporter) export(ctx context.Context, url string, request []byte) error return formattedErr } +// Does the 'code' indicate a permanent error +func isPermanentClientFailure(code int) bool { + switch code { + case http.StatusBadRequest: + return true + case http.StatusPaymentRequired: + // 402 - payment required typically means that an auth token isn't valid anymore and as such, we deem it as permanent + return true + case http.StatusRequestEntityTooLarge: + return true + case http.StatusRequestURITooLong: + return true + case http.StatusRequestHeaderFieldsTooLarge: + return true + default: + return false + } +} + // Read the response and decode the status.Status from the body. // Returns nil if the response is empty or cannot be decoded. func readResponse(resp *http.Response) *status.Status { diff --git a/exporter/otlphttpexporter/otlp_test.go b/exporter/otlphttpexporter/otlp_test.go index 249f899e27c..e0a8f9842f6 100644 --- a/exporter/otlphttpexporter/otlp_test.go +++ b/exporter/otlphttpexporter/otlp_test.go @@ -393,11 +393,35 @@ func TestErrorResponses(t *testing.T) { responseBody: status.New(codes.InvalidArgument, "Bad field"), isPermErr: true, }, + { + name: "402", + responseStatus: http.StatusPaymentRequired, + responseBody: status.New(codes.InvalidArgument, "Bad field"), + isPermErr: true, + }, { name: "404", responseStatus: http.StatusNotFound, err: errors.New(errMsgPrefix + "404"), }, + { + name: "413", + responseStatus: http.StatusRequestEntityTooLarge, + responseBody: status.New(codes.InvalidArgument, "Bad field"), + isPermErr: true, + }, + { + name: "414", + responseStatus: http.StatusRequestURITooLong, + responseBody: status.New(codes.InvalidArgument, "Bad field"), + isPermErr: true, + }, + { + name: "431", + responseStatus: http.StatusRequestHeaderFieldsTooLarge, + responseBody: status.New(codes.InvalidArgument, "Bad field"), + isPermErr: true, + }, { name: "419", responseStatus: http.StatusTooManyRequests,