44 "context"
55 "encoding/json"
66 "fmt"
7- "maps"
87 "runtime/debug"
98 "strings"
109 "sync"
@@ -109,6 +108,10 @@ func (c *WriterConfig) FlushUnderlying() {
109108//
110109// TRACE/DEBUG -> DEBUG, INFO -> INFO, WARN -> WARNING, ERROR -> ERROR, FATAL -> FATAL
111110//
111+ // Sentry reserves the key "type" inside every context object to denote the
112+ // context type, so a value logged under the key "type" is remapped to "type_"
113+ // to keep it visible as data (see [copyContextValues]).
114+ //
112115// Example usage through golog:
113116//
114117// logger.Error("Database error").Str("query", sql).Err(err).Log()
@@ -160,7 +163,8 @@ func (w *Writer) BeginMessage(config golog.Config, timestamp time.Time, level go
160163// - The accumulated message text
161164// - The mapped Sentry level
162165// - The original timestamp
163- // - All key-value pairs as a "log" context (from both config.extra and values)
166+ // - All key-value pairs as a "log" context (from both config.extra and
167+ // values), with the Sentry-reserved "type" key remapped to "type_"
164168// - Optional stack trace (if enabled in Sentry options)
165169// - A fingerprint based on the message for grouping
166170//
@@ -192,8 +196,8 @@ func (w *Writer) CommitMessage() {
192196 // sentry-go v0.46.0 removed Event.Extra; attach the key-value pairs
193197 // as a named context instead (sentry.Context is map[string]any).
194198 logCtx := make (sentry.Context , len (w .config .extra )+ len (w .values ))
195- maps . Copy (logCtx , w .config .extra )
196- maps . Copy (logCtx , w .values )
199+ copyContextValues (logCtx , w .config .extra )
200+ copyContextValues (logCtx , w .values )
197201 if len (logCtx ) > 0 {
198202 event .Contexts ["log" ] = logCtx
199203 }
@@ -209,6 +213,34 @@ func (w *Writer) CommitMessage() {
209213 }
210214}
211215
216+ const (
217+ // reservedContextKey is the key Sentry reserves inside every context
218+ // object to identify the context's type. Within our "log" context it
219+ // defaults to "log" when absent; a value logged under this key would be
220+ // consumed as the context type instead of being shown as data.
221+ // See https://develop.sentry.dev/sdk/data-model/event-payloads/contexts/.
222+ reservedContextKey = "type"
223+
224+ // remappedContextKey is where a logged "type" value is stored instead, so
225+ // it survives as ordinary context data. The Event.Extra map removed in
226+ // sentry-go v0.46.0 had no reserved keys, so this collision is unique to
227+ // the context-based encoding.
228+ remappedContextKey = "type_"
229+ )
230+
231+ // copyContextValues copies src into dst, remapping the Sentry-reserved
232+ // [reservedContextKey] ("type") to [remappedContextKey] ("type_") so a golog
233+ // value logged under "type" is preserved as data rather than swallowed by
234+ // Sentry as the context type.
235+ func copyContextValues (dst , src map [string ]any ) {
236+ for k , v := range src {
237+ if k == reservedContextKey {
238+ k = remappedContextKey
239+ }
240+ dst [k ] = v
241+ }
242+ }
243+
212244// filterFrames removes golog internal frames from stack traces to provide
213245// cleaner Sentry debugging information by focusing on application code.
214246func filterFrames (frames []sentry.Frame ) []sentry.Frame {
0 commit comments