瀏覽代碼

Revise OpenTelemetry configuration: use standard OTel env vars when possible

DarthSim 1 年之前
父節點
當前提交
5d7fe36a67
共有 3 個文件被更改,包括 136 次插入83 次删除
  1. 7 0
      CHANGELOG.md
  2. 8 27
      config/config.go
  3. 121 56
      metrics/otel/otel.go

+ 7 - 0
CHANGELOG.md

@@ -1,5 +1,12 @@
 # Changelog
 
+## [Unreleased]
+### Change
+- Support configuring OpenTelemetry with standart [general](https://opentelemetry.io/docs/languages/sdk-configuration/general/) and [OTLP Exporter](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) environment variables.
+
+### Deprecated
+- `IMGPROXY_OPEN_TELEMETRY_ENDPOINT`, `IMGPROXY_OPEN_TELEMETRY_PROTOCOL`, `IMGPROXY_OPEN_TELEMETRY_GRPC_INSECURE`, `IMGPROXY_OPEN_TELEMETRY_SERVICE_NAME`, `IMGPROXY_OPEN_TELEMETRY_PROPAGATORS`, and `IMGPROXY_OPEN_TELEMETRY_CONNECTION_TIMEOUT` config options are deprecated. Use standart OpenTelemetry environment variables instead.
+
 ## [3.22.0] - 2024-02-22
 ### Add
 - Add the [IMGPROXY_TRUSTED_SIGNATURES](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_TRUSTED_SIGNATURES) config.

+ 8 - 27
config/config.go

@@ -158,17 +158,12 @@ var (
 	PrometheusBind      string
 	PrometheusNamespace string
 
-	OpenTelemetryEndpoint          string
-	OpenTelemetryProtocol          string
-	OpenTelemetryServiceName       string
-	OpenTelemetryEnableMetrics     bool
-	OpenTelemetryServerCert        string
-	OpenTelemetryClientCert        string
-	OpenTelemetryClientKey         string
-	OpenTelemetryGRPCInsecure      bool
-	OpenTelemetryPropagators       []string
-	OpenTelemetryTraceIDGenerator  string
-	OpenTelemetryConnectionTimeout int
+	OpenTelemetryEnable           bool
+	OpenTelemetryEnableMetrics    bool
+	OpenTelemetryServerCert       string
+	OpenTelemetryClientCert       string
+	OpenTelemetryClientKey        string
+	OpenTelemetryTraceIDGenerator string
 
 	CloudWatchServiceName string
 	CloudWatchNamespace   string
@@ -351,17 +346,12 @@ func Reset() {
 	PrometheusBind = ""
 	PrometheusNamespace = ""
 
-	OpenTelemetryEndpoint = ""
-	OpenTelemetryProtocol = "grpc"
-	OpenTelemetryServiceName = "imgproxy"
+	OpenTelemetryEnable = false
 	OpenTelemetryEnableMetrics = false
 	OpenTelemetryServerCert = ""
 	OpenTelemetryClientCert = ""
 	OpenTelemetryClientKey = ""
-	OpenTelemetryGRPCInsecure = true
-	OpenTelemetryPropagators = make([]string, 0)
 	OpenTelemetryTraceIDGenerator = "xray"
-	OpenTelemetryConnectionTimeout = 5
 
 	CloudWatchServiceName = ""
 	CloudWatchNamespace = "imgproxy"
@@ -570,17 +560,12 @@ func Configure() error {
 	configurators.String(&PrometheusBind, "IMGPROXY_PROMETHEUS_BIND")
 	configurators.String(&PrometheusNamespace, "IMGPROXY_PROMETHEUS_NAMESPACE")
 
-	configurators.String(&OpenTelemetryEndpoint, "IMGPROXY_OPEN_TELEMETRY_ENDPOINT")
-	configurators.String(&OpenTelemetryProtocol, "IMGPROXY_OPEN_TELEMETRY_PROTOCOL")
-	configurators.String(&OpenTelemetryServiceName, "IMGPROXY_OPEN_TELEMETRY_SERVICE_NAME")
+	configurators.Bool(&OpenTelemetryEnable, "IMGPROXY_OPEN_TELEMETRY_ENABLE")
 	configurators.Bool(&OpenTelemetryEnableMetrics, "IMGPROXY_OPEN_TELEMETRY_ENABLE_METRICS")
 	configurators.String(&OpenTelemetryServerCert, "IMGPROXY_OPEN_TELEMETRY_SERVER_CERT")
 	configurators.String(&OpenTelemetryClientCert, "IMGPROXY_OPEN_TELEMETRY_CLIENT_CERT")
 	configurators.String(&OpenTelemetryClientKey, "IMGPROXY_OPEN_TELEMETRY_CLIENT_KEY")
-	configurators.Bool(&OpenTelemetryGRPCInsecure, "IMGPROXY_OPEN_TELEMETRY_GRPC_INSECURE")
-	configurators.StringSlice(&OpenTelemetryPropagators, "IMGPROXY_OPEN_TELEMETRY_PROPAGATORS")
 	configurators.String(&OpenTelemetryTraceIDGenerator, "IMGPROXY_OPEN_TELEMETRY_TRACE_ID_GENERATOR")
-	configurators.Int(&OpenTelemetryConnectionTimeout, "IMGPROXY_OPEN_TELEMETRY_CONNECTION_TIMEOUT")
 
 	configurators.String(&CloudWatchServiceName, "IMGPROXY_CLOUD_WATCH_SERVICE_NAME")
 	configurators.String(&CloudWatchNamespace, "IMGPROXY_CLOUD_WATCH_NAMESPACE")
@@ -732,10 +717,6 @@ func Configure() error {
 		return errors.New("Can't use the same binding for the main server and Prometheus")
 	}
 
-	if OpenTelemetryConnectionTimeout < 1 {
-		return errors.New("OpenTelemetry connection timeout should be greater than zero")
-	}
-
 	if FreeMemoryInterval <= 0 {
 		return errors.New("Free memory interval should be greater than zero")
 	}

+ 121 - 56
metrics/otel/otel.go

@@ -9,6 +9,7 @@ import (
 	"net/http"
 	"os"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 	"time"
@@ -40,6 +41,7 @@ import (
 	"google.golang.org/grpc/credentials"
 
 	"github.com/imgproxy/imgproxy/v3/config"
+	"github.com/imgproxy/imgproxy/v3/config/configurators"
 	"github.com/imgproxy/imgproxy/v3/ierrors"
 	"github.com/imgproxy/imgproxy/v3/metrics/errformat"
 	"github.com/imgproxy/imgproxy/v3/metrics/stats"
@@ -69,7 +71,9 @@ var (
 )
 
 func Init() error {
-	if len(config.OpenTelemetryEndpoint) == 0 {
+	mapDeprecatedConfig()
+
+	if !config.OpenTelemetryEnable {
 		return nil
 	}
 
@@ -81,25 +85,29 @@ func Init() error {
 		err            error
 	)
 
-	switch config.OpenTelemetryProtocol {
+	protocol := "grpc"
+	configurators.String(&protocol, "OTEL_EXPORTER_OTLP_PROTOCOL")
+
+	switch protocol {
 	case "grpc":
 		traceExporter, metricExporter, err = buildGRPCExporters()
-	case "https":
-		traceExporter, metricExporter, err = buildHTTPExporters(false)
-	case "http":
-		traceExporter, metricExporter, err = buildHTTPExporters(true)
+	case "http/protobuf", "http", "https":
+		traceExporter, metricExporter, err = buildHTTPExporters()
 	default:
-		return fmt.Errorf("Unknown OpenTelemetry protocol: %s", config.OpenTelemetryProtocol)
+		return fmt.Errorf("Unsupported OpenTelemetry protocol: %s", protocol)
 	}
 
 	if err != nil {
 		return err
 	}
 
+	if len(os.Getenv("OTEL_SERVICE_NAME")) == 0 {
+		os.Setenv("OTEL_SERVICE_NAME", "imgproxy")
+	}
+
 	res, _ := resource.Merge(
 		resource.Default(),
 		resource.NewSchemaless(
-			semconv.ServiceNameKey.String(config.OpenTelemetryServiceName),
 			semconv.ServiceVersionKey.String(version.Version()),
 		),
 	)
@@ -140,8 +148,11 @@ func Init() error {
 
 	tracer = tracerProvider.Tracer("imgproxy")
 
-	if len(config.OpenTelemetryPropagators) > 0 {
-		propagator, err = autoprop.TextMapPropagator(config.OpenTelemetryPropagators...)
+	var propagatorNames []string
+	configurators.StringSlice(&propagatorNames, "OTEL_PROPAGATORS")
+
+	if len(propagatorNames) > 0 {
+		propagator, err = autoprop.TextMapPropagator(propagatorNames...)
 		if err != nil {
 			return err
 		}
@@ -174,35 +185,83 @@ func Init() error {
 	return nil
 }
 
+func mapDeprecatedConfig() {
+	endpoint := os.Getenv("IMGPROXY_OPEN_TELEMETRY_ENDPOINT")
+	if len(endpoint) > 0 {
+		logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_ENDPOINT config is deprecated. Use IMGPROXY_OPEN_TELEMETRY_ENABLE and OTEL_EXPORTER_OTLP_ENDPOINT instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+		config.OpenTelemetryEnable = true
+	}
+
+	if !config.OpenTelemetryEnable {
+		return
+	}
+
+	protocol := "grpc"
+
+	if prot := os.Getenv("IMGPROXY_OPEN_TELEMETRY_PROTOCOL"); len(prot) > 0 {
+		logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_PROTOCOL config is deprecated. Use OTEL_EXPORTER_OTLP_PROTOCOL instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+		protocol = prot
+		os.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", protocol)
+	}
+
+	if len(endpoint) > 0 {
+		schema := "https"
+
+		switch protocol {
+		case "grpc":
+			if insecure, _ := strconv.ParseBool(os.Getenv("IMGPROXY_OPEN_TELEMETRY_GRPC_INSECURE")); insecure {
+				logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_GRPC_INSECURE config is deprecated. Use OTEL_EXPORTER_OTLP_ENDPOINT with the `http://` schema instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+				schema = "http"
+			}
+		case "http":
+			schema = "http"
+		}
+
+		os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", fmt.Sprintf("%s://%s", schema, endpoint))
+	}
+
+	if serviceName := os.Getenv("IMGPROXY_OPEN_TELEMETRY_SERVICE_NAME"); len(serviceName) > 0 {
+		logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_SERVICE_NAME config is deprecated. Use OTEL_SERVICE_NAME instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+		os.Setenv("OTEL_SERVICE_NAME", serviceName)
+	}
+
+	if propagators := os.Getenv("IMGPROXY_OPEN_TELEMETRY_PROPAGATORS"); len(propagators) > 0 {
+		logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_PROPAGATORS config is deprecated. Use OTEL_PROPAGATORS instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+		os.Setenv("OTEL_PROPAGATORS", propagators)
+	}
+
+	if timeout := os.Getenv("IMGPROXY_OPEN_TELEMETRY_CONNECTION_TIMEOUT"); len(timeout) > 0 {
+		logrus.Warn("The IMGPROXY_OPEN_TELEMETRY_CONNECTION_TIMEOUT config is deprecated. Use OTEL_EXPORTER_OTLP_TIMEOUT instead. See https://docs.imgproxy.net/latest/monitoring/open_telemetry#deprecated-environment-variables")
+
+		if to, _ := strconv.Atoi(timeout); to > 0 {
+			os.Setenv("OTEL_EXPORTER_OTLP_TIMEOUT", strconv.Itoa(to*1000))
+		}
+	}
+}
+
 func buildGRPCExporters() (*otlptrace.Exporter, sdkmetric.Exporter, error) {
 	tracerOpts := []otlptracegrpc.Option{
-		otlptracegrpc.WithEndpoint(config.OpenTelemetryEndpoint),
 		otlptracegrpc.WithDialOption(grpc.WithBlock()),
 	}
 
 	meterOpts := []otlpmetricgrpc.Option{
-		otlpmetricgrpc.WithEndpoint(config.OpenTelemetryEndpoint),
 		otlpmetricgrpc.WithDialOption(grpc.WithBlock()),
 	}
 
-	tlsConf, err := buildTLSConfig()
-	if err != nil {
-		return nil, nil, err
-	}
-
-	if tlsConf != nil {
+	if tlsConf, err := buildTLSConfig(); tlsConf != nil && err == nil {
 		creds := credentials.NewTLS(tlsConf)
 		tracerOpts = append(tracerOpts, otlptracegrpc.WithTLSCredentials(creds))
 		meterOpts = append(meterOpts, otlpmetricgrpc.WithTLSCredentials(creds))
-	} else if config.OpenTelemetryGRPCInsecure {
-		tracerOpts = append(tracerOpts, otlptracegrpc.WithInsecure())
-		meterOpts = append(meterOpts, otlpmetricgrpc.WithInsecure())
+	} else if err != nil {
+		return nil, nil, err
 	}
 
-	trctx, trcancel := context.WithTimeout(
-		context.Background(),
-		time.Duration(config.OpenTelemetryConnectionTimeout)*time.Second,
-	)
+	tracesConnTimeout, metricsConnTimeout, err := getConnectionTimeouts()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	trctx, trcancel := context.WithTimeout(context.Background(), tracesConnTimeout)
 	defer trcancel()
 
 	traceExporter, err := otlptracegrpc.New(trctx, tracerOpts...)
@@ -214,10 +273,7 @@ func buildGRPCExporters() (*otlptrace.Exporter, sdkmetric.Exporter, error) {
 		return traceExporter, nil, err
 	}
 
-	mtctx, mtcancel := context.WithTimeout(
-		context.Background(),
-		time.Duration(config.OpenTelemetryConnectionTimeout)*time.Second,
-	)
+	mtctx, mtcancel := context.WithTimeout(context.Background(), metricsConnTimeout)
 	defer mtcancel()
 
 	metricExporter, err := otlpmetricgrpc.New(mtctx, meterOpts...)
@@ -228,34 +284,23 @@ func buildGRPCExporters() (*otlptrace.Exporter, sdkmetric.Exporter, error) {
 	return traceExporter, metricExporter, err
 }
 
-func buildHTTPExporters(insecure bool) (*otlptrace.Exporter, sdkmetric.Exporter, error) {
-	tracerOpts := []otlptracehttp.Option{
-		otlptracehttp.WithEndpoint(config.OpenTelemetryEndpoint),
-	}
+func buildHTTPExporters() (*otlptrace.Exporter, sdkmetric.Exporter, error) {
+	tracerOpts := []otlptracehttp.Option{}
+	meterOpts := []otlpmetrichttp.Option{}
 
-	meterOpts := []otlpmetrichttp.Option{
-		otlpmetrichttp.WithEndpoint(config.OpenTelemetryEndpoint),
+	if tlsConf, err := buildTLSConfig(); tlsConf != nil && err == nil {
+		tracerOpts = append(tracerOpts, otlptracehttp.WithTLSClientConfig(tlsConf))
+		meterOpts = append(meterOpts, otlpmetrichttp.WithTLSClientConfig(tlsConf))
+	} else if err != nil {
+		return nil, nil, err
 	}
 
-	if insecure {
-		tracerOpts = append(tracerOpts, otlptracehttp.WithInsecure())
-		meterOpts = append(meterOpts, otlpmetrichttp.WithInsecure())
-	} else {
-		tlsConf, err := buildTLSConfig()
-		if err != nil {
-			return nil, nil, err
-		}
-
-		if tlsConf != nil {
-			tracerOpts = append(tracerOpts, otlptracehttp.WithTLSClientConfig(tlsConf))
-			meterOpts = append(meterOpts, otlpmetrichttp.WithTLSClientConfig(tlsConf))
-		}
+	tracesConnTimeout, metricsConnTimeout, err := getConnectionTimeouts()
+	if err != nil {
+		return nil, nil, err
 	}
 
-	trctx, trcancel := context.WithTimeout(
-		context.Background(),
-		time.Duration(config.OpenTelemetryConnectionTimeout)*time.Second,
-	)
+	trctx, trcancel := context.WithTimeout(context.Background(), tracesConnTimeout)
 	defer trcancel()
 
 	traceExporter, err := otlptracehttp.New(trctx, tracerOpts...)
@@ -267,10 +312,7 @@ func buildHTTPExporters(insecure bool) (*otlptrace.Exporter, sdkmetric.Exporter,
 		return traceExporter, nil, err
 	}
 
-	mtctx, mtcancel := context.WithTimeout(
-		context.Background(),
-		time.Duration(config.OpenTelemetryConnectionTimeout)*time.Second,
-	)
+	mtctx, mtcancel := context.WithTimeout(context.Background(), metricsConnTimeout)
 	defer mtcancel()
 
 	metricExporter, err := otlpmetrichttp.New(mtctx, meterOpts...)
@@ -281,6 +323,29 @@ func buildHTTPExporters(insecure bool) (*otlptrace.Exporter, sdkmetric.Exporter,
 	return traceExporter, metricExporter, err
 }
 
+func getConnectionTimeouts() (time.Duration, time.Duration, error) {
+	connTimeout := 10000
+	configurators.Int(&connTimeout, "OTEL_EXPORTER_OTLP_TIMEOUT")
+
+	tracesConnTimeout := connTimeout
+	configurators.Int(&tracesConnTimeout, "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT")
+
+	metricsConnTimeout := connTimeout
+	configurators.Int(&metricsConnTimeout, "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT")
+
+	if tracesConnTimeout <= 0 {
+		return 0, 0, errors.New("Opentelemetry traces timeout should be greater than 0")
+	}
+
+	if metricsConnTimeout <= 0 {
+		return 0, 0, errors.New("Opentelemetry metrics timeout should be greater than 0")
+	}
+
+	return time.Duration(tracesConnTimeout) * time.Millisecond,
+		time.Duration(metricsConnTimeout) * time.Millisecond,
+		nil
+}
+
 func buildTLSConfig() (*tls.Config, error) {
 	if len(config.OpenTelemetryServerCert) == 0 {
 		return nil, nil