From 4029ccfda5d491efe86292ad71b9fdb669ac5fef Mon Sep 17 00:00:00 2001 From: Ron Federman Date: Wed, 27 Sep 2023 16:58:03 +0300 Subject: [PATCH 1/8] Add WithServiceName condig option for instrumentation --- instConfig_test.go | 43 ++++++++++++++++++++++++ instrumentation.go | 36 +++++++++++++++++--- internal/pkg/opentelemetry/controller.go | 12 +------ 3 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 instConfig_test.go diff --git a/instConfig_test.go b/instConfig_test.go new file mode 100644 index 000000000..6ff5db893 --- /dev/null +++ b/instConfig_test.go @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package auto + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWithServiceName(t *testing.T) { + testServiceName := "test_serviceName" + + // Use WithServiceName to config the service name + c := newInstConfig([]InstrumentationOption{WithServiceName((testServiceName))}) + assert.Equal(t, testServiceName, c.serviceName) + + // No service name provided - check for default value + c = newInstConfig([]InstrumentationOption{}) + assert.Equal(t, serviceNameDefault, c.serviceName) + + // Add env var to take precedence + envServiceName := "env_serviceName" + err := os.Setenv(envServiceNameKey, envServiceName) + if err != nil { + t.Error(err) + } + c = newInstConfig([]InstrumentationOption{WithServiceName((testServiceName))}) + assert.Equal(t, envServiceName, c.serviceName) +} diff --git a/instrumentation.go b/instrumentation.go index 4712a3be3..ee1cd0fa9 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -25,9 +25,15 @@ import ( "go.opentelemetry.io/auto/internal/pkg/process" ) -// envTargetExeKey is the key for the environment variable value pointing to the -// target binary to instrument. -const envTargetExeKey = "OTEL_GO_AUTO_TARGET_EXE" +const ( + // envTargetExeKey is the key for the environment variable value pointing to the + // target binary to instrument. + envTargetExeKey = "OTEL_GO_AUTO_TARGET_EXE" + // envServiceName is the key for the envoriment variable value containing the service name. + envServiceNameKey = "OTEL_SERVICE_NAME" + // prefix for default service name if not provided. + serviceNameDefault = "unknown_service" +) // Instrumentation manages and controls all OpenTelemetry Go // auto-instrumentation. @@ -57,7 +63,7 @@ func NewInstrumentation(opts ...InstrumentationOption) (*Instrumentation, error) return nil, err } - ctrl, err := opentelemetry.NewController(Version()) + ctrl, err := opentelemetry.NewController(Version(), c.serviceName) if err != nil { return nil, err } @@ -106,7 +112,8 @@ type InstrumentationOption interface { } type instConfig struct { - target *process.TargetArgs + target *process.TargetArgs + serviceName string } func newInstConfig(opts []InstrumentationOption) instConfig { @@ -122,6 +129,11 @@ func (c instConfig) applyEnv() instConfig { if v, ok := os.LookupEnv(envTargetExeKey); ok { c.target = &process.TargetArgs{ExePath: v} } + if v, ok := os.LookupEnv(envServiceNameKey); ok { + c.serviceName = v + } else if c.serviceName == "" { + c.serviceName = serviceNameDefault + } return c } @@ -150,3 +162,17 @@ func WithTarget(path string) InstrumentationOption { return c }) } + +// WithServiceName returns an [InstrumentationOption] defining the name of the service running. +// +// If multiple of these options are provided to an [Instrumentation], the last +// one will be used. +// +// If OTEL_SERVICE_NAME is defined it will take precedence over any value +// passed here. +func WithServiceName(serviceName string) InstrumentationOption { + return fnOpt(func(c instConfig) instConfig { + c.serviceName = serviceName + return c + }) +} diff --git a/internal/pkg/opentelemetry/controller.go b/internal/pkg/opentelemetry/controller.go index 3f6ce517e..499d7ff94 100644 --- a/internal/pkg/opentelemetry/controller.go +++ b/internal/pkg/opentelemetry/controller.go @@ -17,7 +17,6 @@ package opentelemetry import ( "context" "fmt" - "os" "runtime" "strings" "time" @@ -35,10 +34,6 @@ import ( "go.opentelemetry.io/otel/trace" ) -const ( - otelServiceNameEnvVar = "OTEL_SERVICE_NAME" -) - // Information about the runtime environment for inclusion in User-Agent, e.g. "go/1.18.2 (linux/amd64)". var runtimeInfo = fmt.Sprintf("%s (%s/%s)", strings.Replace(runtime.Version(), "go", "go/", 1), runtime.GOOS, runtime.GOARCH) @@ -89,12 +84,7 @@ func (c *Controller) convertTime(t int64) time.Time { } // NewController returns a new initialized [Controller]. -func NewController(version string) (*Controller, error) { - serviceName, exists := os.LookupEnv(otelServiceNameEnvVar) - if !exists { - return nil, fmt.Errorf("%s env var must be set", otelServiceNameEnvVar) - } - +func NewController(version string, serviceName string) (*Controller, error) { ctx := context.Background() res, err := resource.New(ctx, resource.WithAttributes( From d4d4b878cb0814513ab2308b41f32ce2ae698d15 Mon Sep 17 00:00:00 2001 From: Ron Federman Date: Wed, 27 Sep 2023 17:05:42 +0300 Subject: [PATCH 2/8] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 778c8bd47..27fd2c06e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ OpenTelemetry Go Automatic Instrumentation adheres to [Semantic Versioning](http ## [Unreleased] +### Added +- Add WithServiceName config option for instrumentation([#353](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/353)) + ### Changed - Fix runtime panic if OTEL_GO_AUTO_TARGET_EXE is not set. ([#339](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/339)) From 6509216ea4d3d377870ddcbb3100f60b5c9212ba Mon Sep 17 00:00:00 2001 From: Ron Federman <73110295+RonFed@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:03:20 +0300 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Tyler Yahn --- CHANGELOG.md | 3 ++- instrumentation.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27fd2c06e..b949c0557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ OpenTelemetry Go Automatic Instrumentation adheres to [Semantic Versioning](http ## [Unreleased] ### Added -- Add WithServiceName config option for instrumentation([#353](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/353)) + +- Add `WithServiceName` config option for instrumentation. ([#353](https://github.com/open-telemetry/opentelemetry-go-instrumentation/pull/353)) ### Changed diff --git a/instrumentation.go b/instrumentation.go index ee1cd0fa9..a40546ba3 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -31,7 +31,7 @@ const ( envTargetExeKey = "OTEL_GO_AUTO_TARGET_EXE" // envServiceName is the key for the envoriment variable value containing the service name. envServiceNameKey = "OTEL_SERVICE_NAME" - // prefix for default service name if not provided. + // serviceNameDefault is the default service name prefix used if a user does not provide one. serviceNameDefault = "unknown_service" ) From 43a841e2afd51fbb9f17e5a66cab0857e2a5fb59 Mon Sep 17 00:00:00 2001 From: Ron Federman Date: Wed, 27 Sep 2023 22:46:16 +0300 Subject: [PATCH 4/8] Add support for OTEL_RESOURCE_ATTRIBUTES and defualt service name --- instConfig_test.go | 14 +++++++++++++- instrumentation.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/instConfig_test.go b/instConfig_test.go index 6ff5db893..d4321e0a4 100644 --- a/instConfig_test.go +++ b/instConfig_test.go @@ -15,10 +15,13 @@ package auto import ( + "fmt" "os" "testing" "github.com/stretchr/testify/assert" + + semconv "go.opentelemetry.io/otel/semconv/v1.18.0" ) func TestWithServiceName(t *testing.T) { @@ -32,9 +35,18 @@ func TestWithServiceName(t *testing.T) { c = newInstConfig([]InstrumentationOption{}) assert.Equal(t, serviceNameDefault, c.serviceName) + // OTEL_RESOURCE_ATTRIBUTES + resServiceName := "resValue" + err := os.Setenv(resourceAttrKey, fmt.Sprintf("key1=val1,%s=%s", string(semconv.ServiceNameKey), resServiceName)) + if err != nil { + t.Error(err) + } + c = newInstConfig([]InstrumentationOption{WithServiceName((testServiceName))}) + assert.Equal(t, resServiceName, c.serviceName) + // Add env var to take precedence envServiceName := "env_serviceName" - err := os.Setenv(envServiceNameKey, envServiceName) + err = os.Setenv(envServiceNameKey, envServiceName) if err != nil { t.Error(err) } diff --git a/instrumentation.go b/instrumentation.go index a40546ba3..0696ed018 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -18,11 +18,14 @@ import ( "context" "fmt" "os" + "path/filepath" + "strings" "go.opentelemetry.io/auto/internal/pkg/instrumentors" "go.opentelemetry.io/auto/internal/pkg/log" "go.opentelemetry.io/auto/internal/pkg/opentelemetry" "go.opentelemetry.io/auto/internal/pkg/process" + semconv "go.opentelemetry.io/otel/semconv/v1.18.0" ) const ( @@ -33,6 +36,8 @@ const ( envServiceNameKey = "OTEL_SERVICE_NAME" // serviceNameDefault is the default service name prefix used if a user does not provide one. serviceNameDefault = "unknown_service" + // resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from. + resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" ) // Instrumentation manages and controls all OpenTelemetry Go @@ -126,17 +131,49 @@ func newInstConfig(opts []InstrumentationOption) instConfig { } func (c instConfig) applyEnv() instConfig { + c = c.applyResourceAtrrEnv() if v, ok := os.LookupEnv(envTargetExeKey); ok { c.target = &process.TargetArgs{ExePath: v} } if v, ok := os.LookupEnv(envServiceNameKey); ok { c.serviceName = v } else if c.serviceName == "" { + c = c.setDefualtServiceName() + } + return c +} + +func (c instConfig) setDefualtServiceName() instConfig { + if c.target != nil { + c.serviceName = fmt.Sprintf("%s:%s", serviceNameDefault, filepath.Base(c.target.ExePath)) + } else { c.serviceName = serviceNameDefault } return c } +func (c instConfig) applyResourceAtrrEnv() instConfig { + attrs := strings.TrimSpace(os.Getenv(resourceAttrKey)) + + if attrs == "" { + return c + } + + pairs := strings.Split(attrs, ",") + for _, p := range pairs { + k, v, found := strings.Cut(p, "=") + if !found { + continue + } + key := strings.TrimSpace(k) + if key == string(semconv.ServiceNameKey) { + c.serviceName = strings.TrimSpace(v) + } + } + + return c +} + func (c instConfig) validate() error { if c.target == nil { return errUndefinedTarget From 0d2835b75a1593d1aa234690a3fb93085afb655a Mon Sep 17 00:00:00 2001 From: Ron Federman <73110295+RonFed@users.noreply.github.com> Date: Thu, 28 Sep 2023 15:33:20 +0300 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: Tyler Yahn --- instConfig_test.go | 2 +- instrumentation.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/instConfig_test.go b/instConfig_test.go index d4321e0a4..8808f2d35 100644 --- a/instConfig_test.go +++ b/instConfig_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" - semconv "go.opentelemetry.io/otel/semconv/v1.18.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) func TestWithServiceName(t *testing.T) { diff --git a/instrumentation.go b/instrumentation.go index 0696ed018..aea44b0f0 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -25,7 +25,7 @@ import ( "go.opentelemetry.io/auto/internal/pkg/log" "go.opentelemetry.io/auto/internal/pkg/opentelemetry" "go.opentelemetry.io/auto/internal/pkg/process" - semconv "go.opentelemetry.io/otel/semconv/v1.18.0" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) const ( @@ -34,10 +34,11 @@ const ( envTargetExeKey = "OTEL_GO_AUTO_TARGET_EXE" // envServiceName is the key for the envoriment variable value containing the service name. envServiceNameKey = "OTEL_SERVICE_NAME" + // envResourceAttrKey is the key for the environment variable value containing + // OpenTelemetry Resource attributes. + envResourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" // serviceNameDefault is the default service name prefix used if a user does not provide one. serviceNameDefault = "unknown_service" - // resourceAttrKey is the environment variable name OpenTelemetry Resource information will be read from. - resourceAttrKey = "OTEL_RESOURCE_ATTRIBUTES" ) // Instrumentation manages and controls all OpenTelemetry Go From fc1a967022975a71ed49799cd4e1a2f147262c6b Mon Sep 17 00:00:00 2001 From: Ron Federman Date: Thu, 28 Sep 2023 15:43:22 +0300 Subject: [PATCH 6/8] Fix compilation --- instConfig_test.go | 2 +- instrumentation.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/instConfig_test.go b/instConfig_test.go index 8808f2d35..24379c885 100644 --- a/instConfig_test.go +++ b/instConfig_test.go @@ -37,7 +37,7 @@ func TestWithServiceName(t *testing.T) { // OTEL_RESOURCE_ATTRIBUTES resServiceName := "resValue" - err := os.Setenv(resourceAttrKey, fmt.Sprintf("key1=val1,%s=%s", string(semconv.ServiceNameKey), resServiceName)) + err := os.Setenv(envResourceAttrKey, fmt.Sprintf("key1=val1,%s=%s", string(semconv.ServiceNameKey), resServiceName)) if err != nil { t.Error(err) } diff --git a/instrumentation.go b/instrumentation.go index aea44b0f0..055fc62fe 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -154,7 +154,7 @@ func (c instConfig) setDefualtServiceName() instConfig { } func (c instConfig) applyResourceAtrrEnv() instConfig { - attrs := strings.TrimSpace(os.Getenv(resourceAttrKey)) + attrs := strings.TrimSpace(os.Getenv(envResourceAttrKey)) if attrs == "" { return c From 5c254a533d8849248e4d374cc6274867d1072c33 Mon Sep 17 00:00:00 2001 From: Ron Federman Date: Thu, 28 Sep 2023 16:07:11 +0300 Subject: [PATCH 7/8] Fix lint --- instrumentation.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation.go b/instrumentation.go index 055fc62fe..7da6f07f7 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -21,11 +21,12 @@ import ( "path/filepath" "strings" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" + "go.opentelemetry.io/auto/internal/pkg/instrumentors" "go.opentelemetry.io/auto/internal/pkg/log" "go.opentelemetry.io/auto/internal/pkg/opentelemetry" "go.opentelemetry.io/auto/internal/pkg/process" - semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) const ( From 900b78cd2c2a64568fdbfdbfe6a90249d3d0cc1e Mon Sep 17 00:00:00 2001 From: Ron Federman <73110295+RonFed@users.noreply.github.com> Date: Fri, 29 Sep 2023 11:33:20 +0300 Subject: [PATCH 8/8] Update instrumentation.go Co-authored-by: Tyler Yahn --- instrumentation.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/instrumentation.go b/instrumentation.go index 7da6f07f7..bc4eb08cc 100644 --- a/instrumentation.go +++ b/instrumentation.go @@ -133,14 +133,16 @@ func newInstConfig(opts []InstrumentationOption) instConfig { } func (c instConfig) applyEnv() instConfig { - c = c.applyResourceAtrrEnv() if v, ok := os.LookupEnv(envTargetExeKey); ok { c.target = &process.TargetArgs{ExePath: v} } if v, ok := os.LookupEnv(envServiceNameKey); ok { c.serviceName = v - } else if c.serviceName == "" { - c = c.setDefualtServiceName() + } else { + c = c.applyResourceAtrrEnv() + if c.serviceName == "" { + c = c.setDefualtServiceName() + } } return c }