Skip to content

Commit 55ed995

Browse files
committed
TUN-7127: Disconnect logger level requirement for management
By default, we want streaming logs to be able to stream debug logs from cloudflared without needing to update the remote cloudflared's configuration. This disconnects the provided local log level sent to console, file, etc. from the level that management tunnel will utilize via requested filters.
1 parent 820a201 commit 55ed995

File tree

3 files changed

+97
-35
lines changed

3 files changed

+97
-35
lines changed

logger/create.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,36 @@ func fallbackLogger(err error) *zerolog.Logger {
6464
return &failLog
6565
}
6666

67+
// resilientMultiWriter is an alternative to zerolog's so that we can make it resilient to individual
68+
// writer's errors. E.g., when running as a Windows service, the console writer fails, but we don't want to
69+
// allow that to prevent all logging to fail due to breaking the for loop upon an error.
6770
type resilientMultiWriter struct {
68-
writers []io.Writer
71+
level zerolog.Level
72+
writers []io.Writer
73+
managementWriter zerolog.LevelWriter
6974
}
7075

71-
// This custom resilientMultiWriter is an alternative to zerolog's so that we can make it resilient to individual
72-
// writer's errors. E.g., when running as a Windows service, the console writer fails, but we don't want to
73-
// allow that to prevent all logging to fail due to breaking the for loop upon an error.
7476
func (t resilientMultiWriter) Write(p []byte) (n int, err error) {
7577
for _, w := range t.writers {
7678
_, _ = w.Write(p)
7779
}
80+
if t.managementWriter != nil {
81+
_, _ = t.managementWriter.Write(p)
82+
}
83+
return len(p), nil
84+
}
85+
86+
func (t resilientMultiWriter) WriteLevel(level zerolog.Level, p []byte) (n int, err error) {
87+
// Only write the event to normal writers if it exceeds the level, but always write to the
88+
// management logger and let it decided with the provided level of the log event.
89+
if t.level <= level {
90+
for _, w := range t.writers {
91+
_, _ = w.Write(p)
92+
}
93+
}
94+
if t.managementWriter != nil {
95+
_, _ = t.managementWriter.WriteLevel(level, p)
96+
}
7897
return len(p), nil
7998
}
8099

@@ -105,17 +124,18 @@ func newZerolog(loggerConfig *Config) *zerolog.Logger {
105124
writers = append(writers, rollingLogger)
106125
}
107126

127+
var managementWriter zerolog.LevelWriter
108128
if features.Contains(features.FeatureManagementLogs) {
109-
writers = append(writers, ManagementLogger)
129+
managementWriter = ManagementLogger
110130
}
111131

112-
multi := resilientMultiWriter{writers}
113-
114132
level, levelErr := zerolog.ParseLevel(loggerConfig.MinLevel)
115133
if levelErr != nil {
116134
level = zerolog.InfoLevel
117135
}
118-
log := zerolog.New(multi).With().Timestamp().Logger().Level(level)
136+
137+
multi := resilientMultiWriter{level, writers, managementWriter}
138+
log := zerolog.New(multi).With().Timestamp().Logger()
119139
if !levelErrorLogged && levelErr != nil {
120140
log.Error().Msgf("Failed to parse log level %q, using %q instead", loggerConfig.MinLevel, level)
121141
levelErrorLogged = true

logger/create_test.go

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import (
99
"github.com/stretchr/testify/assert"
1010
)
1111

12-
var writeCalls int
13-
1412
type mockedWriter struct {
15-
wantErr bool
13+
wantErr bool
14+
writeCalls int
1615
}
1716

18-
func (c mockedWriter) Write(p []byte) (int, error) {
19-
writeCalls++
17+
func (c *mockedWriter) Write(p []byte) (int, error) {
18+
c.writeCalls++
2019

2120
if c.wantErr {
2221
return -1, errors.New("Expected error")
@@ -26,65 +25,108 @@ func (c mockedWriter) Write(p []byte) (int, error) {
2625
}
2726

2827
// Tests that a new writer is only used if it actually works.
29-
func TestResilientMultiWriter(t *testing.T) {
28+
func TestResilientMultiWriter_Errors(t *testing.T) {
3029
tests := []struct {
3130
name string
32-
writers []io.Writer
31+
writers []*mockedWriter
3332
}{
3433
{
3534
name: "All valid writers",
36-
writers: []io.Writer{
37-
mockedWriter{
35+
writers: []*mockedWriter{
36+
{
3837
wantErr: false,
3938
},
40-
mockedWriter{
39+
{
4140
wantErr: false,
4241
},
4342
},
4443
},
4544
{
4645
name: "All invalid writers",
47-
writers: []io.Writer{
48-
mockedWriter{
46+
writers: []*mockedWriter{
47+
{
4948
wantErr: true,
5049
},
51-
mockedWriter{
50+
{
5251
wantErr: true,
5352
},
5453
},
5554
},
5655
{
5756
name: "First invalid writer",
58-
writers: []io.Writer{
59-
mockedWriter{
57+
writers: []*mockedWriter{
58+
{
6059
wantErr: true,
6160
},
62-
mockedWriter{
61+
{
6362
wantErr: false,
6463
},
6564
},
6665
},
6766
{
6867
name: "First valid writer",
69-
writers: []io.Writer{
70-
mockedWriter{
68+
writers: []*mockedWriter{
69+
{
7170
wantErr: false,
7271
},
73-
mockedWriter{
72+
{
7473
wantErr: true,
7574
},
7675
},
7776
},
7877
}
7978

80-
for _, tt := range tests {
81-
writers := tt.writers
82-
multiWriter := resilientMultiWriter{writers}
79+
for _, test := range tests {
80+
t.Run(test.name, func(t *testing.T) {
81+
writers := []io.Writer{}
82+
for _, w := range test.writers {
83+
writers = append(writers, w)
84+
}
85+
multiWriter := resilientMultiWriter{zerolog.InfoLevel, writers, nil}
86+
87+
logger := zerolog.New(multiWriter).With().Timestamp().Logger()
88+
logger.Info().Msg("Test msg")
89+
90+
for _, w := range test.writers {
91+
// Expect each writer to be written to regardless of the previous writers returning an error
92+
assert.Equal(t, 1, w.writeCalls)
93+
}
94+
})
95+
}
96+
}
97+
98+
type mockedManagementWriter struct {
99+
WriteCalls int
100+
}
101+
102+
func (c *mockedManagementWriter) Write(p []byte) (int, error) {
103+
return len(p), nil
104+
}
105+
106+
func (c *mockedManagementWriter) WriteLevel(level zerolog.Level, p []byte) (int, error) {
107+
c.WriteCalls++
108+
return len(p), nil
109+
}
110+
111+
// Tests that management writer receives write calls of all levels except Disabled
112+
func TestResilientMultiWriter_Management(t *testing.T) {
113+
for _, level := range []zerolog.Level{
114+
zerolog.DebugLevel,
115+
zerolog.InfoLevel,
116+
zerolog.WarnLevel,
117+
zerolog.ErrorLevel,
118+
zerolog.FatalLevel,
119+
zerolog.PanicLevel,
120+
} {
121+
t.Run(level.String(), func(t *testing.T) {
122+
managementWriter := mockedManagementWriter{}
123+
multiWriter := resilientMultiWriter{level, []io.Writer{&mockedWriter{}}, &managementWriter}
83124

84-
logger := zerolog.New(multiWriter).With().Timestamp().Logger().Level(zerolog.InfoLevel)
85-
logger.Info().Msg("Test msg")
125+
logger := zerolog.New(multiWriter).With().Timestamp().Logger()
126+
logger.Info().Msg("Test msg")
86127

87-
assert.Equal(t, len(writers), writeCalls)
88-
writeCalls = 0
128+
// Always write to management
129+
assert.Equal(t, 1, managementWriter.WriteCalls)
130+
})
89131
}
90132
}

management/logger.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewLogger() *Logger {
4141
log := zerolog.New(zerolog.ConsoleWriter{
4242
Out: os.Stdout,
4343
TimeFormat: time.RFC3339,
44-
}).With().Timestamp().Logger().Level(zerolog.DebugLevel)
44+
}).With().Timestamp().Logger().Level(zerolog.InfoLevel)
4545
return &Logger{
4646
Log: &log,
4747
}

0 commit comments

Comments
 (0)