-
Notifications
You must be signed in to change notification settings - Fork 0
/
metrics.go
81 lines (71 loc) · 2.81 KB
/
metrics.go
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
package observability
import (
"context"
"time"
"github.com/pkg/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.opentelemetry.io/otel/sdk/metric/view"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
"google.golang.org/grpc"
)
const (
defaultReaderTimeout = 5 * time.Second
)
type MeterConfig struct {
CollectPeriod time.Duration
ServiceName string
ServiceNamespace string
ServiceVersion string
}
// OtelMeter takes a grpc connection to an otel collector, a collectPeriod time.Duration (more than a second), and
// sets the meter collector up and assigns it to a global meter. If the function returns nil, assume that the global
// meter is now set and ready to be used.
//
// This function merely sets up the scaffolding to ship collected metered data to the opentelemetry collector. It does
// not set up the specific meters for the applications.
func OtelMeter(ctx context.Context, conn *grpc.ClientConn, meterConfig MeterConfig) (error, func(context.Context) error) {
if meterConfig.CollectPeriod < time.Second {
return errors.New("collect period is shorter than a second, please choose a longer period to avoid" +
" overloading the collector"), nil
}
// exporter is the thing that will send the data from the app to wherever else it needs to go.
exporter, err := otlpmetricgrpc.New(
ctx,
otlpmetricgrpc.WithGRPCConn(conn),
)
if err != nil {
return errors.Wrap(err, "otlpmetricgrpc.New"), nil
}
// periodicReader is the thing that collects the data every cycle, and then uses the exporter above to send it
// someplace.
periodicReader := metric.NewPeriodicReader(exporter,
metric.WithTimeout(defaultReaderTimeout),
metric.WithInterval(meterConfig.CollectPeriod),
metric.WithTemporalitySelector(func(view.InstrumentKind) metricdata.Temporality {
return metricdata.DeltaTemporality
}),
)
// resource configures the very basic attributes of every measurement taken.
r := resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(meterConfig.ServiceName),
semconv.TelemetrySDKLanguageGo,
semconv.ServiceNamespaceKey.String(meterConfig.ServiceNamespace),
semconv.ServiceVersionKey.String(meterConfig.ServiceVersion),
semconv.DBSystemPostgreSQL,
attribute.String("exporter", "grpc"),
)
// meterProvider takes the resource, and the reader, to provide a thing that we can create actual instruments out
// of, so we can start measuring things.
meterProvider := metric.NewMeterProvider(
metric.WithResource(r),
metric.WithReader(periodicReader),
)
global.SetMeterProvider(meterProvider)
return nil, meterProvider.Shutdown
}