+66
-28
src/observe.go
+66
-28
src/observe.go
···
51
51
return os.Getenv("SENTRY_DSN") != ""
52
52
}
53
53
54
+
func chainSentryMiddleware(
55
+
middleware ...func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event,
56
+
) func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
57
+
return func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
58
+
for idx := 0; idx < len(middleware) && event != nil; idx++ {
59
+
event = middleware[idx](event, hint)
60
+
}
61
+
return event
62
+
}
63
+
}
64
+
65
+
// sensitiveHTTPHeaders extends the list of sensitive headers defined in the Sentry Go SDK with our
66
+
// own application-specific header field names.
67
+
var sensitiveHTTPHeaders = map[string]struct{}{
68
+
"Forge-Authorization": {},
69
+
}
70
+
71
+
// scrubSentryEvent removes sensitive HTTP header fields from the Sentry event.
72
+
func scrubSentryEvent(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
73
+
if event.Request != nil && event.Request.Headers != nil {
74
+
for key := range event.Request.Headers {
75
+
if _, ok := sensitiveHTTPHeaders[key]; ok {
76
+
delete(event.Request.Headers, key)
77
+
}
78
+
}
79
+
}
80
+
return event
81
+
}
82
+
83
+
// sampleSentryEvent returns a function that discards a Sentry event according to the sample rate,
84
+
// unless the associated HTTP request triggers a mutation or it took too long to produce a response,
85
+
// in which case the event is never discarded.
86
+
func sampleSentryEvent(sampleRate float64) func(*sentry.Event, *sentry.EventHint) *sentry.Event {
87
+
return func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
88
+
newSampleRate := sampleRate
89
+
if event.Request != nil {
90
+
switch event.Request.Method {
91
+
case "PUT", "POST", "DELETE":
92
+
newSampleRate = 1
93
+
}
94
+
}
95
+
duration := event.Timestamp.Sub(event.StartTime)
96
+
threshold := time.Duration(config.Observability.SlowResponseThreshold)
97
+
if duration >= threshold {
98
+
newSampleRate = 1
99
+
}
100
+
if rand.Float64() < newSampleRate {
101
+
return event
102
+
}
103
+
return nil
104
+
}
105
+
}
106
+
54
107
func InitObservability() {
55
108
debug.SetPanicOnFault(true)
56
109
···
98
151
enableTracing = value
99
152
}
100
153
154
+
tracesSampleRate := 1.00
155
+
switch environment {
156
+
case "development", "staging":
157
+
default:
158
+
tracesSampleRate = 0.05
159
+
}
160
+
101
161
options := sentry.ClientOptions{}
102
162
options.DisableTelemetryBuffer = !config.Feature("sentry-telemetry-buffer")
103
163
options.Environment = environment
104
164
options.EnableLogs = enableLogs
105
165
options.EnableTracing = enableTracing
106
-
options.TracesSampleRate = 1
107
-
switch environment {
108
-
case "development", "staging":
109
-
default:
110
-
options.BeforeSendTransaction = func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
111
-
sampleRate := 0.05
112
-
if trace, ok := event.Contexts["trace"]; ok {
113
-
if data, ok := trace["data"].(map[string]any); ok {
114
-
if method, ok := data["http.request.method"].(string); ok {
115
-
switch method {
116
-
case "PUT", "DELETE", "POST":
117
-
sampleRate = 1
118
-
default:
119
-
duration := event.Timestamp.Sub(event.StartTime)
120
-
threshold := time.Duration(config.Observability.SlowResponseThreshold)
121
-
if duration >= threshold {
122
-
sampleRate = 1
123
-
}
124
-
}
125
-
}
126
-
}
127
-
}
128
-
if rand.Float64() < sampleRate {
129
-
return event
130
-
}
131
-
return nil
132
-
}
133
-
}
166
+
options.TracesSampleRate = 1 // use our own custom sampling logic
167
+
options.BeforeSend = scrubSentryEvent
168
+
options.BeforeSendTransaction = chainSentryMiddleware(
169
+
sampleSentryEvent(tracesSampleRate),
170
+
scrubSentryEvent,
171
+
)
134
172
if err := sentry.Init(options); err != nil {
135
173
log.Fatalf("sentry: %s\n", err)
136
174
}