mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-02-03 13:11:53 +02:00
Add environment variables for jaeger exporter
Handle these environment variables: JAEGER_SERVICE_NAME, JAEGER_DISABLED, JAEGER_TAGS, JAEGER_ENDPOINT, JAEGER_USER, JAEGER_PASSWORD
This commit is contained in:
parent
a234027fde
commit
d8d7b41695
132
exporters/trace/jaeger/env.go
Normal file
132
exporters/trace/jaeger/env.go
Normal file
@ -0,0 +1,132 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
"go.opentelemetry.io/otel/api/kv/value"
|
||||
)
|
||||
|
||||
// Environment variable names
|
||||
const (
|
||||
// The service name.
|
||||
envServiceName = "JAEGER_SERVICE_NAME"
|
||||
// Whether the exporter is disabled or not. (default false).
|
||||
envDisabled = "JAEGER_DISABLED"
|
||||
// A comma separated list of name=value tracer-level tags, which get added to all reported spans.
|
||||
// The value can also refer to an environment variable using the format ${envVarName:defaultValue}.
|
||||
envTags = "JAEGER_TAGS"
|
||||
// The HTTP endpoint for sending spans directly to a collector,
|
||||
// i.e. http://jaeger-collector:14268/api/traces.
|
||||
envEndpoint = "JAEGER_ENDPOINT"
|
||||
// Username to send as part of "Basic" authentication to the collector endpoint.
|
||||
envUser = "JAEGER_USER"
|
||||
// Password to send as part of "Basic" authentication to the collector endpoint.
|
||||
envPassword = "JAEGER_PASSWORD"
|
||||
)
|
||||
|
||||
// CollectorEndpointFromEnv return environment variable value of JAEGER_ENDPOINT
|
||||
func CollectorEndpointFromEnv() string {
|
||||
return os.Getenv(envEndpoint)
|
||||
}
|
||||
|
||||
// WithCollectorEndpointOptionFromEnv uses environment variables to set the username and password
|
||||
// if basic auth is required.
|
||||
func WithCollectorEndpointOptionFromEnv() CollectorEndpointOption {
|
||||
return func(o *CollectorEndpointOptions) {
|
||||
if e := os.Getenv(envUser); e != "" {
|
||||
o.username = e
|
||||
}
|
||||
if e := os.Getenv(envPassword); e != "" {
|
||||
o.password = os.Getenv(envPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisabledFromEnv uses environment variables and overrides disabled field.
|
||||
func WithDisabledFromEnv() Option {
|
||||
return func(o *options) {
|
||||
if e := os.Getenv(envDisabled); e != "" {
|
||||
if v, err := strconv.ParseBool(e); err == nil {
|
||||
o.Disabled = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithProcessFromEnv parse environment variables into jaeger exporter's Process.
|
||||
func ProcessFromEnv() Process {
|
||||
var p Process
|
||||
if e := os.Getenv(envServiceName); e != "" {
|
||||
p.ServiceName = e
|
||||
}
|
||||
if e := os.Getenv(envTags); e != "" {
|
||||
p.Tags = parseTags(e)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// WithProcessFromEnv uses environment variables and overrides jaeger exporter's Process.
|
||||
func WithProcessFromEnv() Option {
|
||||
return func(o *options) {
|
||||
p := ProcessFromEnv()
|
||||
if p.ServiceName != "" {
|
||||
o.Process.ServiceName = p.ServiceName
|
||||
}
|
||||
if len(p.Tags) != 0 {
|
||||
o.Process.Tags = p.Tags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseTags parses the given string into a collection of Tags.
|
||||
// Spec for this value:
|
||||
// - comma separated list of key=value
|
||||
// - value can be specified using the notation ${envVar:defaultValue}, where `envVar`
|
||||
// is an environment variable and `defaultValue` is the value to use in case the env var is not set
|
||||
func parseTags(sTags string) []kv.KeyValue {
|
||||
pairs := strings.Split(sTags, ",")
|
||||
tags := make([]kv.KeyValue, 0)
|
||||
for _, p := range pairs {
|
||||
field := strings.SplitN(p, "=", 2)
|
||||
k, v := strings.TrimSpace(field[0]), strings.TrimSpace(field[1])
|
||||
|
||||
if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") {
|
||||
ed := strings.SplitN(v[2:len(v)-1], ":", 2)
|
||||
e, d := ed[0], ed[1]
|
||||
v = os.Getenv(e)
|
||||
if v == "" && d != "" {
|
||||
v = d
|
||||
}
|
||||
}
|
||||
|
||||
tags = append(tags, parseKeyValue(k, v))
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
func parseKeyValue(k, v string) kv.KeyValue {
|
||||
return kv.KeyValue{
|
||||
Key: kv.Key(k),
|
||||
Value: parseValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
func parseValue(str string) value.Value {
|
||||
if v, err := strconv.ParseInt(str, 10, 64); err == nil {
|
||||
return value.Int64(v)
|
||||
}
|
||||
if v, err := strconv.ParseFloat(str, 64); err == nil {
|
||||
return value.Float64(v)
|
||||
}
|
||||
if v, err := strconv.ParseBool(str); err == nil {
|
||||
return value.Bool(v)
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return value.String(str)
|
||||
}
|
334
exporters/trace/jaeger/env_test.go
Normal file
334
exporters/trace/jaeger/env_test.go
Normal file
@ -0,0 +1,334 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.opentelemetry.io/otel/api/kv"
|
||||
"go.opentelemetry.io/otel/api/kv/value"
|
||||
)
|
||||
|
||||
func Test_parseTags(t *testing.T) {
|
||||
require.NoError(t, os.Setenv("existing", "not-default"))
|
||||
|
||||
tags := "key=value,k1=${nonExisting:default}, k2=${withSpace:default},k3=${existing:default},k4=true,k5=42,k6=-1.2"
|
||||
ts := parseTags(tags)
|
||||
assert.Equal(t, 7, len(ts))
|
||||
|
||||
assert.Equal(t, kv.Key("key"), ts[0].Key)
|
||||
assert.Equal(t, value.String("value"), ts[0].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k1"), ts[1].Key)
|
||||
assert.Equal(t, value.String("default"), ts[1].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k2"), ts[2].Key)
|
||||
assert.Equal(t, value.String("default"), ts[2].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k3"), ts[3].Key)
|
||||
assert.Equal(t, value.String("not-default"), ts[3].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k4"), ts[4].Key)
|
||||
assert.Equal(t, value.Bool(true), ts[4].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k5"), ts[5].Key)
|
||||
assert.Equal(t, value.Int64(42), ts[5].Value)
|
||||
|
||||
assert.Equal(t, kv.Key("k6"), ts[6].Key)
|
||||
assert.Equal(t, value.Float64(-1.2), ts[6].Value)
|
||||
|
||||
require.NoError(t, os.Unsetenv("existing"))
|
||||
}
|
||||
|
||||
func Test_parseValue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
str string
|
||||
expected value.Value
|
||||
}{
|
||||
{
|
||||
name: "bool: true",
|
||||
str: "true",
|
||||
expected: value.Bool(true),
|
||||
},
|
||||
{
|
||||
name: "bool: false",
|
||||
str: "false",
|
||||
expected: value.Bool(false),
|
||||
},
|
||||
{
|
||||
name: "int64: 012340",
|
||||
str: "012340",
|
||||
expected: value.Int64(12340),
|
||||
},
|
||||
{
|
||||
name: "int64: -012340",
|
||||
str: "-012340",
|
||||
expected: value.Int64(-12340),
|
||||
},
|
||||
{
|
||||
name: "int64: 0",
|
||||
str: "0",
|
||||
expected: value.Int64(0),
|
||||
},
|
||||
{
|
||||
name: "float64: -0.1",
|
||||
str: "-0.1",
|
||||
expected: value.Float64(-0.1),
|
||||
},
|
||||
{
|
||||
name: "float64: 00.001",
|
||||
str: "00.001",
|
||||
expected: value.Float64(0.001),
|
||||
},
|
||||
{
|
||||
name: "float64: 1E23",
|
||||
str: "1E23",
|
||||
expected: value.Float64(1e23),
|
||||
},
|
||||
{
|
||||
name: "string: foo",
|
||||
str: "foo",
|
||||
expected: value.String("foo"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
v := parseValue(tc.str)
|
||||
assert.Equal(t, tc.expected, v)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRawExporterWithEnv(t *testing.T) {
|
||||
const (
|
||||
collectorEndpoint = "http://localhost"
|
||||
username = "user"
|
||||
password = "password"
|
||||
serviceName = "test-service"
|
||||
disabled = "disable"
|
||||
tags = "key=value"
|
||||
)
|
||||
|
||||
require.NoError(t, os.Setenv(envEndpoint, collectorEndpoint))
|
||||
require.NoError(t, os.Setenv(envUser, username))
|
||||
require.NoError(t, os.Setenv(envPassword, password))
|
||||
require.NoError(t, os.Setenv(envDisabled, disabled))
|
||||
require.NoError(t, os.Setenv(envServiceName, serviceName))
|
||||
require.NoError(t, os.Setenv(envTags, tags))
|
||||
defer func() {
|
||||
require.NoError(t, os.Unsetenv(envEndpoint))
|
||||
require.NoError(t, os.Unsetenv(envUser))
|
||||
require.NoError(t, os.Unsetenv(envPassword))
|
||||
require.NoError(t, os.Unsetenv(envDisabled))
|
||||
require.NoError(t, os.Unsetenv(envServiceName))
|
||||
require.NoError(t, os.Unsetenv(envTags))
|
||||
}()
|
||||
|
||||
// Create Jaeger Exporter with environment variables
|
||||
exp, err := NewRawExporter(
|
||||
WithCollectorEndpoint(CollectorEndpointFromEnv(), WithCollectorEndpointOptionFromEnv()),
|
||||
WithDisabledFromEnv(),
|
||||
WithProcessFromEnv(),
|
||||
)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, exp.o.Disabled, false)
|
||||
assert.EqualValues(t, serviceName, exp.process.ServiceName)
|
||||
assert.Len(t, exp.process.Tags, 1)
|
||||
}
|
||||
|
||||
func TestCollectorEndpointFromEnv(t *testing.T) {
|
||||
const (
|
||||
collectorEndpoint = "http://localhost"
|
||||
)
|
||||
|
||||
require.NoError(t, os.Setenv(envEndpoint, collectorEndpoint))
|
||||
defer func() {
|
||||
require.NoError(t, os.Unsetenv(envEndpoint))
|
||||
}()
|
||||
|
||||
assert.Equal(t, collectorEndpoint, CollectorEndpointFromEnv())
|
||||
}
|
||||
|
||||
func TestWithCollectorEndpointOptionFromEnv(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
envUsername string
|
||||
envPassword string
|
||||
collectorEndpointOptions CollectorEndpointOptions
|
||||
expectedCollectorEndpointOptions CollectorEndpointOptions
|
||||
}{
|
||||
{
|
||||
name: "overrides value via environment variables",
|
||||
envUsername: "username",
|
||||
envPassword: "password",
|
||||
collectorEndpointOptions: CollectorEndpointOptions{
|
||||
username: "foo",
|
||||
password: "bar",
|
||||
},
|
||||
expectedCollectorEndpointOptions: CollectorEndpointOptions{
|
||||
username: "username",
|
||||
password: "password",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "environment variables is empty, will not overwrite value",
|
||||
envUsername: "",
|
||||
envPassword: "",
|
||||
collectorEndpointOptions: CollectorEndpointOptions{
|
||||
username: "foo",
|
||||
password: "bar",
|
||||
},
|
||||
expectedCollectorEndpointOptions: CollectorEndpointOptions{
|
||||
username: "foo",
|
||||
password: "bar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.NoError(t, os.Setenv(envUser, tc.envUsername))
|
||||
require.NoError(t, os.Setenv(envPassword, tc.envPassword))
|
||||
|
||||
f := WithCollectorEndpointOptionFromEnv()
|
||||
f(&tc.collectorEndpointOptions)
|
||||
|
||||
assert.Equal(t, tc.expectedCollectorEndpointOptions, tc.collectorEndpointOptions)
|
||||
})
|
||||
}
|
||||
|
||||
require.NoError(t, os.Unsetenv(envUser))
|
||||
require.NoError(t, os.Unsetenv(envPassword))
|
||||
}
|
||||
|
||||
func TestWithDisabledFromEnv(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
env string
|
||||
options options
|
||||
expectedOptions options
|
||||
}{
|
||||
{
|
||||
name: "overwriting",
|
||||
env: "true",
|
||||
options: options{},
|
||||
expectedOptions: options{Disabled: true},
|
||||
},
|
||||
{
|
||||
name: "no overwriting",
|
||||
env: "",
|
||||
options: options{Disabled: true},
|
||||
expectedOptions: options{Disabled: true},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.NoError(t, os.Setenv(envDisabled, tc.env))
|
||||
|
||||
f := WithDisabledFromEnv()
|
||||
f(&tc.options)
|
||||
|
||||
assert.Equal(t, tc.expectedOptions, tc.options)
|
||||
})
|
||||
}
|
||||
|
||||
require.NoError(t, os.Unsetenv(envDisabled))
|
||||
}
|
||||
|
||||
func TestProcessFromEnv(t *testing.T) {
|
||||
const (
|
||||
serviceName = "test-service"
|
||||
tags = "key=value,key2=123"
|
||||
)
|
||||
|
||||
require.NoError(t, os.Setenv(envServiceName, serviceName))
|
||||
require.NoError(t, os.Setenv(envTags, tags))
|
||||
defer func() {
|
||||
require.NoError(t, os.Unsetenv(envServiceName))
|
||||
require.NoError(t, os.Unsetenv(envTags))
|
||||
}()
|
||||
|
||||
p := ProcessFromEnv()
|
||||
|
||||
assert.Equal(t, Process{
|
||||
ServiceName: serviceName,
|
||||
Tags: []kv.KeyValue{
|
||||
kv.String("key", "value"),
|
||||
kv.Int64("key2", 123),
|
||||
},
|
||||
}, p)
|
||||
}
|
||||
|
||||
func TestWithProcessFromEnv(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
envServiceName string
|
||||
envTags string
|
||||
options options
|
||||
expectedOptions options
|
||||
}{
|
||||
{
|
||||
name: "overwriting",
|
||||
envServiceName: "service-name",
|
||||
envTags: "key=value",
|
||||
options: options{
|
||||
Process: Process{
|
||||
ServiceName: "old-name",
|
||||
Tags: []kv.KeyValue{
|
||||
kv.String("old-key", "old-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedOptions: options{
|
||||
Process: Process{
|
||||
ServiceName: "service-name",
|
||||
Tags: []kv.KeyValue{
|
||||
kv.String("key", "value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no overwriting",
|
||||
envServiceName: "",
|
||||
envTags: "",
|
||||
options: options{
|
||||
Process: Process{
|
||||
ServiceName: "old-name",
|
||||
Tags: []kv.KeyValue{
|
||||
kv.String("old-key", "old-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedOptions: options{
|
||||
Process: Process{
|
||||
ServiceName: "old-name",
|
||||
Tags: []kv.KeyValue{
|
||||
kv.String("old-key", "old-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.NoError(t, os.Setenv(envServiceName, tc.envServiceName))
|
||||
require.NoError(t, os.Setenv(envTags, tc.envTags))
|
||||
|
||||
f := WithProcessFromEnv()
|
||||
f(&tc.options)
|
||||
|
||||
assert.Equal(t, tc.expectedOptions, tc.options)
|
||||
})
|
||||
}
|
||||
|
||||
require.NoError(t, os.Unsetenv(envServiceName))
|
||||
require.NoError(t, os.Unsetenv(envTags))
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user