From bcc9b0a79730598a7e30460b581d335b01d476fb Mon Sep 17 00:00:00 2001 From: Robert Fratto Date: Thu, 29 Feb 2024 10:41:42 -0500 Subject: [PATCH] flow/logging: check for nil values when writing logs (#6561) There may be situations where the flow mode logger receivers a nil value, potentially due to misconfiguration or a component which exports its values only after being ran. Fixes #6557. --- CHANGELOG.md | 2 ++ pkg/flow/logging/logger.go | 9 +++++++++ pkg/flow/logging/logger_test.go | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b047b7701..6c268fc70b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ Main (unreleased) - Fix an issue where a custom component might be wired to a local declare instead of an import declare when they have the same label. (@wildum) +- Fix an issue where flow mode panics if the `logging` config block is given a `null` Loki receiver to write log entries to. (@rfratto) + v0.40.0 (2024-02-27) -------------------- diff --git a/pkg/flow/logging/logger.go b/pkg/flow/logging/logger.go index 5689d00fe0..1856c54654 100644 --- a/pkg/flow/logging/logger.go +++ b/pkg/flow/logging/logger.go @@ -164,6 +164,15 @@ type lokiWriter struct { func (fw *lokiWriter) Write(p []byte) (int, error) { for _, receiver := range fw.f { + // We may have been given a nil value in rare circumstances due to + // misconfiguration or a component which generates exports after + // construction. + // + // Ignore nil values so we don't panic. + if receiver == nil { + continue + } + select { case receiver.Chan() <- loki.Entry{ Labels: model.LabelSet{"component": "agent"}, diff --git a/pkg/flow/logging/logger_test.go b/pkg/flow/logging/logger_test.go index d199f14887..cf3f7a66c1 100644 --- a/pkg/flow/logging/logger_test.go +++ b/pkg/flow/logging/logger_test.go @@ -11,6 +11,7 @@ import ( "github.com/go-kit/log" gokitlevel "github.com/go-kit/log/level" + "github.com/grafana/agent/component/common/loki" "github.com/grafana/agent/pkg/flow/logging" flowlevel "github.com/grafana/agent/pkg/flow/logging/level" "github.com/stretchr/testify/require" @@ -165,6 +166,25 @@ func TestLevels(t *testing.T) { } } +// Test_lokiWriter_nil ensures that writing to a lokiWriter doesn't panic when +// given a nil receiver. +func Test_lokiWriter_nil(t *testing.T) { + logger, err := logging.New(io.Discard, debugLevel()) + require.NoError(t, err) + + err = logger.Update(logging.Options{ + Level: logging.LevelDebug, + Format: logging.FormatLogfmt, + + WriteTo: []loki.LogsReceiver{nil}, + }) + require.NoError(t, err) + + require.NotPanics(t, func() { + _ = logger.Log("msg", "test message") + }) +} + func BenchmarkLogging_NoLevel_Prints(b *testing.B) { logger, err := logging.New(io.Discard, infoLevel()) require.NoError(b, err)