From 0de532c2cf95725f35892c71e70b28398dad1fbc Mon Sep 17 00:00:00 2001 From: David Ashpole Date: Wed, 1 Nov 2023 19:14:26 +0000 Subject: [PATCH] log errors even when retry is not used --- .chloggen/fix_logging_without_retry.yaml | 25 ++++++++++++++++++++++++ exporter/exporterhelper/common.go | 19 +++++++++++++++++- exporter/exporterhelper/common_test.go | 15 ++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 .chloggen/fix_logging_without_retry.yaml diff --git a/.chloggen/fix_logging_without_retry.yaml b/.chloggen/fix_logging_without_retry.yaml new file mode 100644 index 00000000000..c654a917981 --- /dev/null +++ b/.chloggen/fix_logging_without_retry.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: exporterhelper + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Log export errors when retry is not used by the component. + +# One or more tracking issues or pull requests related to the change +issues: [8791] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] \ No newline at end of file diff --git a/exporter/exporterhelper/common.go b/exporter/exporterhelper/common.go index cc97cbc3db1..5a34d8de55a 100644 --- a/exporter/exporterhelper/common.go +++ b/exporter/exporterhelper/common.go @@ -10,6 +10,7 @@ import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" + "go.uber.org/zap" ) // requestSender is an abstraction of a sender for a request independent of the type of the data (traces, metrics, logs). @@ -40,6 +41,22 @@ func (b *baseRequestSender) setNextSender(nextSender requestSender) { b.nextSender = nextSender } +type errorLoggingRequestSender struct { + baseRequestSender + logger *zap.Logger +} + +func (l *errorLoggingRequestSender) send(req internal.Request) error { + err := l.nextSender.send(req) + if err != nil { + l.logger.Error( + "Exporting failed", + zap.Error(err), + ) + } + return err +} + type obsrepSenderFactory func(obsrep *ObsReport) requestSender // baseRequest is a base implementation for the internal.Request. @@ -176,7 +193,7 @@ func newBaseExporter(set exporter.CreateSettings, signal component.DataType, req queueSender: &baseRequestSender{}, obsrepSender: osf(obsReport), - retrySender: &baseRequestSender{}, + retrySender: &errorLoggingRequestSender{logger: set.Logger}, timeoutSender: &timeoutSender{cfg: NewDefaultTimeoutSettings()}, set: set, diff --git a/exporter/exporterhelper/common_test.go b/exporter/exporterhelper/common_test.go index 75c915fc43a..10166c32974 100644 --- a/exporter/exporterhelper/common_test.go +++ b/exporter/exporterhelper/common_test.go @@ -12,6 +12,8 @@ import ( "go.opencensus.io/tag" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" @@ -79,3 +81,16 @@ func TestQueueRetryOptionsWithRequestExporter(t *testing.T) { WithRetry(NewDefaultRetrySettings()), WithQueue(NewDefaultQueueSettings())) }) } + +func TestBaseExporterLogging(t *testing.T) { + set := exportertest.NewNopCreateSettings() + logger, observed := observer.New(zap.DebugLevel) + set.Logger = zap.New(logger) + bs, err := newBaseExporter(set, "", true, nil, nil, newNoopObsrepSender) + require.Nil(t, err) + require.True(t, bs.requestExporter) + sendErr := bs.send(newErrorRequest(context.Background())) + require.Error(t, sendErr) + + require.Len(t, observed.FilterLevelExact(zap.ErrorLevel).All(), 1) +}