1package telemetry
2
3import (
4 "go.opentelemetry.io/otel"
5 "go.opentelemetry.io/otel/metric"
6)
7
8// Metrics holds Gordon-specific OTel metrics instruments.
9type Metrics struct {
10 // Deployments
11 DeployTotal metric.Int64Counter
12 DeployDuration metric.Float64Histogram
13 DeployErrors metric.Int64Counter
14
15 // Container lifecycle
16 ContainerRestarts metric.Int64Counter
17 ContainerCrashLoops metric.Int64Counter
18 ManagedContainers metric.Int64UpDownCounter
19
20 // Registry
21 ImagePushTotal metric.Int64Counter
22 ImagePushSize metric.Int64Counter // bytes
23
24 // Events
25 EventsProcessed metric.Int64Counter
26 EventsDropped metric.Int64Counter
27}
28
29// NewMetrics creates and registers all Gordon metric instruments.
30// Returns a noop-safe Metrics struct — all fields are always initialized
31// (OTel returns noop instruments when no MeterProvider is set).
32func NewMetrics() (*Metrics, error) {
33 meter := otel.Meter("gordon")
34 m := &Metrics{}
35 var err error
36
37 if m.DeployTotal, err = meter.Int64Counter("gordon.deploy.total",
38 metric.WithDescription("Total number of deployments")); err != nil {
39 return nil, err
40 }
41 if m.DeployDuration, err = meter.Float64Histogram("gordon.deploy.duration_seconds",
42 metric.WithDescription("Deploy duration in seconds"),
43 metric.WithUnit("s"),
44 metric.WithExplicitBucketBoundaries(1, 5, 10, 30, 60, 120, 300)); err != nil {
45 return nil, err
46 }
47 if m.DeployErrors, err = meter.Int64Counter("gordon.deploy.errors",
48 metric.WithDescription("Total deploy errors")); err != nil {
49 return nil, err
50 }
51 if m.ContainerRestarts, err = meter.Int64Counter("gordon.container.restarts",
52 metric.WithDescription("Total container restarts")); err != nil {
53 return nil, err
54 }
55 if m.ContainerCrashLoops, err = meter.Int64Counter("gordon.container.crash_loops",
56 metric.WithDescription("Total crash loop detections")); err != nil {
57 return nil, err
58 }
59 if m.ManagedContainers, err = meter.Int64UpDownCounter("gordon.container.managed",
60 metric.WithDescription("Currently managed containers")); err != nil {
61 return nil, err
62 }
63 if m.ImagePushTotal, err = meter.Int64Counter("gordon.registry.push.total",
64 metric.WithDescription("Total image pushes")); err != nil {
65 return nil, err
66 }
67 if m.ImagePushSize, err = meter.Int64Counter("gordon.registry.push.bytes",
68 metric.WithDescription("Total bytes pushed to registry"),
69 metric.WithUnit("By")); err != nil {
70 return nil, err
71 }
72 if m.EventsProcessed, err = meter.Int64Counter("gordon.events.processed",
73 metric.WithDescription("Total events processed")); err != nil {
74 return nil, err
75 }
76 if m.EventsDropped, err = meter.Int64Counter("gordon.events.dropped",
77 metric.WithDescription("Total events dropped")); err != nil {
78 return nil, err
79 }
80
81 return m, nil
82}