SENTRY_TAGS_* environment variables
Summary
The sentry-logback implementation supports the injection of tags through the SENTRY_TAGS_<key>=<value> environment variables. It would be great if the Go SDK would support this too 🙂
Motivation
We would like to inject some additional context as tags into each event, especially things like the Kubernetes pod and Kubernetes namespace that event got triggered in. In Java services we have for that set SENTRY_TAGS_K8S_NAMESPACE and SENTRY_TAGS_K8S_POD and would like to do that also for our Go applications.
Sample
I've added a test-case + sample implementation here: https://github.com/zerok/sentry-go/commit/36dc6dbb540ea558e0d1225f2f4493b584f0244c
Right now we can work around this using a custom eventprocessor but it would be nice if the Java and Go SDKs would behave in a similar way here out of the box 🙂
Is there anything missing in the sample implementation which prevents merging it upstream?
@dennwc would you mind sharing what is your use case?
A quick look onto https://github.com/zerok/sentry-go/commit/36dc6dbb540ea558e0d1225f2f4493b584f0244c and I see some things would need to be better defined, for example, as implemented, passing ClientOptions.Tags when initializing the SDK would ignore the environment.
Also comes to mind that some SDKs have a concept of InitialScope, in that case tags could naturally be there.
This is really so simple to add with EventProcessor, and with total flexibility on behavior (e.g. add to all events, add to errors only, add to transactions only, etc) that I'm not seeing the value of maintaining a limited version which makes the API surface larger (we could read tags from env without adding new fields to ClientOptions).
It's actually very similar to what is described above: mostly passing K8S or other deployment-related variables.
So I agree that it might be okay to keep ClientOptions as-is. At least for our case we will pass everything via environment.
Closing, as the route via an EventProcessor seems to be feasible.
Will someone clarify why automatically supporting this in sentry.Init() is not the best solution? This is seems like a fairly obvious and useful feature that other language implementations do as well as other libraries (e.g. OpenTelemetry). I understand the extra features you get from using a custom EventProcessor but at the cost of more complexity and some runtime cost. I would expect a significant majority of users do not want or need that extra complexity and would like something out of the box that just works without any code changes.
I guess until this is resolved we duplicate this "user space" code in every application with Sentry integration.
func loadTags() map[string]string {
tags := map[string]string{}
for _, pair := range os.Environ() {
parts := strings.Split(pair, "=")
if !strings.HasPrefix(parts[0], "SENTRY_TAGS_") {
continue
}
tag := strings.TrimPrefix(parts[0], "SENTRY_TAGS_")
tag = strings.ToLower(tag)
tags[tag] = parts[1]
}
return tags
}
func main() {
defer sentry.Recover()
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetTags(loadTags())
cmd.Execute()
})
}
We added the tags option back to PHP a while ago (https://github.com/getsentry/sentry-php/pull/1561), and we can also add it to the Go SDK with support for setting tags via env.
@greywolve can you please pick this up? 😃
This was released in 0.25.0.