Перейти к содержанию

Подключение otel lib к сервисам

Требования к сервисам

Django сервис

Программное обеспечение Минимальная версия Максимальная версия
Python 3.10 <3.12
Django 4.1.3 —
Psycopg2-binary 2.9.10 —
Httpx 0.27.2 —

FastAPI сервис

Программное обеспечение Минимальная версия Максимальная версия
Python 3.10 <3.13
FastAPI 0.88.0 —
Psycopg2-binary 2.9.10 —
Asyncpg 0.30.0 —
Uvicorn 0.30.0 —
Httpx 0.27.2 —

Golang сервисы

Программное обеспечение Минимальная версия
Golang 1.22.2

Установка для python (FastAPI)

pip install --extra-index-url https://<nexus-user>:<nexus-password>@nexus.infra.sarex.io/repository/PyPi/simple fastapi-otel-tools == 0.0.21

Пример config.py

class TraceSettings(BaseSettings):
    use: bool = False
    host: str = 'localhost'
    service_name: str = 'my-service'
    insecure: bool = True

    class Config:
        env_prefix = 'TRACE_'

class LoggerSettings(BaseSettings):
    format: str = '{"timestamp": "%(asctime)s", "level": "%(levelname)s", "message": "%(message)s"}'

    class Config:
        env_prefix = "LOG_"

    @property
    def logger(self) -> logging.Logger:
        logger = logging.getLogger(__name__)
        handler = logging.StreamHandler(sys.stdout)
        log_level = logging.INFO
        logger.setLevel(log_level)
        handler.setLevel(log_level)
        handler.setFormatter(jsonlogger.JsonFormatter(self.format))
        logger.addHandler(handler)
        return logger

logger = LoggerSettings().logger
trace = TraceSettings()

Пример инициалзации приложения FastAPI


from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from fastapi_otel_tools.logging import init_otel_logger
from fastapi_otel_tools.tracing import setup_otel_tracing
from fastapi_otel_tools.middleware import OtelMiddleware

from config import trace, logger

app = FastAPI()
if trace.use:
    setup_otel_tracing(settings.trace.service_name, settings.trace.host, settings.trace.insecure)
    init_otel_logger(settings.trace.service_name, settings.trace.host, settings.trace.insecure)

    app.add_middleware(OtelMiddleware, logger=logger)
    FastAPIInstrumentor.instrument_app(app)

Запуск приложения через gunicorn

gunicorn -w 1 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 --forwarded-allow-ips '*' --proxy-protocol main:app

Установка для python (Django)

pip install --extra-index-url https://<nexus-user>:<nexus-password>@nexus.infra.sarex.io/repository/PyPi/simple django-otel-tools==0.0.18

base.py

from django_otel_tools.tracing import setup_otel_tracing
from django_otel_tools.logging import get_otel_logger

service_name: str = os.getenv('SERVICE_NAME', 'resources-backend.sarex-resources')
tracer_endpoint: str = os.getenv('TRACER_ENDPOINT', 'localhost:4375')
use_insecure: bool = os.getenv('USE_INSECURE', False)

setup_otel_tracing(service_name, tracer_endpoint, use_insecure)
LOGGER = get_otel_logger(service_name, tracer_endpoint, use_insecure)

MIDDLEWARE = ['django_otel_tools.middleware.OtelMiddleware'] + MIDDLEWARE

uwsgi.ini

[uwsgi]
log-format = {"time": "%(time)", "method": "%(method)", "uri": "%(uri)", "status": "%(status)", "size": "%(size)", "addr": "%(addr)", "user": "%(user)", "proto": "%(proto)", "user_agent": "%(uagent)", "referer": "%(referer)", "trace_id": "%(trace_id)", "span_id": "%(span_id)"}
module                 = config.wsgi:application
DJANGO_SETTINGS_MODULE = config.settings.production
http                   = 0.0.0.0:8000
processes              = 1
master                 = true
vacuum                 = true
enable-threads         = true

wsgi.py

from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware
from django.core.wsgi import get_wsgi_application

application = get_wsgi_application()
application = OpenTelemetryMiddleware(application)

пример запуска приложения

opentelemetry-instrument uwsgi --plugin python3 --ini uwsgi.ini

Установка для golang (net/http)

echo "https://<username>:<token>@gitlab.sarex.io" > ~/.git-credentials && \
    git config --global credential.helper store && \
    go env -w GOPRIVATE=gitlab.sarex.io && \
    go env -w GOPROXY=https://proxy.golang.org,direct && \
    go env -w GONOSUMDB=gitlab.sarex.io

go get gitlab.sarex.io/infra/golang-net-http-otel-tools

main.go

import (
    "log/slog"
    "context"
    oteltools "gitlab.sarex.io/infra/golang-net-http-otel-tools/pkg"
)

var loggerOtel *slog.Logger
ctx := context.Background()

if cfg.TracerUse {
        tracerConfig := oteltools.TracerConfig{
            Context:     ctx,
            UseInsecure: cfg.TracerInsecure,
            Host:        cfg.TracerHost,
            ServiceName: cfg.ServiceName,
            LoggerName:  cfg.TracerLoggerName,
        }
        shutdownTracer, errTracer := oteltools.InitTracer(&tracerConfig)
        if errTracer != nil {
            logger.Fatalf("failed to set up otel: %v", err)
        }
        defer func() {
            if err := shutdownTracer(ctx); err != nil {
                logger.Info("failed to shutdown otel: %v", err)
            }
        }()
        var err error
        loggerOtel, shutdownLogger, err = oteltools.SetupLogger(&tracerConfig)
        if err != nil {
            panic(fmt.Sprintf("failed to set up otel logger: %v", err))
        }
        defer shutdownLogger()
    } else {
        loggerOtel = nil
    }

// connections to DB
db := pg.Connect(&pg.Options{
        User:       cfg.PostgresUser,
        Password:   cfg.PostgresPassword,
        Database:   cfg.PostgresDatabase,
        Addr:       fmt.Sprintf("%s:%s", cfg.PostgresAddr, cfg.PostgresPort),
        MaxRetries: 3,
        PoolSize:   cfg.PostgresPoolSize,
        TLSConfig:  tlsConfig,
    })
    defer func() { _ = db.Close() }()
    if cfg.EnableSQLQuery {
        db.AddQueryHook(&gpg.Logger{})
    }
    if cfg.TracerUse {
        db.AddQueryHook(pgotel.NewTracingHook())
    }

bootstrap.go

import (
    "gitlab.sarex.io/platform/gotools/rest"
    oteltools "gitlab.sarex.io/infra/golang-net-http-otel-tools/pkg"
    "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

router := rest.NewCustomRouter(logger)

apiV1 := router.PathPrefix("/api/v1").Subrouter()
internalV1 := router.PathPrefix("/internal/v1").Subrouter()
if cfg.TracerUse {
    router.Use(func(next http.Handler) http.Handler {
        next = oteltools.LoggingMiddleware(otelLogger, next)
        otelhttp.NewHandler(next, "HTTPHandler")
    })
}


Установка для golang (Fiber)

echo "https://<username>:<token>@gitlab.sarex.io" > ~/.git-credentials && \
    git config --global credential.helper store && \
    go env -w GOPRIVATE=gitlab.sarex.io && \
    go env -w GOPROXY=https://proxy.golang.org,direct && \
    go env -w GONOSUMDB=gitlab.sarex.io

go get gitlab.com/sarex-team/golang-fiber-otel-tools

main.go

import (
    "log/slog"
    "context"
    oteltools "gitlab.sarex.io/infra/golang-net-http-otel-tools/pkg"
    "github.com/gofiber/contrib/otelfiber/v2"
)
var loggerOtel *slog.Logger
var shutdownLogger func()
ctx := context.Background()

tracerConfig := oteltools.TracerConfig{
    Context: ctx,
    UseInsecure: a.Config.TRACER.Insecure,
    Host: a.Config.TRACER.Host,
    ServiceName: a.Config.TRACER.ServiceName,
    LoggerName: a.Config.TRACER.LoggerName,
}

if (a.Config.TRACER.Use){
  tp := oteltools.InitTracer(&tracerConfig)
  defer func() {
    if err := tp.Shutdown(ctx); err != nil {
      a.logger.Infof("Error shutting down tracer provider: %v", err)
    }
  }()
  var err error
  loggerOtel, shutdownLogger, err = oteltools.SetupLogger(&tracerConfig)
  if err != nil {
    a.logger.Infof(fmt.Sprintf("failed to set up otel logger: %v", err))
  }
  defer shutdownLogger()
  db = pgxconnection.GetPgConnection(ctx, true, a.Config.Postgres, a.logger)

} else {
  db = pgxconnection.GetPgConnection(context.Background(), false, a.Config.Postgres, a.logger)
  loggerOtel = nil 
}

if (a.Config.TRACER.Use){
        a.Fiber.Use(otelfiber.Middleware())
        a.Fiber.Use(oteltools.LoggingMiddleware(*loggerOtel))
}

Значения ENVS для разных окружений (stage, production, preprod)

Переменные окружения для stage

- name: TRACING_USE
  value: "True"
- name: TRACING_HOST
  value: "signoz-otel-collector.signoz.svc.cluster.local:4317"
- name: TRACING_INSECURE
  value: "True"
- name: TRACING_SERVICE_NAME
  value: "<service-name>.<namespace>-stage"

Переменные окружения для production

- name: TRACING_USE
  value: "True"
- name: TRACING_HOST
  value: "otel-collector.opentelemetry-collector.svc.cluster.local:4317"
- name: TRACING_INSECURE
  value: "True"
- name: TRACING_SERVICE_NAME
  value: "<service-name>.<namespace>-prod"

Переменные окружения для preprod

- name: TRACING_USE
  value: "True"
- name: TRACING_HOST
  value: "otel-collector.opentelemetry-collector.svc.cluster.local:4317"
- name: TRACING_INSECURE
  value: "True"
- name: TRACING_SERVICE_NAME
  value: "<service-name>.<namespace>-preprod"