From f222e2e08bbd636fe75108199c8814c674042876 Mon Sep 17 00:00:00 2001
From: Robert Fratto <robertfratto@gmail.com>
Date: Thu, 29 Feb 2024 14:24:19 -0500
Subject: [PATCH] Prepare release v0.40.1 (#6569)

* ignore errors when the logging node empties the log buffer (#6558)

(cherry picked from commit b691a44b47b3d443cf9fa462190069ed5ff5b98f)

* Fix wiring of custom component nodes (#6563)

* fix wiring of custom component nodes by checking import before local declares

* update changelog

* add comment in loader to explain why the imports should be checked before the local declare

(cherry picked from commit 0dde507f404ca2236789f8fe35ecb5f916ab50e4)

* 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.

(cherry picked from commit bcc9b0a79730598a7e30460b581d335b01d476fb)

* changelog: cut 0.40.1 (#6568)

(cherry picked from commit 9154af36520ee2ff4f368daa62f883504d67ac82)

---------

Co-authored-by: William Dumont <william.dumont@grafana.com>
---
 CHANGELOG.md                                  | 11 ++++++
 docs/sources/_index.md                        |  2 +-
 pkg/flow/internal/controller/loader.go        | 10 +++---
 pkg/flow/logging/logger.go                    | 15 ++++++--
 pkg/flow/logging/logger_test.go               | 20 +++++++++++
 .../testdata/import_file/import_file_16.txtar | 36 +++++++++++++++++++
 pkg/operator/defaults.go                      |  2 +-
 tools/gen-versioned-files/agent-version.txt   |  2 +-
 8 files changed, 88 insertions(+), 10 deletions(-)
 create mode 100644 pkg/flow/testdata/import_file/import_file_16.txtar

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a220278e711..48f592c8165a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,17 @@ internal API changes are not present.
 
 
 
+v0.40.1 (2024-02-27)
+--------------------
+
+### Bugfixes
+
+- Fix an issues where the logging config block would trigger an error when trying to send logs to components that were not running. (@wildum)
+
+- 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/docs/sources/_index.md b/docs/sources/_index.md
index 605655ef6a7d..556ea167a769 100644
--- a/docs/sources/_index.md
+++ b/docs/sources/_index.md
@@ -9,7 +9,7 @@ title: Grafana Agent
 description: Grafana Agent is a flexible, performant, vendor-neutral, telemetry collector
 weight: 350
 cascade:
-  AGENT_RELEASE: v0.40.0
+  AGENT_RELEASE: v0.40.1
   OTEL_VERSION: v0.87.0
 ---
 
diff --git a/pkg/flow/internal/controller/loader.go b/pkg/flow/internal/controller/loader.go
index 741f4e4d5c25..79779837cce9 100644
--- a/pkg/flow/internal/controller/loader.go
+++ b/pkg/flow/internal/controller/loader.go
@@ -589,15 +589,17 @@ func (l *Loader) wireGraphEdges(g *dag.Graph) diag.Diagnostics {
 
 // wireCustomComponentNode wires a custom component to the import/declare nodes that it depends on.
 func (l *Loader) wireCustomComponentNode(g *dag.Graph, cc *CustomComponentNode) {
-	if declare, ok := l.declareNodes[cc.customComponentName]; ok {
+	// It's important to check first if the importNamespace matches an import node because there might be a
+	// local node that has the same label as an imported declare.
+	if importNode, ok := l.importConfigNodes[cc.importNamespace]; ok {
+		// add an edge between the custom component and the corresponding import node.
+		g.AddEdge(dag.Edge{From: cc, To: importNode})
+	} else if declare, ok := l.declareNodes[cc.customComponentName]; ok {
 		refs := l.findCustomComponentReferences(declare.Block())
 		for ref := range refs {
 			// add edges between the custom component and declare/import nodes.
 			g.AddEdge(dag.Edge{From: cc, To: ref})
 		}
-	} else if importNode, ok := l.importConfigNodes[cc.importNamespace]; ok {
-		// add an edge between the custom component and the corresponding import node.
-		g.AddEdge(dag.Edge{From: cc, To: importNode})
 	}
 }
 
diff --git a/pkg/flow/logging/logger.go b/pkg/flow/logging/logger.go
index da0046a281af..1856c5465401 100644
--- a/pkg/flow/logging/logger.go
+++ b/pkg/flow/logging/logger.go
@@ -126,9 +126,9 @@ func (l *Logger) Update(o Options) error {
 
 	// Print out the buffered logs since we determined the log format already
 	for _, bufferedLogChunk := range l.buffer {
-		if err := slogadapter.GoKit(l.handler).Log(bufferedLogChunk...); err != nil {
-			return err
-		}
+		// the buffered logs are currently only sent to the standard output
+		// because the components with the receivers are not running yet
+		slogadapter.GoKit(l.handler).Log(bufferedLogChunk...)
 	}
 	l.buffer = nil
 
@@ -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 d199f1488747..cf3f7a66c139 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)
diff --git a/pkg/flow/testdata/import_file/import_file_16.txtar b/pkg/flow/testdata/import_file/import_file_16.txtar
new file mode 100644
index 000000000000..804c7c6d751e
--- /dev/null
+++ b/pkg/flow/testdata/import_file/import_file_16.txtar
@@ -0,0 +1,36 @@
+Imported declare and local declare have the same label.
+
+-- main.river --
+testcomponents.count "inc" {
+	frequency = "10ms"
+	max = 10
+}
+
+import.file "certmanager" {
+	filename = "module.river"
+}
+
+certmanager.config "this" { 
+	input = testcomponents.count.inc.count
+}
+
+declare "config" {
+}
+
+testcomponents.summation "sum" {
+	input = certmanager.config.this.output
+}
+
+-- module.river --
+declare "config" {
+	argument "input" {}
+
+	testcomponents.passthrough "pt" {
+		input = argument.input.value
+		lag = "1ms"
+	}
+
+	export "output" {
+		value = testcomponents.passthrough.pt.output
+	}
+}
\ No newline at end of file
diff --git a/pkg/operator/defaults.go b/pkg/operator/defaults.go
index d62a46a1ece9..e985937bb348 100644
--- a/pkg/operator/defaults.go
+++ b/pkg/operator/defaults.go
@@ -2,7 +2,7 @@ package operator
 
 // Supported versions of the Grafana Agent.
 var (
-	DefaultAgentVersion   = "v0.40.0"
+	DefaultAgentVersion   = "v0.40.1"
 	DefaultAgentBaseImage = "grafana/agent"
 	DefaultAgentImage     = DefaultAgentBaseImage + ":" + DefaultAgentVersion
 )
diff --git a/tools/gen-versioned-files/agent-version.txt b/tools/gen-versioned-files/agent-version.txt
index dbccec6e080f..01437515a7c3 100644
--- a/tools/gen-versioned-files/agent-version.txt
+++ b/tools/gen-versioned-files/agent-version.txt
@@ -1 +1 @@
-v0.40.0
\ No newline at end of file
+v0.40.1