Подключение 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"