@@ -22,9 +22,7 @@ import (
22
22
"context"
23
23
"fmt"
24
24
"log/slog"
25
- "os"
26
25
"strings"
27
- "time"
28
26
29
27
"cloud.google.com/go/logging"
30
28
"github.com/jba/slog/withsupport"
@@ -37,29 +35,21 @@ const MetadataKey = "metadata"
37
35
38
36
// Enhanced handler with error handling
39
37
type handler struct {
40
- level slog.Leveler
41
- handleEntry func (logging.Entry )
42
- goa * withsupport.GroupOrAttrs
43
- projectID string
44
- fallbackHandler slog.Handler
45
- instructionsLogged bool
38
+ level slog.Leveler
39
+ handleEntry func (logging.Entry )
40
+ goa * withsupport.GroupOrAttrs
41
+ projectID string
46
42
}
47
43
48
44
func newHandler (level slog.Leveler , f func (logging.Entry ), projectID string ) * handler {
49
45
if level == nil {
50
46
level = slog .LevelInfo
51
47
}
52
48
53
- // Create fallback handler for when GCP logging fails
54
- fallbackHandler := slog .NewTextHandler (os .Stderr , & slog.HandlerOptions {
55
- Level : level ,
56
- })
57
-
58
49
return & handler {
59
- level : level ,
60
- handleEntry : f ,
61
- projectID : projectID ,
62
- fallbackHandler : fallbackHandler ,
50
+ level : level ,
51
+ handleEntry : f ,
52
+ projectID : projectID ,
63
53
}
64
54
}
65
55
@@ -69,21 +59,19 @@ func (h *handler) Enabled(ctx context.Context, level slog.Level) bool {
69
59
70
60
func (h * handler ) WithAttrs (as []slog.Attr ) slog.Handler {
71
61
return & handler {
72
- level : h .level ,
73
- handleEntry : h .handleEntry ,
74
- goa : h .goa .WithAttrs (as ),
75
- projectID : h .projectID ,
76
- fallbackHandler : h .fallbackHandler ,
62
+ level : h .level ,
63
+ handleEntry : h .handleEntry ,
64
+ goa : h .goa .WithAttrs (as ),
65
+ projectID : h .projectID ,
77
66
}
78
67
}
79
68
80
69
func (h * handler ) WithGroup (name string ) slog.Handler {
81
70
return & handler {
82
- level : h .level ,
83
- handleEntry : h .handleEntry ,
84
- goa : h .goa .WithGroup (name ),
85
- projectID : h .projectID ,
86
- fallbackHandler : h .fallbackHandler ,
71
+ level : h .level ,
72
+ handleEntry : h .handleEntry ,
73
+ goa : h .goa .WithGroup (name ),
74
+ projectID : h .projectID ,
87
75
}
88
76
}
89
77
@@ -96,95 +84,16 @@ func (h *handler) Handle(ctx context.Context, r slog.Record) error {
96
84
strings .Contains (message , "google.logging.v2.LoggingServiceV2" )
97
85
98
86
if isInternalGoogleCloudLog {
99
- // Skip internal Google Cloud SDK logs, but send to fallback for debugging if needed
100
- return h . fallbackHandler . Handle ( ctx , r )
87
+ // Skip these logs - they're noise
88
+ return nil
101
89
}
102
90
103
91
entry := h .recordToEntry (ctx , r )
104
92
105
- // Try to send to GCP with error handling and recovery
106
- if err := h .handleWithRecovery (entry ); err != nil {
107
- // Fall back to local logging if GCP fails
108
- return h .fallbackHandler .Handle (ctx , r )
109
- }
110
-
93
+ h .handleEntry (entry )
111
94
return nil
112
95
}
113
96
114
- // handleWithRecovery attempts to send the log entry to GCP
115
- func (h * handler ) handleWithRecovery (entry logging.Entry ) error {
116
- // Attempt to send the log entry
117
- defer func () {
118
- if r := recover (); r != nil {
119
- h .handleError (fmt .Errorf ("panic in GCP logging: %v" , r ))
120
- }
121
- }()
122
-
123
- // Create a channel to capture any errors from the async logging operation
124
- errChan := make (chan error , 1 )
125
-
126
- // Wrap the handleEntry function to capture errors
127
- wrappedHandleEntry := func (entry logging.Entry ) {
128
- defer func () {
129
- if r := recover (); r != nil {
130
- errChan <- fmt .Errorf ("logging operation panic: %v" , r )
131
- } else {
132
- errChan <- nil
133
- }
134
- }()
135
- h .handleEntry (entry )
136
- }
137
-
138
- go wrappedHandleEntry (entry )
139
-
140
- // Wait for completion with timeout
141
- select {
142
- case err := <- errChan :
143
- if err != nil {
144
- h .handleError (err )
145
- return err
146
- }
147
- return nil
148
- case <- time .After (5 * time .Second ):
149
- err := fmt .Errorf ("GCP logging timeout" )
150
- h .handleError (err )
151
- return err
152
- }
153
- }
154
-
155
- // handleError processes logging errors and triggers immediate recovery
156
- func (h * handler ) handleError (err error ) {
157
- // Check if this is a permission denied error for helpful messaging
158
- if loggingDenied (err ) {
159
- h .logPermissionError (err )
160
- } else {
161
- // Log generic error
162
- h .fallbackHandler .Handle (context .Background (), slog .NewRecord (
163
- time .Now (),
164
- slog .LevelError ,
165
- fmt .Sprintf ("Unable to send logs to Google Cloud: %v" , err ),
166
- 0 ,
167
- ))
168
- }
169
-
170
- }
171
-
172
- // logPermissionError logs helpful permission error messages (only once)
173
- func (h * handler ) logPermissionError (err error ) {
174
- if ! h .instructionsLogged {
175
- h .instructionsLogged = true
176
- helpText := loggingDeniedHelpText (h .projectID )
177
- errorMsg := fmt .Sprintf ("Unable to send logs to Google Cloud: %v\n \n %s\n " , err , helpText )
178
-
179
- h .fallbackHandler .Handle (context .Background (), slog .NewRecord (
180
- time .Now (),
181
- slog .LevelError ,
182
- errorMsg ,
183
- 0 ,
184
- ))
185
- }
186
- }
187
-
188
97
func (h * handler ) recordToEntry (ctx context.Context , r slog.Record ) logging.Entry {
189
98
span := trace .SpanFromContext (ctx )
190
99
0 commit comments