@@ -27,55 +27,59 @@ import (
2727
2828// GoogleCloudSlogHandler wraps Google Cloud Logging's Logger for use with slog.
2929type GoogleCloudSlogHandler struct {
30- client * logging.Client
31- logger * logging.Logger
32- level slog.Level
30+ logger * logging.Logger
31+ client * logging.Client
32+ level slog.Leveler
33+ groupPrefix string
34+ attrs []slog.Attr
3335}
3436
37+ var _ slog.Handler = & GoogleCloudSlogHandler {}
38+
3539// NewGoogleCloudSlogHandler initializes a new GoogleCloudSlogHandler.
36- func NewGoogleCloudSlogHandler (ctx context.Context , projectID , logName string , level slog.Level ) ( * GoogleCloudSlogHandler , error ) {
40+ func NewGoogleCloudSlogHandler (ctx context.Context , projectID , logName string , level slog.Level ) * GoogleCloudSlogHandler {
3741 client , err := logging .NewClient (ctx , projectID )
3842 if err != nil {
39- return nil , fmt . Errorf ( "failed to create logging client: %w" , err )
43+ return nil
4044 }
4145 return & GoogleCloudSlogHandler {
4246 client : client ,
4347 logger : client .Logger (logName ),
4448 level : level ,
45- }, nil
49+ }
50+ }
51+
52+ func (h * GoogleCloudSlogHandler ) Enabled (ctx context.Context , level slog.Level ) bool {
53+ minLevel := slog .LevelInfo
54+ if h .level != nil {
55+ minLevel = h .level .Level ()
56+ }
57+ return level >= minLevel
4658}
4759
4860// Handle adapts slog.Record entries to Google Cloud Logging entries.
4961func (h * GoogleCloudSlogHandler ) Handle (ctx context.Context , r slog.Record ) error {
50- // Convert slog.Level to Google Cloud Logging severity
51- var severity logging.Severity
52- switch r .Level {
53- case slog .LevelDebug :
54- severity = logging .Debug
55- case slog .LevelInfo :
56- severity = logging .Info
57- case slog .LevelWarn :
58- severity = logging .Warning
59- case slog .LevelError :
60- severity = logging .Error
61- default :
62- severity = logging .Default
62+ // Check if the log level is enabled
63+ if ! h .Enabled (ctx , r .Level ) {
64+ return nil
6365 }
6466
65- // Construct the payload with message and additional attributes
67+ // Convert slog.Level to Google Cloud Logging severity
68+ severity := h .mapSeverity (r .Level )
69+
70+ // Construct the payload with message, time, and additional attributes
6671 payload := map [string ]interface {}{
6772 "message" : r .Message ,
68- "level" : r .Level .String (),
6973 "time" : r .Time ,
7074 }
7175
7276 // Add attributes from slog fields
7377 r .Attrs (func (a slog.Attr ) bool {
74- payload [a .Key ] = a .Value
78+ payload [a .Key ] = h . formatAttrValue ( a .Value )
7579 return true
7680 })
7781
78- // Send log entry to Google Cloud Logging
82+ // Send log entry to Google Cloud Logging and return any errors
7983 h .logger .Log (logging.Entry {
8084 Payload : payload ,
8185 Severity : severity ,
@@ -84,6 +88,71 @@ func (h *GoogleCloudSlogHandler) Handle(ctx context.Context, r slog.Record) erro
8488 return nil
8589}
8690
91+ // mapSeverity converts slog.Level to Google Cloud Logging's Severity.
92+ func (h * GoogleCloudSlogHandler ) mapSeverity (level slog.Level ) logging.Severity {
93+ switch level {
94+ case slog .LevelDebug :
95+ return logging .Debug
96+ case slog .LevelInfo :
97+ return logging .Info
98+ case slog .LevelWarn :
99+ return logging .Warning
100+ case slog .LevelError :
101+ return logging .Error
102+ default :
103+ return logging .Default
104+ }
105+ }
106+
107+ // formatAttrValue formats attribute values for Google Cloud Logging.
108+ func (h * GoogleCloudSlogHandler ) formatAttrValue (value interface {}) interface {} {
109+ switch v := value .(type ) {
110+ case string , int , int64 , float64 , bool :
111+ return v
112+ case error :
113+ return v .Error ()
114+ default :
115+ return fmt .Sprintf ("%v" , v ) // Fallback for unsupported types
116+ }
117+ }
118+
119+ func (h * GoogleCloudSlogHandler ) WithAttrs (attrs []slog.Attr ) slog.Handler {
120+ for i , attr := range attrs {
121+ attrs [i ] = withGroupPrefix (h .groupPrefix , attr )
122+ }
123+
124+ return & GoogleCloudSlogHandler {
125+ logger : h .logger ,
126+ level : h .level ,
127+ groupPrefix : h .groupPrefix ,
128+ attrs : append (h .attrs , attrs ... ),
129+ }
130+ }
131+
132+ func (h * GoogleCloudSlogHandler ) WithGroup (name string ) slog.Handler {
133+ if name == "" {
134+ return h
135+ }
136+ prefix := name + "."
137+ if h .groupPrefix != "" {
138+ prefix = h .groupPrefix + prefix
139+ }
140+
141+ return & GoogleCloudSlogHandler {
142+ logger : h .logger ,
143+ level : h .level ,
144+ attrs : h .attrs ,
145+ groupPrefix : prefix ,
146+ }
147+ }
148+
149+ func withGroupPrefix (groupPrefix string , attr slog.Attr ) slog.Attr {
150+ if groupPrefix != "" {
151+ attr .Key = groupPrefix + attr .Key
152+ }
153+ return attr
154+ }
155+
87156// Close closes the Google Cloud Logging client.
88157func (h * GoogleCloudSlogHandler ) Close () error {
89158 return h .client .Close ()
0 commit comments