forgejo/modules/opentelemetry/otel.go
TheFox0x7 c738542201 Open telemetry integration (#3972)
This PR adds opentelemetry and chi wrapper to have basic instrumentation

<!--start release-notes-assistant-->

## Draft release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
  - [PR](https://codeberg.org/forgejo/forgejo/pulls/3972): <!--number 3972 --><!--line 0 --><!--description YWRkIHN1cHBvcnQgZm9yIGJhc2ljIHJlcXVlc3QgdHJhY2luZyB3aXRoIG9wZW50ZWxlbWV0cnk=-->add support for basic request tracing with opentelemetry<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/3972
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-committed-by: TheFox0x7 <thefox0x7@gmail.com>
2024-08-05 06:04:39 +00:00

97 lines
2.2 KiB
Go

// 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)
}