Newer
Older
package tracing
import (
"encoding/json"
"errors"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
othttp "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/zipkin"
"go.opentelemetry.io/otel/sdk/trace"
)
var (
// Enabled reports whether tracing is globally enabled or not.
Enabled bool
// Global Tracer instance.
Tracer apitrace.Tracer
// The active tracing configuration, if Enabled is true.
config tracingConfig
initOnce sync.Once
)
const globalTracingConfigPath = "/etc/tracing/client.conf"
type tracingConfig struct {
ReportURL string `json:"report_url"`
}
// Read the global tracing configuration file. Its location is
// hardcoded, but it can be overriden using the TRACING_CONFIG
// environment variable.
func readTracingConfig() (*tracingConfig, error) {
// Read and decode configuration.
cfgPath := globalTracingConfigPath
if s := os.Getenv("TRACING_CONFIG"); s != "" {
cfgPath = s
}
data, err := ioutil.ReadFile(cfgPath)
if err != nil {
if err := json.Unmarshal(data, &config); err != nil {
log.Printf("warning: error in tracing configuration: %v, tracing disabled", err)
}
if config.ReportURL == "" {
log.Printf("warning: tracing configuration contains no report_url, tracing disabled")
}
// Compute the service name for Zipkin: this is usually the program
// name (without path), but it can be overriden by the TRACING_SERVICE
// environment variable.
func getServiceName() string {
if s := os.Getenv("TRACING_SERVICE"); s != "" {
return s
}
return filepath.Base(os.Args[0])
}
// Initialize tracing. Tracing will be enabled if the system-wide
// tracing configuration file is present and valid. Explicitly set
// TRACING_ENABLE=0 in the environment to disable tracing.
//
// We need to check the configuration as soon as possible, because
// it's likely that client transports are created before HTTP servers,
// and we need to wrap them with opencensus at creation time.
func initTracing(endpointAddr string) {
initOnce.Do(func() {
// Kill switch from environment.
if s := os.Getenv("TRACING_ENABLE"); s == "0" {
return
}
config, err := readTracingConfig()
if err != nil {
return
}
ze, err := zipkin.New(config.ReportURL)
log.Printf("error creating Zipkin exporter: %v", err)
switch config.Sample {
case "", "always":
default:
frac, err := strconv.ParseFloat(config.Sample, 64)
if err != nil {
log.Printf("warning: error in tracing configuration: sample: %v, tracing disabled", err)
return
}
sampler = trace.TraceIDRatioBased(frac)
tp := trace.NewTracerProvider(
trace.WithSampler(sampler),
trace.WithBatcher(ze),
)
otel.SetTracerProvider(tp)
log.Printf("tracing enabled (report_url %s)", config.ReportURL)
Enabled = true
})
}
// Init tracing support, if not using WrapHandler.
func Init() {
initTracing("")
}
// WrapTransport optionally wraps a http.RoundTripper with OpenCensus
// tracing functionality, if it is globally enabled.
func WrapTransport(t http.RoundTripper) http.RoundTripper {
if Enabled {
}
return t
}
// WrapHandler wraps a http.Handler with OpenCensus tracing
// functionality, if globally enabled. Automatically calls Init().
func WrapHandler(h http.Handler, endpointAddr string) http.Handler {
if Enabled {
initTracing(endpointAddr)
h = othttp.NewHandler(h, getServiceName())