diff --git a/.chloggen/add-scraperID-to-error-logs.yaml b/.chloggen/add-scraperID-to-error-logs.yaml new file mode 100644 index 00000000000..02ff0cd292f --- /dev/null +++ b/.chloggen/add-scraperID-to-error-logs.yaml @@ -0,0 +1,13 @@ +# 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. receiver/otlp) +component: pkg/scraperhelper + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: ScraperID has been added to the logs for metrics, logs, and profiles + +# One or more tracking issues or pull requests related to the change +issues: [14461] diff --git a/scraper/scraperhelper/controller_test.go b/scraper/scraperhelper/controller_test.go index 1ec22dff8b2..8366dd677cd 100644 --- a/scraper/scraperhelper/controller_test.go +++ b/scraper/scraperhelper/controller_test.go @@ -16,6 +16,8 @@ import ( "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.uber.org/multierr" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" @@ -763,3 +765,59 @@ func TestNewDefaultControllerConfig(t *testing.T) { intControllerConfig := controller.NewDefaultControllerConfig() require.Equal(t, intControllerConfig, controllerConfig) } + +func TestNewMetricsController_ScraperIDInErrorLogs(t *testing.T) { + t.Parallel() + + core, observedLogs := observer.New(zap.ErrorLevel) + tel := componenttest.NewTelemetry() + t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) + telset := tel.NewTelemetrySettings() + telset.Logger = zap.New(core) + + receiverID := component.MustNewID("fakeReceiver") + scraperType := component.MustNewType("fakeScraper") + scrapeErr := errors.New("scrape error") + + scrapeCh := make(chan int, 1) + ts := &testScrape{ch: scrapeCh, err: scrapeErr} + scp, err := scraper.NewMetrics(ts.scrapeMetrics) + require.NoError(t, err) + + cfg := newTestNoDelaySettings() + tickerCh := make(chan time.Time) + + recv, err := NewMetricsController( + cfg, + receiver.Settings{ID: receiverID, TelemetrySettings: telset, BuildInfo: component.NewDefaultBuildInfo()}, + new(consumertest.MetricsSink), + AddMetricsScraper(scraperType, scp), + WithTickerChannel(tickerCh), + ) + require.NoError(t, err) + require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) + defer func() { require.NoError(t, recv.Shutdown(context.Background())) }() + + <-scrapeCh + + require.Eventually(t, func() bool { + return observedLogs.Len() >= 1 + }, time.Second, 10*time.Millisecond) + errorLogs := observedLogs.FilterLevelExact(zap.ErrorLevel).All() + require.Len(t, errorLogs, 1) + + assert.Equal(t, "Error scraping metrics", errorLogs[0].Message) + assert.Equal(t, scraperType.String(), errorLogs[0].ContextMap()["scraper"]) + assert.Equal(t, scrapeErr.Error(), errorLogs[0].ContextMap()["error"]) + + // Verify the original receiver telemetry settings logger was NOT mutated + // by logging something and checking it doesn't have the scraper field + telset.Logger.Error("test log from receiver") + + allLogs := observedLogs.FilterLevelExact(zap.ErrorLevel).All() + require.Len(t, allLogs, 2) + + receiverLog := allLogs[1] + assert.Equal(t, "test log from receiver", receiverLog.Message) + assert.NotContains(t, receiverLog.ContextMap(), "scraper") +} diff --git a/scraper/scraperhelper/internal/controller/controller.go b/scraper/scraperhelper/internal/controller/controller.go index 3d00113c969..60f37cc9e2f 100644 --- a/scraper/scraperhelper/internal/controller/controller.go +++ b/scraper/scraperhelper/internal/controller/controller.go @@ -11,6 +11,7 @@ import ( "time" "go.uber.org/multierr" + "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/receiver" @@ -124,9 +125,12 @@ func (sc *Controller[T]) startScraping() { } func GetSettings(sType component.Type, rSet receiver.Settings) scraper.Settings { + id := component.NewID(sType) + telemetry := rSet.TelemetrySettings + telemetry.Logger = telemetry.Logger.With(zap.String("scraper", id.String())) return scraper.Settings{ - ID: component.NewID(sType), - TelemetrySettings: rSet.TelemetrySettings, + ID: id, + TelemetrySettings: telemetry, BuildInfo: rSet.BuildInfo, } } diff --git a/scraper/scraperhelper/obs_logs_test.go b/scraper/scraperhelper/obs_logs_test.go index 454bf51f947..2153580cb88 100644 --- a/scraper/scraperhelper/obs_logs_test.go +++ b/scraper/scraperhelper/obs_logs_test.go @@ -14,12 +14,16 @@ import ( "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" + "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/scraper" + "go.opentelemetry.io/collector/scraper/scraperhelper/internal/controller" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadatatest" ) @@ -97,6 +101,36 @@ func TestCheckScraperLogs(t *testing.T) { checkScraperLogs(t, tel, receiverID, scraperID, 7, 0) } +func TestScrapeLogsDataOp_LogsScraperID(t *testing.T) { + tel := componenttest.NewTelemetry() + t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) + + core, observedLogs := observer.New(zap.ErrorLevel) + telset := tel.NewTelemetrySettings() + telset.Logger = zap.New(core) + + rSet := receiver.Settings{ + ID: receiverID, + TelemetrySettings: telset, + } + set := controller.GetSettings(scraperID.Type(), rSet) + + sm, err := scraper.NewLogs(func(context.Context) (plog.Logs, error) { + return plog.NewLogs(), errFake + }) + require.NoError(t, err) + sf, err := wrapObsLogs(sm, receiverID, scraperID, set.TelemetrySettings) + require.NoError(t, err) + _, err = sf.ScrapeLogs(context.Background()) + require.ErrorIs(t, err, errFake) + + errorLogs := observedLogs.FilterLevelExact(zap.ErrorLevel).All() + require.Len(t, errorLogs, 1) + assert.Equal(t, "Error scraping logs", errorLogs[0].Message) + assert.Equal(t, scraperID.String(), errorLogs[0].ContextMap()["scraper"]) + assert.Equal(t, errFake.Error(), errorLogs[0].ContextMap()["error"]) +} + func checkScraperLogs(t *testing.T, tel *componenttest.Telemetry, receiver, scraper component.ID, scrapedLogRecords, erroredLogRecords int64) { metadatatest.AssertEqualScraperScrapedLogRecords(t, tel, []metricdata.DataPoint[int64]{ diff --git a/scraper/scraperhelper/obs_metrics_test.go b/scraper/scraperhelper/obs_metrics_test.go index 2a9cf4e989c..14a0e961983 100644 --- a/scraper/scraperhelper/obs_metrics_test.go +++ b/scraper/scraperhelper/obs_metrics_test.go @@ -14,13 +14,17 @@ import ( "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" + "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" + "go.opentelemetry.io/collector/scraper/scraperhelper/internal/controller" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadatatest" ) @@ -110,6 +114,36 @@ func TestCheckScraperMetrics(t *testing.T) { checkScraperMetrics(t, tel, receiverID, scraperID, 7, 0) } +func TestScrapeMetricsDataOp_LogsScraperID(t *testing.T) { + tel := componenttest.NewTelemetry() + t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) + + core, observedLogs := observer.New(zap.ErrorLevel) + telset := tel.NewTelemetrySettings() + telset.Logger = zap.New(core) + + rSet := receiver.Settings{ + ID: receiverID, + TelemetrySettings: telset, + } + set := controller.GetSettings(scraperID.Type(), rSet) + + sm, err := scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { + return pmetric.NewMetrics(), errFake + }) + require.NoError(t, err) + sf, err := wrapObsMetrics(sm, receiverID, scraperID, set.TelemetrySettings) + require.NoError(t, err) + _, err = sf.ScrapeMetrics(context.Background()) + require.ErrorIs(t, err, errFake) + + errorLogs := observedLogs.FilterLevelExact(zap.ErrorLevel).All() + require.Len(t, errorLogs, 1) + assert.Equal(t, "Error scraping metrics", errorLogs[0].Message) + assert.Equal(t, scraperID.String(), errorLogs[0].ContextMap()["scraper"]) + assert.Equal(t, errFake.Error(), errorLogs[0].ContextMap()["error"]) +} + func checkScraperMetrics(t *testing.T, tt *componenttest.Telemetry, receiver, scraper component.ID, scrapedMetricPoints, erroredMetricPoints int64) { metadatatest.AssertEqualScraperScrapedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ diff --git a/scraper/scraperhelper/xscraperhelper/obs_profiles_test.go b/scraper/scraperhelper/xscraperhelper/obs_profiles_test.go index bf90b3a875b..3a10da77665 100644 --- a/scraper/scraperhelper/xscraperhelper/obs_profiles_test.go +++ b/scraper/scraperhelper/xscraperhelper/obs_profiles_test.go @@ -15,12 +15,16 @@ import ( "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" + "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/scraper/scrapererror" + "go.opentelemetry.io/collector/scraper/scraperhelper/internal/controller" "go.opentelemetry.io/collector/scraper/scraperhelper/xscraperhelper/internal/metadatatest" "go.opentelemetry.io/collector/scraper/xscraper" ) @@ -112,6 +116,36 @@ func TestCheckScraperProfiles(t *testing.T) { checkScraperProfiles(t, tel, receiverID, scraperID, 7, 0) } +func TestScrapeProfilesDataOp_LogsScraperID(t *testing.T) { + tel := componenttest.NewTelemetry() + t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) + + core, observedLogs := observer.New(zap.ErrorLevel) + telset := tel.NewTelemetrySettings() + telset.Logger = zap.New(core) + + rSet := receiver.Settings{ + ID: receiverID, + TelemetrySettings: telset, + } + set := controller.GetSettings(scraperID.Type(), rSet) + + sm, err := xscraper.NewProfiles(func(context.Context) (pprofile.Profiles, error) { + return pprofile.NewProfiles(), errFake + }) + require.NoError(t, err) + sf, err := wrapObsProfiles(sm, receiverID, scraperID, set.TelemetrySettings) + require.NoError(t, err) + _, err = sf.ScrapeProfiles(context.Background()) + require.ErrorIs(t, err, errFake) + + errorLogs := observedLogs.FilterLevelExact(zap.ErrorLevel).All() + require.Len(t, errorLogs, 1) + assert.Equal(t, "Error scraping profiles", errorLogs[0].Message) + assert.Equal(t, scraperID.String(), errorLogs[0].ContextMap()["scraper"]) + assert.Equal(t, errFake.Error(), errorLogs[0].ContextMap()["error"]) +} + func checkScraperProfiles(t *testing.T, tel *componenttest.Telemetry, receiver, scraper component.ID, scrapedProfileRecords, erroredProfileRecords int64) { metadatatest.AssertEqualScraperScrapedProfileRecords(t, tel, []metricdata.DataPoint[int64]{