@@ -5,27 +5,42 @@ import (
55 "log/slog"
66 "os"
77 "runtime/pprof"
8+ "slices"
89
910 "go.opentelemetry.io/otel/baggage"
1011)
1112
12- var ExampleOpts = Options {
13+ var ExampleOptions = Options {
14+ Level : LevelEverything ,
1315 OmitTime : true ,
1416 OmitSource : true ,
17+ ContextKey : SetAttrs ,
18+ LevelKey : SetLevel ,
1519}
1620
21+ type ctxkey int
22+
23+ // Context key variables for the examples.
24+ const (
25+ _ ctxkey = iota
26+ SetAttrs
27+ SetLevel
28+ )
29+
1730func Example () {
18- h := NewHandler (os .Stdout , & ExampleOpts )
31+ h := NewHandler (os .Stdout , & ExampleOptions )
1932 slog .New (h ).With ("a" , "b" ).Info ("test" , "c" , "d" )
2033
2134 // Output:
2235 // {"level":"INFO","msg":"test","a":"b","c":"d"}
2336}
2437
38+ // In this example, some values are extracted from the pprof labels and inserted
39+ // into the record.
2540func Example_pprof () {
2641 ctx := pprof .WithLabels (context .Background (), pprof .Labels ("test_kind" , "example" ))
2742 pprof .SetGoroutineLabels (ctx )
28- h := NewHandler (os .Stdout , & ExampleOpts )
43+ h := NewHandler (os .Stdout , & ExampleOptions )
2944 slog .New (h ).InfoContext (ctx , "test" )
3045
3146 // Output:
@@ -39,72 +54,119 @@ func must[T any](t T, err error) T {
3954 return t
4055}
4156
57+ // In this example, some values are extracted from the OpenTelemetry baggage and
58+ // inserted into the record.
4259func Example_baggage () {
43- BaggageOpts := Options {
44- OmitTime : true ,
45- OmitSource : true ,
46- Baggage : func (_ string ) bool { return true },
47- }
60+ opts := ExampleOptions
61+ opts .Baggage = func (_ string ) bool { return true }
4862 b := must (baggage .New (
4963 must (baggage .NewMember ("test_kind" , "example" )),
5064 ))
5165 ctx := baggage .ContextWithBaggage (context .Background (), b )
52- h := NewHandler (os .Stdout , & BaggageOpts )
66+ h := NewHandler (os .Stdout , & opts )
5367 slog .New (h ).InfoContext (ctx , "test" )
5468
5569 // Output:
5670 // {"level":"INFO","msg":"test","baggage":{"test_kind":"example"}}
5771}
5872
59- func ExampleWithLevel () {
60- opts := Options {
61- OmitTime : true ,
62- OmitSource : true ,
73+ // In this example, the handler is configured with a very high minimum level, so
74+ // without the per-record level filtering there would be no log messages.
75+ func Example_with_Level () {
76+ // Per-record filter levels.
77+ filters := []slog.Level {slog .LevelDebug , slog .LevelInfo , slog .LevelWarn , slog .LevelError }
78+ // Levels of records to emit.
79+ levels := []slog.Level {slog .LevelDebug - 4 , slog .LevelDebug , slog .LevelInfo , slog .LevelWarn , slog .LevelError }
80+ // With is a helper function to add the log level to the Context at the known key.
81+ //
82+ // Typically, a module would provide a helper to do this.
83+ with := func (ctx context.Context , l slog.Level ) context.Context {
84+ return context .WithValue (ctx , SetLevel , l )
6385 }
64- levels := []slog.Level {slog .LevelDebug , slog .LevelInfo , slog .LevelWarn , slog .LevelError }
86+
87+ // Setup:
6588 ctx := context .Background ()
89+ opts := ExampleOptions
90+ opts .Level = slog .Level (100 )
6691 h := NewHandler (os .Stdout , & opts )
92+ log := slog .New (h )
93+
94+ // Usage:
95+ a := slog .String ("filter" , "NONE" )
6796 for _ , l := range levels {
68- ctx := WithLevel (ctx , l )
69- for i , l := range levels {
70- slog .New (h ).LogAttrs (ctx , l , "normal log message" , slog .Int ("i" , i ))
97+ log .LogAttrs (ctx , l , "" , a )
98+ }
99+ for _ , l := range filters {
100+ a = slog .String ("filter" , l .String ())
101+ ctx := with (ctx , l )
102+ for _ , l := range levels {
103+ log .LogAttrs (ctx , l , "" , a )
71104 }
72105 }
73106
74107 // Output:
75- // {"level":"DEBUG","msg":"normal log message ","i":0 }
76- // {"level":"INFO","msg":"normal log message ","i":1 }
77- // {"level":"WARN","msg":"normal log message ","i":2 }
78- // {"level":"ERROR","msg":"normal log message ","i":3 }
79- // {"level":"INFO","msg":"normal log message ","i":1 }
80- // {"level":"WARN","msg":"normal log message ","i":2 }
81- // {"level":"ERROR","msg":"normal log message ","i":3 }
82- // {"level":"WARN","msg":"normal log message ","i":2 }
83- // {"level":"ERROR","msg":"normal log message ","i":3 }
84- // {"level":"ERROR","msg":"normal log message ","i":3 }
108+ // {"level":"DEBUG","msg":"","filter":"DEBUG" }
109+ // {"level":"INFO","msg":"","filter":"DEBUG" }
110+ // {"level":"WARN","msg":"","filter":"DEBUG" }
111+ // {"level":"ERROR","msg":"","filter":"DEBUG" }
112+ // {"level":"INFO","msg":"","filter":"INFO" }
113+ // {"level":"WARN","msg":"","filter":"INFO" }
114+ // {"level":"ERROR","msg":"","filter":"INFO" }
115+ // {"level":"WARN","msg":"","filter":"WARN" }
116+ // {"level":"ERROR","msg":"","filter":"WARN" }
117+ // {"level":"ERROR","msg":"","filter":"ERROR" }
85118}
86119
87- func ExampleWithAttrs () {
88- opts := Options {
89- OmitTime : true ,
90- OmitSource : true ,
120+ // In this example, there are values stored in the Context at a known key and
121+ // then automatically retrieved and integrated into the record by the handler.
122+ func Example_with_Attrs () {
123+ // With is a helper function to add values to the Context at the known key.
124+ //
125+ // Typically, a module would provide a helper to do this, and do it with
126+ // less garbage. Any ordering or replacement semantics need to happen here;
127+ // this example does not implement being able to remove keys from the
128+ // Context.
129+ with := func (ctx context.Context , args ... any ) context.Context {
130+ var s []slog.Attr
131+ if v , ok := ctx .Value (SetAttrs ).(slog.Value ); ok {
132+ s = v .Group ()
133+ }
134+ s = append (s , slog .Group ("" , args ... ).Value .Group ()... )
135+ seen := make (map [string ]struct {}, len (s ))
136+ del := func (a slog.Attr ) bool {
137+ _ , ok := seen [a .Key ]
138+ seen [a .Key ] = struct {}{}
139+ return ok
140+ }
141+ slices .Reverse (s )
142+ s = slices .DeleteFunc (s , del )
143+ slices .Reverse (s )
144+ return context .WithValue (ctx , SetAttrs , slog .GroupValue (s ... ))
91145 }
146+ // Setup:
92147 ctx := context .Background ()
93- h := NewHandler (os .Stdout , & opts )
148+ h := NewHandler (os .Stdout , & ExampleOptions )
94149 l := slog .New (h )
150+
151+ // Usage:
95152 l .InfoContext (ctx , "without ctx attrs" , "a" , "b" )
96- ctx = WithAttrs (ctx , "contextual" , "value" )
97- l .InfoContext (ctx , "with ctx attrs" , "a" , "b" )
98153 {
99- ctx := WithLevel (ctx , slog .LevelDebug )
100- l .DebugContext (ctx , "with ctx attrs" , "a" , "b" )
154+ ctx := with (ctx , "contextual" , "value" )
155+ l .InfoContext (ctx , "with ctx attrs" , "a" , "b" )
156+ {
157+ ctx := context .WithValue (ctx , SetLevel , slog .LevelDebug )
158+ ctx = with (ctx , "contextual" , "level" )
159+ l .DebugContext (ctx , "with ctx attrs" , "a" , "b" )
160+ }
161+ ctx = with (ctx , "appended" , "value" )
162+ l .InfoContext (ctx , "with more ctx attrs" )
101163 }
102- ctx = WithAttrs (ctx , "contextual" , slog .GroupValue ())
103- l .InfoContext (ctx , "removed ctx attrs" , "a" , "b" )
164+ l .InfoContext (ctx , "without ctx attrs" , "a" , "b" )
104165
105166 // Output:
106167 // {"level":"INFO","msg":"without ctx attrs","a":"b"}
107168 // {"level":"INFO","msg":"with ctx attrs","contextual":"value","a":"b"}
108- // {"level":"DEBUG","msg":"with ctx attrs","contextual":"value","a":"b"}
109- // {"level":"INFO","msg":"removed ctx attrs","a":"b"}
169+ // {"level":"DEBUG","msg":"with ctx attrs","contextual":"level","a":"b"}
170+ // {"level":"INFO","msg":"with more ctx attrs","contextual":"value","appended":"value"}
171+ // {"level":"INFO","msg":"without ctx attrs","a":"b"}
110172}
0 commit comments