Skip to content

Commit 2fe1039

Browse files
committed
Escape line breaks in collector error logs
1 parent 9fda81f commit 2fe1039

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

pkg/collectormetrics/collectormetrics.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package collectormetrics
33
import (
44
"context"
55
"log/slog"
6+
"strings"
67
"time"
78

89
cloudcost_exporter "github.com/grafana/cloudcost-exporter"
@@ -67,7 +68,7 @@ func Collect(ctx context.Context, c provider.Collector, ch chan<- prometheus.Met
6768
hasError = true
6869
logger.LogAttrs(ctx, slog.LevelError, "could not collect metrics",
6970
slog.String("collector", c.Name()),
70-
slog.String("message", collectErr.Error()),
71+
slog.String("message", escapeLineBreaks(collectErr.Error())),
7172
)
7273
for _, region := range regions {
7374
errorCounter := errorCounterVec.WithLabelValues(c.Name(), providerName, region)
@@ -82,3 +83,11 @@ func Collect(ctx context.Context, c provider.Collector, ch chan<- prometheus.Met
8283

8384
return duration, hasError
8485
}
86+
87+
func escapeLineBreaks(message string) string {
88+
replacer := strings.NewReplacer(
89+
"\n", "\\n",
90+
"\r", "\\r",
91+
)
92+
return replacer.Replace(message)
93+
}

pkg/collectormetrics/collectormetrics_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package collectormetrics
22

33
import (
4+
"bytes"
45
"context"
6+
"errors"
57
"log/slog"
68
"testing"
79

@@ -92,6 +94,26 @@ func TestCollect_ErrorCounterEmitted(t *testing.T) {
9294
assert.Equal(t, 1.0, counterValue, "error counter should be incremented by 1")
9395
}
9496

97+
func TestCollect_EscapesLineBreaksInLoggedErrorMessage(t *testing.T) {
98+
ch := make(chan prometheus.Metric, 10)
99+
ctrl := gomock.NewController(t)
100+
defer ctrl.Finish()
101+
102+
c := mock_provider.NewMockCollector(ctrl)
103+
c.EXPECT().Name().Return("collector_with_multiline_error").AnyTimes()
104+
c.EXPECT().Collect(gomock.Any(), ch).Return(errors.New("first line\nsecond line\rthird line"))
105+
106+
var logOutput bytes.Buffer
107+
logger := slog.New(slog.NewTextHandler(&logOutput, nil))
108+
109+
Collect(context.Background(), c, ch, logger, "test_provider")
110+
111+
got := logOutput.String()
112+
assert.Contains(t, got, `message="first line\\nsecond line\\rthird line"`)
113+
assert.NotContains(t, got, "first line\nsecond line")
114+
assert.NotContains(t, got, "second line\rthird line")
115+
}
116+
95117
type collectorConfig struct {
96118
name string
97119
collect func(context.Context, chan<- prometheus.Metric) error

0 commit comments

Comments
 (0)