8e4d66a998
add GetVersionTimestamp * add GetVersionTimestamp * docs
152 lines
3.3 KiB
Go
152 lines
3.3 KiB
Go
package observability
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"sync"
|
|
"time"
|
|
|
|
"runtime/debug"
|
|
|
|
"queryorchestration/internal/serviceconfig/observability/prometheus"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
)
|
|
|
|
const (
|
|
SystemName = "doczy"
|
|
)
|
|
|
|
var startupTime time.Time
|
|
var startupTimeOnce sync.Once
|
|
|
|
func GetVersionTimestamp() time.Time {
|
|
startupTimeOnce.Do(func() {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
startupTime = time.Now()
|
|
return
|
|
}
|
|
|
|
// Look for vcs.time in build settings
|
|
for _, setting := range info.Settings {
|
|
if setting.Key == "vcs.time" {
|
|
// Parse the build timestamp
|
|
buildTime, err := time.Parse(time.RFC3339, setting.Value)
|
|
if err == nil {
|
|
startupTime = buildTime
|
|
return
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
// Return current time if no build time found
|
|
startupTime = time.Now()
|
|
})
|
|
|
|
return startupTime
|
|
}
|
|
|
|
// GetVersion returns the version of the application in the Golang build info format.
|
|
// This is a raw format and will change depending on the build environment and the git tags.
|
|
// When building from a commit with an associated Git tag (e.g., v1.2.3),
|
|
//
|
|
// the runtime version uses the tag name without a timestamp.
|
|
//
|
|
// The "+dirty" suffix is appended when there are uncommitted changes
|
|
//
|
|
// present in the version control system (VCS) at the time of building.
|
|
//
|
|
// An example of a version v0.0.2-0.20250310175756-a91372dc0602+dirty.
|
|
func GetVersion() string {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
return "unknown"
|
|
}
|
|
return info.Main.Version
|
|
}
|
|
|
|
type ConfigProvider interface {
|
|
IsOtelEnabled() bool
|
|
SetOtel(context.Context) func() error
|
|
GetMetrics() *prometheus.Metrics
|
|
SetMetrics(metrics *prometheus.Metrics)
|
|
}
|
|
|
|
type ObsConfig struct {
|
|
EnableOtel bool `env:"ENABLE_OTEL" envDefault:"false"`
|
|
metrics *prometheus.Metrics
|
|
}
|
|
|
|
func (o *ObsConfig) GetMetrics() *prometheus.Metrics {
|
|
return o.metrics
|
|
}
|
|
|
|
func (o *ObsConfig) SetMetrics(metrics *prometheus.Metrics) {
|
|
o.metrics = metrics
|
|
}
|
|
|
|
func (o *ObsConfig) IsOtelEnabled() bool {
|
|
return o.EnableOtel
|
|
}
|
|
|
|
func (o *ObsConfig) SetOtel(ctx context.Context) func() error {
|
|
if !o.EnableOtel {
|
|
slog.Warn("OpenTelemetry is disabled. Set ENABLE_OTEL to true to enable.")
|
|
return func() error { return nil }
|
|
}
|
|
|
|
exporter, err := otlptracegrpc.New(ctx)
|
|
if err != nil {
|
|
return func() error { return nil }
|
|
}
|
|
|
|
tp := sdktrace.NewTracerProvider(
|
|
sdktrace.WithBatcher(exporter),
|
|
)
|
|
|
|
otel.SetTracerProvider(tp)
|
|
|
|
return func() error {
|
|
err := tp.Shutdown(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
const (
|
|
SubSystem = "RunnerService"
|
|
)
|
|
|
|
func InitializeMetrics(ctx context.Context, cfg ConfigProvider) error {
|
|
standardDefinitions := prometheus.NewStandardMetricDefinitions()
|
|
config := prometheus.MetricsConfig{
|
|
Port: 8080,
|
|
Namespace: SystemName,
|
|
Subsystem: SubSystem,
|
|
ServeHttp: true,
|
|
Definitions: standardDefinitions,
|
|
}
|
|
|
|
metrics, err := prometheus.New(ctx, config)
|
|
if err != nil {
|
|
slog.Error("Failed to create metrics object", "error", err)
|
|
return err
|
|
}
|
|
slog.Info("Metrics server started on port 8080")
|
|
cfg.SetMetrics(metrics)
|
|
|
|
err = cfg.GetMetrics().RecordLifecycleEvent(1.0, "startup", "main")
|
|
if err != nil {
|
|
slog.Error("Failed to create metrics at startup", "error", err)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|