summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorTheFox0x7 <thefox0x7@gmail.com>2024-08-07 11:22:43 +0200
committerTheFox0x7 <thefox0x7@gmail.com>2024-08-07 11:22:43 +0200
commit2e2a0444934133213399765993abadc2e354e0f3 (patch)
tree0f0d1c0a271797584af5c2e72f3ff24fb0f92323 /modules
parentMerge pull request '[BUG] Ensure all filters are persistent in issue filters'... (diff)
downloadforgejo-2e2a0444934133213399765993abadc2e354e0f3.tar.xz
forgejo-2e2a0444934133213399765993abadc2e354e0f3.zip
Revert "Open telemetry integration (#3972)"
This reverts commit c738542201d4d6f960184cb913055322138c1b46.
Diffstat (limited to 'modules')
-rw-r--r--modules/opentelemetry/otel.go96
-rw-r--r--modules/opentelemetry/otel_test.go121
-rw-r--r--modules/opentelemetry/resource.go90
-rw-r--r--modules/opentelemetry/resource_test.go73
-rw-r--r--modules/opentelemetry/traces.go98
-rw-r--r--modules/opentelemetry/traces_test.go114
-rw-r--r--modules/setting/opentelemetry.go199
-rw-r--r--modules/setting/opentelemetry_test.go239
-rw-r--r--modules/setting/setting.go1
9 files changed, 0 insertions, 1031 deletions
diff --git a/modules/opentelemetry/otel.go b/modules/opentelemetry/otel.go
deleted file mode 100644
index 963b696a54..0000000000
--- a/modules/opentelemetry/otel.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "crypto/tls"
- "crypto/x509"
- "fmt"
- "os"
-
- "code.gitea.io/gitea/modules/graceful"
- "code.gitea.io/gitea/modules/log"
-
- "github.com/go-logr/logr/funcr"
- "go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/propagation"
-)
-
-func Init(ctx context.Context) error {
- // Redirect otel logger to write to common forgejo log at info
- logWrap := funcr.New(func(prefix, args string) {
- log.Info(fmt.Sprint(prefix, args))
- }, funcr.Options{})
- otel.SetLogger(logWrap)
- // Redirect error handling to forgejo log as well
- otel.SetErrorHandler(otel.ErrorHandlerFunc(func(cause error) {
- log.Error("internal opentelemetry error was raised: %s", cause)
- }))
- var shutdownFuncs []func(context.Context) error
- shutdownCtx := context.Background()
-
- otel.SetTextMapPropagator(newPropagator())
-
- res, err := newResource(ctx)
- if err != nil {
- return err
- }
-
- traceShutdown, err := setupTraceProvider(ctx, res)
- if err != nil {
- log.Warn("OpenTelemetry trace setup failed, err=%s", err)
- } else {
- shutdownFuncs = append(shutdownFuncs, traceShutdown)
- }
-
- graceful.GetManager().RunAtShutdown(ctx, func() {
- for _, fn := range shutdownFuncs {
- if err := fn(shutdownCtx); err != nil {
- log.Warn("exporter shutdown failed, err=%s", err)
- }
- }
- shutdownFuncs = nil
- })
-
- return nil
-}
-
-func newPropagator() propagation.TextMapPropagator {
- return propagation.NewCompositeTextMapPropagator(
- propagation.TraceContext{},
- propagation.Baggage{},
- )
-}
-
-func withCertPool(path string, tlsConf *tls.Config) {
- if path == "" {
- return
- }
- b, err := os.ReadFile(path)
- if err != nil {
- log.Warn("Otel: reading ca cert failed path=%s, err=%s", path, err)
- return
- }
- cp := x509.NewCertPool()
- if ok := cp.AppendCertsFromPEM(b); !ok {
- log.Warn("Otel: no valid PEM certificate found path=%s", path)
- return
- }
- tlsConf.RootCAs = cp
-}
-
-func withClientCert(nc, nk string, tlsConf *tls.Config) {
- if nc == "" || nk == "" {
- return
- }
-
- crt, err := tls.LoadX509KeyPair(nc, nk)
- if err != nil {
- log.Warn("Otel: create tls client key pair failed")
- return
- }
-
- tlsConf.Certificates = append(tlsConf.Certificates, crt)
-}
diff --git a/modules/opentelemetry/otel_test.go b/modules/opentelemetry/otel_test.go
deleted file mode 100644
index d40146f9cb..0000000000
--- a/modules/opentelemetry/otel_test.go
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "crypto/ed25519"
- "crypto/rand"
- "crypto/tls"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "math/big"
- "net"
- "os"
- "strings"
- "testing"
- "time"
-
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.opentelemetry.io/otel"
- sdktrace "go.opentelemetry.io/otel/sdk/trace"
- "go.opentelemetry.io/otel/sdk/trace/tracetest"
-)
-
-func TestNoopDefault(t *testing.T) {
- inMem := tracetest.NewInMemoryExporter()
- called := false
- exp := func(ctx context.Context) (sdktrace.SpanExporter, error) {
- called = true
- return inMem, nil
- }
- exporter["inmemory"] = exp
- t.Cleanup(func() {
- delete(exporter, "inmemory")
- })
- defer test.MockVariableValue(&setting.OpenTelemetry.Traces, "inmemory")
-
- ctx := context.Background()
- require.NoError(t, Init(ctx))
- tracer := otel.Tracer("test_noop")
-
- _, span := tracer.Start(ctx, "test span")
- defer span.End()
-
- assert.False(t, span.SpanContext().HasTraceID())
- assert.False(t, span.SpanContext().HasSpanID())
- assert.False(t, called)
-}
-
-func generateTestTLS(t *testing.T, path, host string) *tls.Config {
- _, priv, err := ed25519.GenerateKey(rand.Reader)
- require.NoError(t, err, "Failed to generate private key: %v", err)
-
- keyUsage := x509.KeyUsageDigitalSignature
-
- notBefore := time.Now()
- notAfter := notBefore.Add(time.Hour)
-
- serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
- serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
- require.NoError(t, err, "Failed to generate serial number: %v", err)
-
- template := x509.Certificate{
- SerialNumber: serialNumber,
- Subject: pkix.Name{
- Organization: []string{"Forgejo Testing"},
- },
- NotBefore: notBefore,
- NotAfter: notAfter,
-
- KeyUsage: keyUsage,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
- BasicConstraintsValid: true,
- }
-
- hosts := strings.Split(host, ",")
- for _, h := range hosts {
- if ip := net.ParseIP(h); ip != nil {
- template.IPAddresses = append(template.IPAddresses, ip)
- } else {
- template.DNSNames = append(template.DNSNames, h)
- }
- }
-
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
- require.NoError(t, err, "Failed to create certificate: %v", err)
-
- certOut, err := os.Create(path + "/cert.pem")
- require.NoError(t, err, "Failed to open cert.pem for writing: %v", err)
-
- if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
- t.Fatalf("Failed to write data to cert.pem: %v", err)
- }
- if err := certOut.Close(); err != nil {
- t.Fatalf("Error closing cert.pem: %v", err)
- }
- keyOut, err := os.OpenFile(path+"/key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
- require.NoError(t, err, "Failed to open key.pem for writing: %v", err)
-
- privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
- require.NoError(t, err, "Unable to marshal private key: %v", err)
-
- if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
- t.Fatalf("Failed to write data to key.pem: %v", err)
- }
- if err := keyOut.Close(); err != nil {
- t.Fatalf("Error closing key.pem: %v", err)
- }
- serverCert, err := tls.LoadX509KeyPair(path+"/cert.pem", path+"/key.pem")
- require.NoError(t, err, "failed to load the key pair")
- return &tls.Config{
- Certificates: []tls.Certificate{serverCert},
- ClientAuth: tls.RequireAnyClientCert,
- }
-}
diff --git a/modules/opentelemetry/resource.go b/modules/opentelemetry/resource.go
deleted file mode 100644
index 419c98a074..0000000000
--- a/modules/opentelemetry/resource.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "net/url"
- "strings"
-
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
-
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/sdk/resource"
- semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
-)
-
-const (
- decoderTelemetrySdk = "sdk"
- decoderProcess = "process"
- decoderOS = "os"
- decoderHost = "host"
-)
-
-func newResource(ctx context.Context) (*resource.Resource, error) {
- opts := []resource.Option{
- resource.WithAttributes(parseSettingAttributes(setting.OpenTelemetry.ResourceAttributes)...),
- }
- opts = append(opts, parseDecoderOpts()...)
- opts = append(opts, resource.WithAttributes(
- semconv.ServiceName(setting.OpenTelemetry.ServiceName),
- semconv.ServiceVersion(setting.ForgejoVersion),
- ))
- return resource.New(ctx, opts...)
-}
-
-func parseDecoderOpts() []resource.Option {
- var opts []resource.Option
- for _, v := range strings.Split(setting.OpenTelemetry.ResourceDetectors, ",") {
- switch v {
- case decoderTelemetrySdk:
- opts = append(opts, resource.WithTelemetrySDK())
- case decoderProcess:
- opts = append(opts, resource.WithProcess())
- case decoderOS:
- opts = append(opts, resource.WithOS())
- case decoderHost:
- opts = append(opts, resource.WithHost())
- case "": // Don't warn on empty string
- default:
- log.Warn("Ignoring unknown resource decoder option: %s", v)
- }
- }
- return opts
-}
-
-func parseSettingAttributes(s string) []attribute.KeyValue {
- var attrs []attribute.KeyValue
- rawAttrs := strings.TrimSpace(s)
-
- if rawAttrs == "" {
- return attrs
- }
-
- pairs := strings.Split(rawAttrs, ",")
-
- var invalid []string
- for _, p := range pairs {
- k, v, found := strings.Cut(p, "=")
- if !found {
- invalid = append(invalid, p)
- continue
- }
- key := strings.TrimSpace(k)
- val, err := url.PathUnescape(strings.TrimSpace(v))
- if err != nil {
- // Retain original value if decoding fails, otherwise it will be
- // an empty string.
- val = v
- log.Warn("Otel resource attribute decoding error, retaining unescaped value. key=%s, val=%s", key, val)
- }
- attrs = append(attrs, attribute.String(key, val))
- }
- if len(invalid) > 0 {
- log.Warn("Partial resource, missing values: %v", invalid)
- }
-
- return attrs
-}
diff --git a/modules/opentelemetry/resource_test.go b/modules/opentelemetry/resource_test.go
deleted file mode 100644
index 9a1733bac1..0000000000
--- a/modules/opentelemetry/resource_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "slices"
- "testing"
-
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/sdk/resource"
- semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
-)
-
-func TestResourceServiceName(t *testing.T) {
- ctx := context.Background()
-
- resource, err := newResource(ctx)
- require.NoError(t, err)
- serviceKeyIdx := slices.IndexFunc(resource.Attributes(), func(v attribute.KeyValue) bool {
- return v.Key == semconv.ServiceNameKey
- })
- require.NotEqual(t, -1, serviceKeyIdx)
-
- assert.Equal(t, "forgejo", resource.Attributes()[serviceKeyIdx].Value.AsString())
-
- defer test.MockVariableValue(&setting.OpenTelemetry.ServiceName, "non-default value")()
- resource, err = newResource(ctx)
- require.NoError(t, err)
-
- serviceKeyIdx = slices.IndexFunc(resource.Attributes(), func(v attribute.KeyValue) bool {
- return v.Key == semconv.ServiceNameKey
- })
- require.NotEqual(t, -1, serviceKeyIdx)
-
- assert.Equal(t, "non-default value", resource.Attributes()[serviceKeyIdx].Value.AsString())
-}
-
-func TestResourceAttributes(t *testing.T) {
- ctx := context.Background()
- defer test.MockVariableValue(&setting.OpenTelemetry.ResourceDetectors, "foo")()
- defer test.MockVariableValue(&setting.OpenTelemetry.ResourceAttributes, "Test=LABEL,broken,unescape=%XXlabel")()
- res, err := newResource(ctx)
- require.NoError(t, err)
- expected, err := resource.New(ctx, resource.WithAttributes(
- semconv.ServiceName(setting.OpenTelemetry.ServiceName),
- semconv.ServiceVersion(setting.ForgejoVersion),
- attribute.String("Test", "LABEL"),
- attribute.String("unescape", "%XXlabel"),
- ))
- require.NoError(t, err)
- assert.Equal(t, expected, res)
-}
-
-func TestDecoderParity(t *testing.T) {
- ctx := context.Background()
- defer test.MockVariableValue(&setting.OpenTelemetry.ResourceDetectors, "sdk,process,os,host")()
- exp, err := resource.New(
- ctx, resource.WithTelemetrySDK(), resource.WithOS(), resource.WithProcess(), resource.WithHost(), resource.WithAttributes(
- semconv.ServiceName(setting.OpenTelemetry.ServiceName), semconv.ServiceVersion(setting.ForgejoVersion),
- ),
- )
- require.NoError(t, err)
- res2, err := newResource(ctx)
- require.NoError(t, err)
- assert.Equal(t, exp, res2)
-}
diff --git a/modules/opentelemetry/traces.go b/modules/opentelemetry/traces.go
deleted file mode 100644
index 30d9436392..0000000000
--- a/modules/opentelemetry/traces.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "crypto/tls"
-
- "code.gitea.io/gitea/modules/setting"
-
- "go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
- "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
- "go.opentelemetry.io/otel/sdk/resource"
- sdktrace "go.opentelemetry.io/otel/sdk/trace"
- "google.golang.org/grpc/credentials"
-)
-
-func newGrpcExporter(ctx context.Context) (sdktrace.SpanExporter, error) {
- endpoint := setting.OpenTelemetry.OtelTraces.Endpoint
-
- opts := []otlptracegrpc.Option{}
-
- tlsConf := &tls.Config{}
- opts = append(opts, otlptracegrpc.WithEndpoint(endpoint.Host))
- opts = append(opts, otlptracegrpc.WithTimeout(setting.OpenTelemetry.OtelTraces.Timeout))
- switch setting.OpenTelemetry.OtelTraces.Endpoint.Scheme {
- case "http", "unix":
- opts = append(opts, otlptracegrpc.WithInsecure())
- }
-
- if setting.OpenTelemetry.OtelTraces.Compression != "" {
- opts = append(opts, otlptracegrpc.WithCompressor(setting.OpenTelemetry.OtelTraces.Compression))
- }
- withCertPool(setting.OpenTelemetry.OtelTraces.Certificate, tlsConf)
- withClientCert(setting.OpenTelemetry.OtelTraces.ClientCertificate, setting.OpenTelemetry.OtelTraces.ClientKey, tlsConf)
- if tlsConf.RootCAs != nil || len(tlsConf.Certificates) > 0 {
- opts = append(opts, otlptracegrpc.WithTLSCredentials(
- credentials.NewTLS(tlsConf),
- ))
- }
- opts = append(opts, otlptracegrpc.WithHeaders(setting.OpenTelemetry.OtelTraces.Headers))
-
- return otlptracegrpc.New(ctx, opts...)
-}
-
-func newHTTPExporter(ctx context.Context) (sdktrace.SpanExporter, error) {
- endpoint := setting.OpenTelemetry.OtelTraces.Endpoint
- opts := []otlptracehttp.Option{}
- tlsConf := &tls.Config{}
- opts = append(opts, otlptracehttp.WithEndpoint(endpoint.Host))
- switch setting.OpenTelemetry.OtelTraces.Endpoint.Scheme {
- case "http", "unix":
- opts = append(opts, otlptracehttp.WithInsecure())
- }
- switch setting.OpenTelemetry.OtelTraces.Compression {
- case "gzip":
- opts = append(opts, otlptracehttp.WithCompression(otlptracehttp.GzipCompression))
- default:
- opts = append(opts, otlptracehttp.WithCompression(otlptracehttp.NoCompression))
- }
- withCertPool(setting.OpenTelemetry.OtelTraces.Certificate, tlsConf)
- withClientCert(setting.OpenTelemetry.OtelTraces.ClientCertificate, setting.OpenTelemetry.OtelTraces.ClientKey, tlsConf)
- if tlsConf.RootCAs != nil || len(tlsConf.Certificates) > 0 {
- opts = append(opts, otlptracehttp.WithTLSClientConfig(tlsConf))
- }
- opts = append(opts, otlptracehttp.WithHeaders(setting.OpenTelemetry.OtelTraces.Headers))
-
- return otlptracehttp.New(ctx, opts...)
-}
-
-var exporter = map[string]func(context.Context) (sdktrace.SpanExporter, error){
- "http/protobuf": newHTTPExporter,
- "grpc": newGrpcExporter,
-}
-
-// Create new and register trace provider from user defined configuration
-func setupTraceProvider(ctx context.Context, r *resource.Resource) (func(context.Context) error, error) {
- var shutdown func(context.Context) error
- switch setting.OpenTelemetry.Traces {
- case "otlp":
- traceExporter, err := exporter[setting.OpenTelemetry.OtelTraces.Protocol](ctx)
- if err != nil {
- return nil, err
- }
- traceProvider := sdktrace.NewTracerProvider(
- sdktrace.WithSampler(setting.OpenTelemetry.Sampler),
- sdktrace.WithBatcher(traceExporter),
- sdktrace.WithResource(r),
- )
- otel.SetTracerProvider(traceProvider)
- shutdown = traceProvider.Shutdown
- default:
- shutdown = func(ctx context.Context) error { return nil }
- }
- return shutdown, nil
-}
diff --git a/modules/opentelemetry/traces_test.go b/modules/opentelemetry/traces_test.go
deleted file mode 100644
index dcc3c57394..0000000000
--- a/modules/opentelemetry/traces_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package opentelemetry
-
-import (
- "context"
- "net"
- "net/http"
- "net/http/httptest"
- "net/url"
- "os"
- "testing"
- "time"
-
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.opentelemetry.io/otel"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
-)
-
-func TestTraceGrpcExporter(t *testing.T) {
- grpcMethods := make(chan string)
- tlsConfig := generateTestTLS(t, os.TempDir(), "localhost,127.0.0.1")
- assert.NotNil(t, tlsConfig)
-
- collector := grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)), grpc.UnknownServiceHandler(func(srv any, stream grpc.ServerStream) error {
- method, _ := grpc.Method(stream.Context())
- grpcMethods <- method
- return nil
- }))
- defer collector.GracefulStop()
- ln, err := net.Listen("tcp", "localhost:0")
- require.NoError(t, err)
- defer ln.Close()
- go collector.Serve(ln)
-
- traceEndpoint, err := url.Parse("https://" + ln.Addr().String())
- require.NoError(t, err)
- config := &setting.OtelExporter{
- Endpoint: traceEndpoint,
- Certificate: os.TempDir() + "/cert.pem",
- ClientCertificate: os.TempDir() + "/cert.pem",
- ClientKey: os.TempDir() + "/key.pem",
- Protocol: "grpc",
- }
-
- defer test.MockVariableValue(&setting.OpenTelemetry.ServiceName, "forgejo-certs")()
- defer test.MockVariableValue(&setting.OpenTelemetry.Enabled, true)()
- defer test.MockVariableValue(&setting.OpenTelemetry.Traces, "otlp")()
- defer test.MockVariableValue(&setting.OpenTelemetry.OtelTraces, config)()
- ctx := context.Background()
- require.NoError(t, Init(ctx))
-
- tracer := otel.Tracer("test_tls")
- _, span := tracer.Start(ctx, "test span")
- assert.True(t, span.SpanContext().HasTraceID())
- assert.True(t, span.SpanContext().HasSpanID())
-
- span.End()
- // Give the exporter time to send the span
- select {
- case method := <-grpcMethods:
- assert.Equal(t, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", method)
- case <-time.After(10 * time.Second):
- t.Fatal("no grpc call within 10s")
- }
-}
-
-func TestTraceHttpExporter(t *testing.T) {
- httpCalls := make(chan string)
- tlsConfig := generateTestTLS(t, os.TempDir(), "localhost,127.0.0.1")
- assert.NotNil(t, tlsConfig)
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- httpCalls <- r.URL.Path
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(`{"success": true}`))
- }))
- server.TLS = tlsConfig
-
- traceEndpoint, err := url.Parse("http://" + server.Listener.Addr().String())
- require.NoError(t, err)
- config := &setting.OtelExporter{
- Endpoint: traceEndpoint,
- Certificate: os.TempDir() + "/cert.pem",
- ClientCertificate: os.TempDir() + "/cert.pem",
- ClientKey: os.TempDir() + "/key.pem",
- Protocol: "http/protobuf",
- }
-
- defer test.MockVariableValue(&setting.OpenTelemetry.ServiceName, "forgejo-certs")()
- defer test.MockVariableValue(&setting.OpenTelemetry.Enabled, true)()
- defer test.MockVariableValue(&setting.OpenTelemetry.Traces, "otlp")()
- defer test.MockVariableValue(&setting.OpenTelemetry.OtelTraces, config)()
- ctx := context.Background()
- require.NoError(t, Init(ctx))
-
- tracer := otel.Tracer("test_tls")
- _, span := tracer.Start(ctx, "test span")
- assert.True(t, span.SpanContext().HasTraceID())
- assert.True(t, span.SpanContext().HasSpanID())
-
- span.End()
- select {
- case path := <-httpCalls:
- assert.Equal(t, "/v1/traces", path)
- case <-time.After(10 * time.Second):
- t.Fatal("no http call within 10s")
- }
-}
diff --git a/modules/setting/opentelemetry.go b/modules/setting/opentelemetry.go
deleted file mode 100644
index 810cb58f5f..0000000000
--- a/modules/setting/opentelemetry.go
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package setting
-
-import (
- "net/url"
- "path/filepath"
- "strconv"
- "strings"
- "time"
-
- "code.gitea.io/gitea/modules/log"
-
- sdktrace "go.opentelemetry.io/otel/sdk/trace"
-)
-
-const (
- opentelemetrySectionName string = "opentelemetry"
- exporter string = ".exporter"
- otlp string = ".otlp"
- alwaysOn string = "always_on"
- alwaysOff string = "always_off"
- traceIDRatio string = "traceidratio"
- parentBasedAlwaysOn string = "parentbased_always_on"
- parentBasedAlwaysOff string = "parentbased_always_off"
- parentBasedTraceIDRatio string = "parentbased_traceidratio"
-)
-
-var OpenTelemetry = struct {
- // Inverse of OTEL_SDK_DISABLE, skips telemetry setup
- Enabled bool
- ServiceName string
- ResourceAttributes string
- ResourceDetectors string
- Sampler sdktrace.Sampler
- Traces string
-
- OtelTraces *OtelExporter
-}{
- ServiceName: "forgejo",
- Traces: "otel",
-}
-
-type OtelExporter struct {
- Endpoint *url.URL `ini:"ENDPOINT"`
- Headers map[string]string `ini:"-"`
- Compression string `ini:"COMPRESSION"`
- Certificate string `ini:"CERTIFICATE"`
- ClientKey string `ini:"CLIENT_KEY"`
- ClientCertificate string `ini:"CLIENT_CERTIFICATE"`
- Timeout time.Duration `ini:"TIMEOUT"`
- Protocol string `ini:"-"`
-}
-
-func createOtlpExporterConfig(rootCfg ConfigProvider, section string) *OtelExporter {
- protocols := []string{"http/protobuf", "grpc"}
- endpoint, _ := url.Parse("http://localhost:4318/")
- exp := &OtelExporter{
- Endpoint: endpoint,
- Timeout: 10 * time.Second,
- Headers: map[string]string{},
- Protocol: "http/protobuf",
- }
-
- loadSection := func(name string) {
- otlp := rootCfg.Section(name)
- if otlp.HasKey("ENDPOINT") {
- endpoint, err := url.Parse(otlp.Key("ENDPOINT").String())
- if err != nil {
- log.Warn("Endpoint parsing failed, section: %s, err %v", name, err)
- } else {
- exp.Endpoint = endpoint
- }
- }
- if err := otlp.MapTo(exp); err != nil {
- log.Warn("Mapping otlp settings failed, section: %s, err: %v", name, err)
- }
-
- exp.Protocol = otlp.Key("PROTOCOL").In(exp.Protocol, protocols)
-
- headers := otlp.Key("HEADERS").String()
- if headers != "" {
- for k, v := range _stringToHeader(headers) {
- exp.Headers[k] = v
- }
- }
- }
- loadSection("opentelemetry.exporter.otlp")
-
- loadSection("opentelemetry.exporter.otlp" + section)
-
- if len(exp.Certificate) > 0 && !filepath.IsAbs(exp.Certificate) {
- exp.Certificate = filepath.Join(CustomPath, exp.Certificate)
- }
- if len(exp.ClientCertificate) > 0 && !filepath.IsAbs(exp.ClientCertificate) {
- exp.ClientCertificate = filepath.Join(CustomPath, exp.ClientCertificate)
- }
- if len(exp.ClientKey) > 0 && !filepath.IsAbs(exp.ClientKey) {
- exp.ClientKey = filepath.Join(CustomPath, exp.ClientKey)
- }
-
- return exp
-}
-
-func loadOpenTelemetryFrom(rootCfg ConfigProvider) {
- sec := rootCfg.Section(opentelemetrySectionName)
- OpenTelemetry.Enabled = sec.Key("ENABLED").MustBool(false)
- if !OpenTelemetry.Enabled {
- return
- }
-
- // Load resource related settings
- OpenTelemetry.ServiceName = sec.Key("SERVICE_NAME").MustString("forgejo")
- OpenTelemetry.ResourceAttributes = sec.Key("RESOURCE_ATTRIBUTES").String()
- OpenTelemetry.ResourceDetectors = strings.ToLower(sec.Key("RESOURCE_DETECTORS").String())
-
- // Load tracing related settings
- samplers := make([]string, 0, len(sampler))
- for k := range sampler {
- samplers = append(samplers, k)
- }
-
- samplerName := sec.Key("TRACES_SAMPLER").In(parentBasedAlwaysOn, samplers)
- samplerArg := sec.Key("TRACES_SAMPLER_ARG").MustString("")
- OpenTelemetry.Sampler = sampler[samplerName](samplerArg)
-
- switch sec.Key("TRACES_EXPORTER").MustString("otlp") {
- case "none":
- OpenTelemetry.Traces = "none"
- default:
- OpenTelemetry.Traces = "otlp"
- OpenTelemetry.OtelTraces = createOtlpExporterConfig(rootCfg, ".traces")
- }
-}
-
-var sampler = map[string]func(arg string) sdktrace.Sampler{
- alwaysOff: func(_ string) sdktrace.Sampler {
- return sdktrace.NeverSample()
- },
- alwaysOn: func(_ string) sdktrace.Sampler {
- return sdktrace.AlwaysSample()
- },
- traceIDRatio: func(arg string) sdktrace.Sampler {
- ratio, err := strconv.ParseFloat(arg, 64)
- if err != nil {
- ratio = 1
- }
- return sdktrace.TraceIDRatioBased(ratio)
- },
- parentBasedAlwaysOff: func(_ string) sdktrace.Sampler {
- return sdktrace.ParentBased(sdktrace.NeverSample())
- },
- parentBasedAlwaysOn: func(_ string) sdktrace.Sampler {
- return sdktrace.ParentBased(sdktrace.AlwaysSample())
- },
- parentBasedTraceIDRatio: func(arg string) sdktrace.Sampler {
- ratio, err := strconv.ParseFloat(arg, 64)
- if err != nil {
- ratio = 1
- }
- return sdktrace.ParentBased(sdktrace.TraceIDRatioBased(ratio))
- },
-}
-
-// Opentelemetry SDK function port
-
-func _stringToHeader(value string) map[string]string {
- headersPairs := strings.Split(value, ",")
- headers := make(map[string]string)
-
- for _, header := range headersPairs {
- n, v, found := strings.Cut(header, "=")
- if !found {
- log.Warn("Otel header ignored on %q: missing '='", header)
- continue
- }
- name, err := url.PathUnescape(n)
- if err != nil {
- log.Warn("Otel header ignored on %q, invalid header key: %s", header, n)
- continue
- }
- trimmedName := strings.TrimSpace(name)
- value, err := url.PathUnescape(v)
- if err != nil {
- log.Warn("Otel header ignored on %q, invalid header value: %s", header, v)
- continue
- }
- trimmedValue := strings.TrimSpace(value)
-
- headers[trimmedName] = trimmedValue
- }
-
- return headers
-}
-
-func IsOpenTelemetryEnabled() bool {
- return OpenTelemetry.Enabled
-}
diff --git a/modules/setting/opentelemetry_test.go b/modules/setting/opentelemetry_test.go
deleted file mode 100644
index 21da3837c7..0000000000
--- a/modules/setting/opentelemetry_test.go
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2024 TheFox0x7. All rights reserved.
-// SPDX-License-Identifier: EUPL-1.2
-
-package setting
-
-import (
- "net/url"
- "testing"
- "time"
-
- "code.gitea.io/gitea/modules/test"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- sdktrace "go.opentelemetry.io/otel/sdk/trace"
-)
-
-func TestExporterLoad(t *testing.T) {
- globalSetting := `
- [opentelemetry.exporter.otlp]
-ENDPOINT=http://example.org:4318/
-CERTIFICATE=/boo/bar
-CLIENT_CERTIFICATE=/foo/bar
-CLIENT_KEY=/bar/bar
-COMPRESSION=
-HEADERS=key=val,val=key
-PROTOCOL=http/protobuf
-TIMEOUT=20s
- `
- endpoint, err := url.Parse("http://example.org:4318/")
- require.NoError(t, err)
- expected := &OtelExporter{
- Endpoint: endpoint,
- Certificate: "/boo/bar",
- ClientCertificate: "/foo/bar",
- ClientKey: "/bar/bar",
- Headers: map[string]string{
- "key": "val", "val": "key",
- },
- Timeout: 20 * time.Second,
- Protocol: "http/protobuf",
- }
- cfg, err := NewConfigProviderFromData(globalSetting)
- require.NoError(t, err)
- exp := createOtlpExporterConfig(cfg, ".traces")
- assert.Equal(t, expected, exp)
- localSetting := `
-[opentelemetry.exporter.otlp.traces]
-ENDPOINT=http://example.com:4318/
-CERTIFICATE=/boo
-CLIENT_CERTIFICATE=/foo
-CLIENT_KEY=/bar
-COMPRESSION=gzip
-HEADERS=key=val2,val1=key
-PROTOCOL=grpc
-TIMEOUT=5s
- `
- endpoint, err = url.Parse("http://example.com:4318/")
- require.NoError(t, err)
- expected = &OtelExporter{
- Endpoint: endpoint,
- Certificate: "/boo",
- ClientCertificate: "/foo",
- ClientKey: "/bar",
- Compression: "gzip",
- Headers: map[string]string{
- "key": "val2", "val1": "key", "val": "key",
- },
- Timeout: 5 * time.Second,
- Protocol: "grpc",
- }
-
- cfg, err = NewConfigProviderFromData(globalSetting + localSetting)
- require.NoError(t, err)
- exp = createOtlpExporterConfig(cfg, ".traces")
- require.NoError(t, err)
- assert.Equal(t, expected, exp)
-}
-
-func TestOpenTelemetryConfiguration(t *testing.T) {
- defer test.MockProtect(&OpenTelemetry)()
- iniStr := ``
- cfg, err := NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
- assert.Nil(t, OpenTelemetry.OtelTraces)
- assert.False(t, IsOpenTelemetryEnabled())
-
- iniStr = `
- [opentelemetry]
- ENABLED=true
- SERVICE_NAME = test service
- RESOURCE_ATTRIBUTES = foo=bar
- TRACES_SAMPLER = always_on
-
- [opentelemetry.exporter.otlp]
- ENDPOINT = http://jaeger:4317/
- TIMEOUT = 30s
- COMPRESSION = gzip
- INSECURE = TRUE
- HEADERS=foo=bar,overwrite=false
- `
- cfg, err = NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
-
- assert.True(t, IsOpenTelemetryEnabled())
- assert.Equal(t, "test service", OpenTelemetry.ServiceName)
- assert.Equal(t, "foo=bar", OpenTelemetry.ResourceAttributes)
- assert.Equal(t, 30*time.Second, OpenTelemetry.OtelTraces.Timeout)
- assert.Equal(t, "gzip", OpenTelemetry.OtelTraces.Compression)
- assert.Equal(t, sdktrace.AlwaysSample(), OpenTelemetry.Sampler)
- assert.Equal(t, "http://jaeger:4317/", OpenTelemetry.OtelTraces.Endpoint.String())
- assert.Contains(t, OpenTelemetry.OtelTraces.Headers, "foo")
- assert.Equal(t, "bar", OpenTelemetry.OtelTraces.Headers["foo"])
- assert.Contains(t, OpenTelemetry.OtelTraces.Headers, "overwrite")
- assert.Equal(t, "false", OpenTelemetry.OtelTraces.Headers["overwrite"])
-}
-
-func TestOpenTelemetryTraceDisable(t *testing.T) {
- defer test.MockProtect(&OpenTelemetry)()
- iniStr := ``
- cfg, err := NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
- assert.False(t, OpenTelemetry.Enabled)
- assert.False(t, IsOpenTelemetryEnabled())
-
- iniStr = `
- [opentelemetry]
- ENABLED=true
- EXPORTER_OTLP_ENDPOINT =
- `
- cfg, err = NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
-
- assert.True(t, IsOpenTelemetryEnabled())
- endpoint, _ := url.Parse("http://localhost:4318/")
- assert.Equal(t, endpoint, OpenTelemetry.OtelTraces.Endpoint)
-}
-
-func TestSamplerCombinations(t *testing.T) {
- defer test.MockProtect(&OpenTelemetry)()
- type config struct {
- IniCfg string
- Expected sdktrace.Sampler
- }
- testSamplers := []config{
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = always_on
- TRACES_SAMPLER_ARG = nothing`, sdktrace.AlwaysSample()},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = always_off`, sdktrace.NeverSample()},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = traceidratio
- TRACES_SAMPLER_ARG = 0.7`, sdktrace.TraceIDRatioBased(0.7)},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = traceidratio
- TRACES_SAMPLER_ARG = badarg`, sdktrace.TraceIDRatioBased(1)},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = parentbased_always_off`, sdktrace.ParentBased(sdktrace.NeverSample())},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = parentbased_always_of`, sdktrace.ParentBased(sdktrace.AlwaysSample())},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = parentbased_traceidratio
- TRACES_SAMPLER_ARG = 0.3`, sdktrace.ParentBased(sdktrace.TraceIDRatioBased(0.3))},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = parentbased_traceidratio
- TRACES_SAMPLER_ARG = badarg`, sdktrace.ParentBased(sdktrace.TraceIDRatioBased(1))},
- {`[opentelemetry]
- ENABLED=true
- TRACES_SAMPLER = not existing
- TRACES_SAMPLER_ARG = badarg`, sdktrace.ParentBased(sdktrace.AlwaysSample())},
- }
-
- for _, sampler := range testSamplers {
- cfg, err := NewConfigProviderFromData(sampler.IniCfg)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
- assert.Equal(t, sampler.Expected, OpenTelemetry.Sampler)
- }
-}
-
-func TestOpentelemetryBadConfigs(t *testing.T) {
- defer test.MockProtect(&OpenTelemetry)()
- iniStr := `
- [opentelemetry]
- ENABLED=true
-
- [opentelemetry.exporter.otlp]
- ENDPOINT = jaeger:4317/
- `
- cfg, err := NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
-
- assert.True(t, IsOpenTelemetryEnabled())
- assert.Equal(t, "jaeger:4317/", OpenTelemetry.OtelTraces.Endpoint.String())
-
- iniStr = ``
- cfg, err = NewConfigProviderFromData(iniStr)
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
- assert.False(t, IsOpenTelemetryEnabled())
-
- iniStr = `
- [opentelemetry]
- ENABLED=true
- SERVICE_NAME =
- TRACES_SAMPLER = not existing one
- [opentelemetry.exporter.otlp]
- ENDPOINT = http://jaeger:4317/
-
- TIMEOUT = abc
- COMPRESSION = foo
- HEADERS=%s=bar,foo=%h,foo
-
- `
-
- cfg, err = NewConfigProviderFromData(iniStr)
-
- require.NoError(t, err)
- loadOpenTelemetryFrom(cfg)
- assert.True(t, IsOpenTelemetryEnabled())
- assert.Equal(t, "forgejo", OpenTelemetry.ServiceName)
- assert.Equal(t, 10*time.Second, OpenTelemetry.OtelTraces.Timeout)
- assert.Equal(t, sdktrace.ParentBased(sdktrace.AlwaysSample()), OpenTelemetry.Sampler)
- assert.Equal(t, "http://jaeger:4317/", OpenTelemetry.OtelTraces.Endpoint.String())
- assert.Empty(t, OpenTelemetry.OtelTraces.Headers)
-}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 9c6f09c13b..892e41cddf 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -150,7 +150,6 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error {
loadAPIFrom(cfg)
loadBadgesFrom(cfg)
loadMetricsFrom(cfg)
- loadOpenTelemetryFrom(cfg)
loadCamoFrom(cfg)
loadI18nFrom(cfg)
loadGitFrom(cfg)