Feat: configure audit fields and metrics for onix adapter and add local configuration for onix adapterZ
This commit is contained in:
@@ -3,23 +3,25 @@ package otelsetup
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
clientprom "github.com/prometheus/client_golang/prometheus"
|
||||
clientpromhttp "github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
otelprom "go.opentelemetry.io/otel/exporters/prometheus"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"time"
|
||||
|
||||
"github.com/beckn-one/beckn-onix/pkg/log"
|
||||
"github.com/beckn-one/beckn-onix/pkg/plugin"
|
||||
"github.com/beckn-one/beckn-onix/pkg/telemetry"
|
||||
"go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/log/global"
|
||||
logsdk "go.opentelemetry.io/otel/sdk/log"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"go.opentelemetry.io/otel/sdk/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
// Setup wires the telemetry provider. This is the concrete implementation
|
||||
@@ -30,9 +32,16 @@ type Setup struct{}
|
||||
type Config struct {
|
||||
ServiceName string `yaml:"serviceName"`
|
||||
ServiceVersion string `yaml:"serviceVersion"`
|
||||
EnableMetrics bool `yaml:"enableMetrics"`
|
||||
Environment string `yaml:"environment"`
|
||||
MetricsPort string `yaml:"metricsPort"`
|
||||
Domain string `yaml:"domain"`
|
||||
DeviceID string `yaml:"deviceID"`
|
||||
EnableMetrics bool `yaml:"enableMetrics"`
|
||||
EnableTracing bool `yaml:"enableTracing"`
|
||||
EnableLogs bool `yaml:"enableLogs"`
|
||||
OtlpEndpoint string `yaml:"otlpEndpoint"`
|
||||
TimeInterval int64 `yaml:"timeInterval"`
|
||||
Producer string `yaml:"producer"`
|
||||
ProducerType string `yaml:"producerType"`
|
||||
}
|
||||
|
||||
// DefaultConfig returns sensible defaults for telemetry configuration.
|
||||
@@ -40,9 +49,11 @@ func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
ServiceName: "beckn-onix",
|
||||
ServiceVersion: "dev",
|
||||
EnableMetrics: true,
|
||||
Environment: "development",
|
||||
MetricsPort: "9090",
|
||||
Domain: "",
|
||||
DeviceID: "beckn-onix-device",
|
||||
OtlpEndpoint: "localhost:4317",
|
||||
TimeInterval: 5,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +64,11 @@ func ToPluginConfig(cfg *Config) *plugin.Config {
|
||||
Config: map[string]string{
|
||||
"serviceName": cfg.ServiceName,
|
||||
"serviceVersion": cfg.ServiceVersion,
|
||||
"enableMetrics": fmt.Sprintf("%t", cfg.EnableMetrics),
|
||||
"environment": cfg.Environment,
|
||||
"metricsPort": cfg.MetricsPort,
|
||||
"enableMetrics": fmt.Sprintf("%t", cfg.EnableMetrics),
|
||||
"enableTracing": fmt.Sprintf("%t", cfg.EnableTracing),
|
||||
"otelEndpoint": cfg.OtlpEndpoint,
|
||||
"deviceID": cfg.DeviceID,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -78,92 +91,126 @@ func (Setup) New(ctx context.Context, cfg *Config) (*telemetry.Provider, error)
|
||||
if cfg.Environment == "" {
|
||||
cfg.Environment = DefaultConfig().Environment
|
||||
}
|
||||
if cfg.MetricsPort == "" {
|
||||
cfg.MetricsPort = DefaultConfig().MetricsPort
|
||||
if cfg.Domain == "" {
|
||||
cfg.Domain = DefaultConfig().Domain
|
||||
}
|
||||
if cfg.DeviceID == "" {
|
||||
cfg.DeviceID = DefaultConfig().DeviceID
|
||||
}
|
||||
if cfg.TimeInterval == 0 {
|
||||
cfg.TimeInterval = DefaultConfig().TimeInterval
|
||||
}
|
||||
|
||||
if !cfg.EnableMetrics {
|
||||
log.Info(ctx, "OpenTelemetry metrics disabled")
|
||||
if !cfg.EnableMetrics && !cfg.EnableTracing {
|
||||
log.Info(ctx, "OpenTelemetry metrics and tracing are disabled")
|
||||
return &telemetry.Provider{
|
||||
Shutdown: func(context.Context) error { return nil },
|
||||
}, nil
|
||||
}
|
||||
|
||||
res, err := resource.New(
|
||||
ctx,
|
||||
resource.WithAttributes(
|
||||
attribute.String("service.name", cfg.ServiceName),
|
||||
attribute.String("service.version", cfg.ServiceVersion),
|
||||
attribute.String("deployment.environment", cfg.Environment),
|
||||
),
|
||||
)
|
||||
//this will be used by both matric and traces
|
||||
|
||||
// to build resource with envelope metadata
|
||||
baseAttrs := []attribute.KeyValue{
|
||||
attribute.String("service.name", cfg.ServiceName),
|
||||
attribute.String("service.version", cfg.ServiceVersion),
|
||||
attribute.String("environment", cfg.Environment),
|
||||
attribute.String("domain", cfg.Domain),
|
||||
attribute.String("device_id", cfg.DeviceID),
|
||||
attribute.String("producerType", cfg.ProducerType),
|
||||
attribute.String("producer", cfg.Producer),
|
||||
}
|
||||
|
||||
resMetric, err := resource.New(ctx, resource.WithAttributes(buildAtts(baseAttrs, "METRIC")...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create telemetry resource: %w", err)
|
||||
return nil, fmt.Errorf("failed to create telemetry resource for matric: %w", err)
|
||||
}
|
||||
|
||||
registry := clientprom.NewRegistry()
|
||||
|
||||
exporter, err := otelprom.New(
|
||||
otelprom.WithRegisterer(registry),
|
||||
otelprom.WithoutUnits(),
|
||||
otelprom.WithoutScopeInfo(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create prometheus exporter: %w", err)
|
||||
}
|
||||
|
||||
meterProvider := metric.NewMeterProvider(
|
||||
metric.WithReader(exporter),
|
||||
metric.WithResource(res),
|
||||
)
|
||||
|
||||
otel.SetMeterProvider(meterProvider)
|
||||
log.Infof(ctx, "OpenTelemetry metrics initialized for service=%s version=%s env=%s",
|
||||
cfg.ServiceName, cfg.ServiceVersion, cfg.Environment)
|
||||
|
||||
if err := runtime.Start(runtime.WithMinimumReadMemStatsInterval(0)); err != nil {
|
||||
log.Warnf(ctx, "Failed to start Go runtime instrumentation: %v", err)
|
||||
}
|
||||
|
||||
// Create metrics handler
|
||||
metricsHandler := clientpromhttp.HandlerFor(registry, clientpromhttp.HandlerOpts{})
|
||||
|
||||
// Create and start metrics HTTP server
|
||||
metricsMux := http.NewServeMux()
|
||||
metricsMux.Handle("/metrics", metricsHandler)
|
||||
|
||||
metricsServer := &http.Server{
|
||||
Addr: net.JoinHostPort("", cfg.MetricsPort),
|
||||
Handler: metricsMux,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
var serverWg sync.WaitGroup
|
||||
serverWg.Add(1)
|
||||
go func() {
|
||||
defer serverWg.Done()
|
||||
log.Infof(ctx, "Metrics server listening on %s", metricsServer.Addr)
|
||||
if err := metricsServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Errorf(ctx, fmt.Errorf("metrics server ListenAndServe: %w", err), "error listening and serving metrics")
|
||||
//OTLP matric
|
||||
var meterProvider *metric.MeterProvider
|
||||
if cfg.EnableMetrics {
|
||||
metricExpoter, err := otlpmetricgrpc.New(ctx, otlpmetricgrpc.WithEndpoint(cfg.OtlpEndpoint),
|
||||
otlpmetricgrpc.WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create OTLP metric exporter: %w", err)
|
||||
}
|
||||
}()
|
||||
reader := metric.NewPeriodicReader(metricExpoter, metric.WithInterval(time.Second*time.Duration(cfg.TimeInterval)))
|
||||
meterProvider = metric.NewMeterProvider(metric.WithReader(reader), metric.WithResource(resMetric))
|
||||
otel.SetMeterProvider(meterProvider)
|
||||
log.Infof(ctx, "OpenTelemetry metrics initialized for service=%s version=%s env=%s (OTLP endpoint=%s)",
|
||||
cfg.ServiceName, cfg.ServiceVersion, cfg.Environment, cfg.OtlpEndpoint)
|
||||
// for the go runtime matrics
|
||||
if err := runtime.Start(runtime.WithMinimumReadMemStatsInterval(runtime.DefaultMinimumReadMemStatsInterval)); err != nil {
|
||||
log.Warnf(ctx, "Failed to start Go runtime instrumentation: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
//OTLP traces
|
||||
restrace, err := resource.New(ctx, resource.WithAttributes(buildAtts(baseAttrs, "API")...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create trace resource: %w", err)
|
||||
}
|
||||
var traceProvider *trace.TracerProvider
|
||||
if cfg.EnableTracing {
|
||||
traceExpoter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint(cfg.OtlpEndpoint), otlptracegrpc.WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create OTLP trace exporter: %w", err)
|
||||
}
|
||||
traceProvider = trace.NewTracerProvider(trace.WithBatcher(traceExpoter), trace.WithResource(restrace)) //TODO: need to add the trace sampleing rate
|
||||
otel.SetTracerProvider(traceProvider)
|
||||
log.Infof(ctx, "OpenTelemetry tracing initialized for service=%s (OTLP endpoint=%s)",
|
||||
cfg.ServiceName, cfg.OtlpEndpoint)
|
||||
}
|
||||
|
||||
resAudit, err := resource.New(ctx, resource.WithAttributes(buildAtts(baseAttrs, "AUDIT")...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create audit resource: %w", err)
|
||||
}
|
||||
var logProvider *logsdk.LoggerProvider
|
||||
if cfg.EnableLogs {
|
||||
logExporter, err := otlploggrpc.New(ctx, otlploggrpc.WithEndpoint(cfg.OtlpEndpoint), otlploggrpc.WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create OTLP logs exporter: %w", err)
|
||||
}
|
||||
processor := logsdk.NewBatchProcessor(logExporter)
|
||||
logProvider = logsdk.NewLoggerProvider(logsdk.WithProcessor(processor), logsdk.WithResource(resAudit))
|
||||
global.SetLoggerProvider(logProvider)
|
||||
}
|
||||
|
||||
return &telemetry.Provider{
|
||||
MeterProvider: meterProvider,
|
||||
MetricsHandler: metricsHandler,
|
||||
MeterProvider: meterProvider,
|
||||
TraceProvider: traceProvider,
|
||||
LogProvider: logProvider,
|
||||
Shutdown: func(shutdownCtx context.Context) error {
|
||||
log.Infof(ctx, "Shutting down metrics server...")
|
||||
// Shutdown the metrics server
|
||||
serverShutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second)
|
||||
defer cancel()
|
||||
if err := metricsServer.Shutdown(serverShutdownCtx); err != nil {
|
||||
log.Errorf(ctx, fmt.Errorf("metrics server shutdown: %w", err), "error shutting down metrics server")
|
||||
|
||||
var errs []error
|
||||
if traceProvider != nil {
|
||||
if err := traceProvider.Shutdown(shutdownCtx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("tracer shutdown: %w", err))
|
||||
}
|
||||
}
|
||||
serverWg.Wait()
|
||||
// Shutdown the meter provider
|
||||
return meterProvider.Shutdown(shutdownCtx)
|
||||
if meterProvider != nil {
|
||||
if err := meterProvider.Shutdown(shutdownCtx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("meter shutdown: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if logProvider != nil {
|
||||
if err := logProvider.Shutdown(shutdownCtx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("logs shutdown: %w", err))
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("shutdown errors: %v", errs)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildAtts(base []attribute.KeyValue, eid string) []attribute.KeyValue {
|
||||
atts := make([]attribute.KeyValue, 0, len(base)+1)
|
||||
atts = append(atts, base...)
|
||||
atts = append(atts, attribute.String("eid", eid))
|
||||
return atts
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user