Files
grafana/pkg/infra/tracing/tracing_config.go
2025-04-01 17:34:42 +02:00

151 lines
4.0 KiB
Go

package tracing
import (
"fmt"
"os"
"strings"
"go.opentelemetry.io/otel/attribute"
"github.com/grafana/grafana/pkg/setting"
)
type TracingConfig struct {
enabled string
Address string
Propagation string
CustomAttribs []attribute.KeyValue
Sampler string
SamplerParam float64
SamplerRemoteURL string
ServiceName string
ServiceVersion string
ProfilingIntegration bool
Insecure bool
}
func ProvideTracingConfig(cfg *setting.Cfg) (*TracingConfig, error) {
return ParseTracingConfig(cfg)
}
func NewEmptyTracingConfig() *TracingConfig {
return &TracingConfig{
CustomAttribs: []attribute.KeyValue{},
}
}
func NewJaegerTracingConfig(address string, propagation string) (*TracingConfig, error) {
if address == "" {
return nil, fmt.Errorf("address cannot be empty")
}
cfg := NewEmptyTracingConfig()
cfg.enabled = jaegerExporter
cfg.Address = address
cfg.Propagation = propagation
return cfg, nil
}
func NewOTLPTracingConfig(address string, propagation string, insecure bool) (*TracingConfig, error) {
if address == "" {
return nil, fmt.Errorf("address cannot be empty")
}
cfg := NewEmptyTracingConfig()
cfg.enabled = otlpExporter
cfg.Address = address
cfg.Propagation = propagation
cfg.Insecure = insecure
return cfg, nil
}
func ParseTracingConfig(cfg *setting.Cfg) (*TracingConfig, error) {
if cfg == nil {
return nil, fmt.Errorf("cfg cannot be nil")
}
tc := NewEmptyTracingConfig()
tc.ServiceName = "grafana"
tc.ServiceVersion = cfg.BuildVersion
legacyAddress, legacyTags := "", ""
if section, err := cfg.Raw.GetSection("tracing.jaeger"); err == nil {
legacyAddress = section.Key("address").MustString("")
if legacyAddress == "" {
host, port := os.Getenv(envJaegerAgentHost), os.Getenv(envJaegerAgentPort)
if host != "" || port != "" {
legacyAddress = fmt.Sprintf("%s:%s", host, port)
}
}
legacyTags = section.Key("always_included_tag").MustString("")
tc.Sampler = section.Key("sampler_type").MustString("")
tc.SamplerParam = section.Key("sampler_param").MustFloat64(1)
tc.SamplerRemoteURL = section.Key("sampling_server_url").MustString("")
}
section := cfg.Raw.Section("tracing.opentelemetry")
var err error
// we default to legacy tag set (attributes) if the new config format is absent
tc.CustomAttribs, err = splitCustomAttribs(section.Key("custom_attributes").MustString(legacyTags))
if err != nil {
return nil, err
}
// if sampler_type is set in tracing.opentelemetry, we ignore the config in tracing.jaeger
sampler := section.Key("sampler_type").MustString("")
if sampler != "" {
tc.Sampler = sampler
}
samplerParam := section.Key("sampler_param").MustFloat64(0)
if samplerParam != 0 {
tc.SamplerParam = samplerParam
}
samplerRemoteURL := section.Key("sampling_server_url").MustString("")
if samplerRemoteURL != "" {
tc.SamplerRemoteURL = samplerRemoteURL
}
section = cfg.Raw.Section("tracing.opentelemetry.jaeger")
tc.enabled = noopExporter
// we default to legacy Jaeger agent address if the new config value is empty
tc.Address = section.Key("address").MustString(legacyAddress)
tc.Propagation = section.Key("propagation").MustString("")
if tc.Address != "" {
tc.enabled = jaegerExporter
return tc, nil
}
section = cfg.Raw.Section("tracing.opentelemetry.otlp")
tc.Address = section.Key("address").MustString("")
if tc.Address != "" {
tc.enabled = otlpExporter
}
tc.Propagation = section.Key("propagation").MustString("")
tc.Insecure = section.Key("insecure").MustBool(true)
return tc, nil
}
func (tc TracingConfig) OTelExporterEnabled() bool {
return tc.enabled == otlpExporter
}
func splitCustomAttribs(s string) ([]attribute.KeyValue, error) {
res := []attribute.KeyValue{}
attribs := strings.Split(s, ",")
for _, v := range attribs {
parts := strings.SplitN(v, ":", 2)
if len(parts) > 1 {
res = append(res, attribute.String(parts[0], parts[1]))
} else if v != "" {
return nil, fmt.Errorf("custom attribute malformed - must be in 'key:value' form: %q", v)
}
}
return res, nil
}