diff --git a/traces/traces.go b/traces/traces.go index e11017d..af23cf0 100644 --- a/traces/traces.go +++ b/traces/traces.go @@ -14,17 +14,17 @@ import ( const instrumentationPkg = "github.com/osquery/osquery-go" -var internalVersion string +var ( + internalVersion string // provides the instrumentation version for attribute `otel.scope.version` + tracerProvider trace.TracerProvider +) -// osqueryGoVersion returns the version of osquery-go, to be used to set the instrumentation -// version `otel.scope.version`. It looks through build info to determine the current version -// of the osquery-go package. Once determined, it saves the version to avoid performing this -// work again. If the version cannot be determined, the version defaults to the current version, -// which is hardcoded. -func osqueryGoVersion() string { - if internalVersion != "" { - return internalVersion - } +// init sets `internalVersion` and a default tracer provider. +func init() { + // By default, use the global tracer provider, which is a no-op provider. + tracerProvider = otel.GetTracerProvider() + + // Look through build info to determine the current version of the osquery-go package. if info, ok := debug.ReadBuildInfo(); ok { for _, dep := range info.Deps { if dep == nil { @@ -32,20 +32,16 @@ func osqueryGoVersion() string { } if dep.Path == instrumentationPkg { internalVersion = dep.Version - return internalVersion + return } } } - // Couldn't get the version from runtime build info -- save and return 0.0.0, + // Couldn't get the version from runtime build info -- save 0.0.0, // which is the current osquery-go version. internalVersion = "0.0.0" - return internalVersion } -// By default, use the global tracer provider, which is a no-op provider. -var tracerProvider = otel.GetTracerProvider() - // SetTracerProvider allows consuming libraries to set a custom/non-global tracer provider. func SetTracerProvider(tp trace.TracerProvider) { tracerProvider = tp @@ -56,7 +52,7 @@ func SetTracerProvider(tp trace.TracerProvider) { // not supported by `StartSpan` below -- i.e., any `SpanStartOption` besides // `WithAttributes`. func OsqueryGoTracer() trace.Tracer { - return tracerProvider.Tracer(instrumentationPkg, trace.WithInstrumentationVersion(osqueryGoVersion())) + return tracerProvider.Tracer(instrumentationPkg, trace.WithInstrumentationVersion(internalVersion)) } // StartSpan is a wrapper around trace.Tracer.Start that simplifies passing in span attributes. diff --git a/traces/traces_test.go b/traces/traces_test.go new file mode 100644 index 0000000..5b366ed --- /dev/null +++ b/traces/traces_test.go @@ -0,0 +1,27 @@ +package traces + +import ( + "context" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTraceInit(t *testing.T) { + t.Parallel() + + // Start several spans in quick succession to confirm there's no data race on setting `internalVersion` + var wg sync.WaitGroup + for i := 0; i < 5; i += 1 { + wg.Add(1) + go func() { + defer wg.Done() + _, span := StartSpan(context.TODO(), "TestSpan") + span.End() + }() + } + + wg.Wait() + assert.NotEmpty(t, internalVersion, "internal version should have been set") +}