File size: 6,014 Bytes
6380833
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package pgxpoolobserver

import (
	"context"

	"github.com/jackc/pgx/v5/pgxpool"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/metric"
)

// ObservePoolMetrics registers a callback that observes the metrics of the provided pgxpool.Pool.
// the implementation is based on https://github.com/cmackenzie1/pgxpool-prometheus
func ObservePoolMetrics(meter metric.Meter, pool *pgxpool.Pool, additionalAttributes ...attribute.KeyValue) error {
	allMetrics := []metric.Observable{}

	acquireCountMetric, err := meter.Int64ObservableCounter(
		"pgxpool.acquire_count",
		metric.WithDescription("The cumulative count of successful acquires from the pool."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, acquireCountMetric)

	acquiredDurationMetric, err := meter.Int64ObservableGauge(
		"pgxpool.acquire_duration",
		metric.WithDescription("The total duration of all successful acquires from the pool in ms."),
		metric.WithUnit("ms"),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, acquiredDurationMetric)

	avgAcquiredDurationMetric, err := meter.Int64ObservableGauge(
		"pgxpool.acquire_duration_avg",
		metric.WithDescription("The average duration of all successful acquires from the pool in ms."),
		metric.WithUnit("ms"),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, avgAcquiredDurationMetric)

	acquiredConnsMetric, err := meter.Int64ObservableGauge(
		"pgxpool.acquired_conns",
		metric.WithDescription("The number of currently acquired connections in the pool."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, acquiredConnsMetric)

	canceledAcquireCountMetric, err := meter.Int64ObservableCounter(
		"pgxpool.canceled_acquire_count",
		metric.WithDescription("The cumulative count of acquires from the pool that were canceled by a context."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, canceledAcquireCountMetric)

	constructingConnsMetric, err := meter.Int64ObservableGauge(
		"pgxpool.constructing_conns",
		metric.WithDescription("The number of conns with construction in progress in the pool."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, constructingConnsMetric)

	emptyAcquireCountMetric, err := meter.Int64ObservableCounter(
		"pgxpool.empty_acquire_count",
		metric.WithDescription("The cumulative count of successful acquires from the pool that waited for a resource to be released or constructed because the pool was empty."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, emptyAcquireCountMetric)

	idleConnsMetric, err := meter.Int64ObservableGauge(
		"pgxpool.idle_conns",
		metric.WithDescription("The number of currently idle conns in the pool."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, idleConnsMetric)

	maxConns, err := meter.Int64ObservableGauge(
		"pgxpool.max_conns",
		metric.WithDescription("The maximum size of the pool."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, maxConns)

	totalConns, err := meter.Int64ObservableGauge(
		"pgxpool.total_conns",
		metric.WithDescription("The total number of resources currently in the pool. The value is the sum of ConstructingConns, AcquiredConns, and IdleConns."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, totalConns)

	newConnsCount, err := meter.Int64ObservableCounter(
		"pgxpool.new_conns_count",
		metric.WithDescription("The cumulative count of new connections opened."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, newConnsCount)

	maxLifetimeDestroyCount, err := meter.Int64ObservableCounter(
		"pgxpool.max_lifetime_destroy_count",
		metric.WithDescription("The cumulative count of connections closed due to reaching their maximum lifetime (MaxConnLifetime)."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, maxLifetimeDestroyCount)

	maxIdleDestroyCount, err := meter.Int64ObservableCounter(
		"pgxpool.max_idle_destroy_count",
		metric.WithDescription("The cumulative count of connections closed due to reaching their maximum idle time (MaxConnIdleTime)."),
	)
	if err != nil {
		return err
	}
	allMetrics = append(allMetrics, maxIdleDestroyCount)

	_, err = meter.RegisterCallback(func(_ context.Context, o metric.Observer) error {
		stat := pool.Stat()

		acquireCount := stat.AcquireCount()
		acquireDurationMS := stat.AcquireDuration().Milliseconds()

		o.ObserveInt64(acquireCountMetric, acquireCount, metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(acquiredDurationMetric, acquireDurationMS, metric.WithAttributes(additionalAttributes...))

		if acquireCount > 0 {
			o.ObserveInt64(avgAcquiredDurationMetric, acquireDurationMS/acquireCount, metric.WithAttributes(additionalAttributes...))
		}
		o.ObserveInt64(acquiredConnsMetric, int64(stat.AcquiredConns()), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(canceledAcquireCountMetric, stat.CanceledAcquireCount(), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(constructingConnsMetric, int64(stat.ConstructingConns()), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(emptyAcquireCountMetric, stat.EmptyAcquireCount(), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(idleConnsMetric, int64(stat.IdleConns()), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(maxConns, int64(stat.MaxConns()), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(totalConns, int64(stat.TotalConns()), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(newConnsCount, stat.NewConnsCount(), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(maxLifetimeDestroyCount, stat.MaxLifetimeDestroyCount(), metric.WithAttributes(additionalAttributes...))
		o.ObserveInt64(maxIdleDestroyCount, stat.MaxIdleDestroyCount(), metric.WithAttributes(additionalAttributes...))

		return nil
	}, allMetrics...)
	if err != nil {
		return err
	}

	return nil
}