Skip to content

Commit d2f17ae

Browse files
authored
Merge pull request #40 from hashicorp/f-std-force-level
Allow Standard Logger to force log level
2 parents 85dc09e + 0864b16 commit d2f17ae

File tree

4 files changed

+110
-2
lines changed

4 files changed

+110
-2
lines changed

intlogger.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,5 +519,9 @@ func (l *intLogger) StandardLogger(opts *StandardLoggerOptions) *log.Logger {
519519
}
520520

521521
func (l *intLogger) StandardWriter(opts *StandardLoggerOptions) io.Writer {
522-
return &stdlogAdapter{l, opts.InferLevels}
522+
return &stdlogAdapter{
523+
log: l,
524+
inferLevels: opts.InferLevels,
525+
forceLevel: opts.ForceLevel,
526+
}
523527
}

logger.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ type StandardLoggerOptions struct {
143143
// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
144144
// [DEBUG] and strip it off before reapplying it.
145145
InferLevels bool
146+
147+
// ForceLevel is used to force all output from the standard logger to be at
148+
// the specified level. Similar to InferLevels, this will strip any level
149+
// prefix contained in the logged string before applying the forced level.
150+
// If set, this override InferLevels.
151+
ForceLevel Level
146152
}
147153

148154
// LoggerOptions can be used to configure a new logger.

stdlog.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,35 @@ import (
1111
type stdlogAdapter struct {
1212
log Logger
1313
inferLevels bool
14+
forceLevel Level
1415
}
1516

1617
// Take the data, infer the levels if configured, and send it through
1718
// a regular Logger.
1819
func (s *stdlogAdapter) Write(data []byte) (int, error) {
1920
str := string(bytes.TrimRight(data, " \t\n"))
2021

21-
if s.inferLevels {
22+
if s.forceLevel != NoLevel {
23+
// Use pickLevel to strip log levels included in the line since we are
24+
// forcing the level
25+
_, str := s.pickLevel(str)
26+
27+
// Log at the forced level
28+
switch s.forceLevel {
29+
case Trace:
30+
s.log.Trace(str)
31+
case Debug:
32+
s.log.Debug(str)
33+
case Info:
34+
s.log.Info(str)
35+
case Warn:
36+
s.log.Warn(str)
37+
case Error:
38+
s.log.Error(str)
39+
default:
40+
s.log.Info(str)
41+
}
42+
} else if s.inferLevels {
2243
level, str := s.pickLevel(str)
2344
switch level {
2445
case Trace:

stdlog_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package hclog
22

33
import (
4+
"bytes"
5+
"strings"
46
"testing"
57

68
"github.com/stretchr/testify/assert"
@@ -61,3 +63,78 @@ func TestStdlogAdapter(t *testing.T) {
6163
assert.Equal(t, "coffee?", rest)
6264
})
6365
}
66+
67+
func TestStdlogAdapter_ForceLevel(t *testing.T) {
68+
cases := []struct {
69+
name string
70+
forceLevel Level
71+
inferLevels bool
72+
write string
73+
expect string
74+
}{
75+
{
76+
name: "force error",
77+
forceLevel: Error,
78+
write: "this is a test",
79+
expect: "[ERROR] test: this is a test\n",
80+
},
81+
{
82+
name: "force error overrides infer",
83+
forceLevel: Error,
84+
inferLevels: true,
85+
write: "[DEBUG] this is a test",
86+
expect: "[ERROR] test: this is a test\n",
87+
},
88+
{
89+
name: "force error and strip debug",
90+
forceLevel: Error,
91+
write: "[DEBUG] this is a test",
92+
expect: "[ERROR] test: this is a test\n",
93+
},
94+
{
95+
name: "force trace",
96+
forceLevel: Trace,
97+
write: "this is a test",
98+
expect: "[TRACE] test: this is a test\n",
99+
},
100+
{
101+
name: "force trace and strip higher level error",
102+
forceLevel: Trace,
103+
write: "[WARN] this is a test",
104+
expect: "[TRACE] test: this is a test\n",
105+
},
106+
{
107+
name: "force with invalid level",
108+
forceLevel: -10,
109+
write: "this is a test",
110+
expect: "[INFO] test: this is a test\n",
111+
},
112+
}
113+
114+
for _, c := range cases {
115+
t.Run(c.name, func(t *testing.T) {
116+
var stderr bytes.Buffer
117+
118+
logger := New(&LoggerOptions{
119+
Name: "test",
120+
Output: &stderr,
121+
Level: Trace,
122+
})
123+
124+
s := &stdlogAdapter{
125+
log: logger,
126+
forceLevel: c.forceLevel,
127+
inferLevels: c.inferLevels,
128+
}
129+
130+
_, err := s.Write([]byte(c.write))
131+
assert.NoError(t, err)
132+
133+
errStr := stderr.String()
134+
errDataIdx := strings.IndexByte(errStr, ' ')
135+
errRest := errStr[errDataIdx+1:]
136+
137+
assert.Equal(t, c.expect, errRest)
138+
})
139+
}
140+
}

0 commit comments

Comments
 (0)