package main
import (
"context"
"io"
"log"
"net/http"
"os"
"github.com/hyperdxio/opentelemetry-go/otelzap"
"github.com/hyperdxio/opentelemetry-logs-go/exporters/otlp/otlplogs"
"github.com/hyperdxio/otel-config-go/otelconfig"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
sdk "github.com/hyperdxio/opentelemetry-logs-go/sdk/logs"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.opentelemetry.io/otel/sdk/resource"
)
// настройка общих атрибутов для всех логов
func newResource() *resource.Resource {
hostName, _ := os.Hostname()
return resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceVersion("1.0.0"),
semconv.HostName(hostName),
)
}
// привязка идентификатора трассировки к логу
func WithTraceMetadata(ctx context.Context, logger *zap.Logger) *zap.Logger {
spanContext := trace.SpanContextFromContext(ctx)
if !spanContext.IsValid() {
// ctx не содержит валидный span.
// Метаданные трассировки отсутствуют.
return logger
}
return logger.With(
zap.String("trace_id", spanContext.TraceID().String()),
zap.String("span_id", spanContext.SpanID().String()),
)
}
func main() {
// Инициализация конфигурации OTel и её использование во всём приложении
otelShutdown, err := otelconfig.ConfigureOpenTelemetry()
if err != nil {
log.Fatalf("ошибка настройки OTel SDK - %e", err)
}
defer otelShutdown()
ctx := context.Background()
// настройка провайдера логгера OpenTelemetry
logExporter, _ := otlplogs.NewExporter(ctx)
loggerProvider := sdk.NewLoggerProvider(
sdk.WithBatcher(logExporter),
)
// корректное завершение работы логгера для сброса накопленных сигналов перед завершением программы
defer loggerProvider.Shutdown(ctx)
// создание нового логгера с ядром OpenTelemetry zap и его глобальная установка
logger := zap.New(otelzap.NewOtelCore(loggerProvider))
zap.ReplaceGlobals(logger)
logger.Warn("hello world", zap.String("foo", "bar"))
http.Handle("/", otelhttp.NewHandler(wrapHandler(logger, ExampleHandler), "example-service"))
port := os.Getenv("PORT")
if port == "" {
port = "7777"
}
logger.Info("** Сервис запущен на порту " + port + " **")
if err := http.ListenAndServe(":"+port, nil); err != nil {
logger.Fatal(err.Error())
}
}
// Используйте для обёртки всех обработчиков с целью добавления метаданных трассировки к логгеру
func wrapHandler(logger *zap.Logger, handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := WithTraceMetadata(r.Context(), logger)
logger.Info("запрос получен", zap.String("url", r.URL.Path), zap.String("method", r.Method))
handler(w, r)
logger.Info("запрос завершён", zap.String("path", r.URL.Path), zap.String("method", r.Method))
}
}
func ExampleHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
io.WriteString(w, `{"status":"ok"}`)
}