1
1
use std:: time:: Duration ;
2
2
3
- use opentelemetry_sdk:: { metrics:: MeterProvider , runtime, Resource } ;
3
+ use opentelemetry:: {
4
+ global,
5
+ metrics:: { MeterProvider , Unit } ,
6
+ } ;
7
+ use opentelemetry_otlp:: WithExportConfig as _;
8
+ use opentelemetry_sdk:: {
9
+ metrics:: {
10
+ reader:: { DefaultAggregationSelector , DefaultTemporalitySelector } ,
11
+ Instrument , MeterProvider as SdkMeterProvider , PeriodicReader , Stream , View ,
12
+ } ,
13
+ runtime, Resource ,
14
+ } ;
4
15
use tracing:: { Metadata , Subscriber } ;
5
16
use tracing_opentelemetry:: MetricsLayer ;
6
17
use tracing_subscriber:: { filter:: filter_fn, layer:: Filter , registry:: LookupSpan , Layer } ;
@@ -13,23 +24,68 @@ pub fn metrics_event_filter<S: Subscriber>() -> impl Filter<S> {
13
24
filter_fn ( |metadata : & Metadata < ' _ > | metadata. target ( ) != METRICS_EVENT_TARGET )
14
25
}
15
26
16
- pub fn layer < S > ( resource : Resource ) -> impl Layer < S >
27
+ pub fn layer < S > ( endpoint : impl Into < String > , resource : Resource ) -> impl Layer < S >
17
28
where
18
29
S : Subscriber + for < ' span > LookupSpan < ' span > ,
19
30
{
20
- MetricsLayer :: new ( init_meter_provider ( resource) )
31
+ MetricsLayer :: new ( init_meter_provider ( endpoint , resource) )
21
32
}
22
33
23
- fn init_meter_provider ( resource : Resource ) -> MeterProvider {
24
- let provider = opentelemetry_otlp:: new_pipeline ( )
25
- . metrics ( runtime:: Tokio )
26
- . with_resource ( resource)
27
- . with_exporter ( opentelemetry_otlp:: new_exporter ( ) . tonic ( ) )
28
- . with_period ( Duration :: from_secs ( 60 ) )
29
- . build ( )
34
+ fn init_meter_provider ( endpoint : impl Into < String > , resource : Resource ) -> impl MeterProvider {
35
+ // Currently OtelpMetricPipeline does not provide a way to set up views.
36
+ let exporter = opentelemetry_otlp:: new_exporter ( )
37
+ . tonic ( )
38
+ . with_endpoint ( endpoint)
39
+ . build_metrics_exporter (
40
+ Box :: new ( DefaultAggregationSelector :: new ( ) ) ,
41
+ Box :: new ( DefaultTemporalitySelector :: new ( ) ) ,
42
+ )
30
43
. unwrap ( ) ;
31
44
32
- opentelemetry:: global:: set_meter_provider ( provider. clone ( ) ) ;
45
+ let reader = PeriodicReader :: builder ( exporter, runtime:: Tokio )
46
+ . with_interval ( Duration :: from_secs ( 60 ) )
47
+ . build ( ) ;
48
+
49
+ let view = view ( ) ;
50
+
51
+ let meter_provider = SdkMeterProvider :: builder ( )
52
+ . with_resource ( resource)
53
+ . with_reader ( reader)
54
+ . with_view ( view)
55
+ . build ( ) ;
56
+
57
+ global:: set_meter_provider ( meter_provider. clone ( ) ) ;
58
+
59
+ meter_provider
60
+ }
61
+
62
+ fn view ( ) -> impl View {
63
+ |instrument : & Instrument | -> Option < Stream > {
64
+ tracing:: debug!( "{instrument:?}" ) ;
33
65
34
- provider
66
+ match instrument. name . as_ref ( ) {
67
+ "graphql.duration" => Some (
68
+ Stream :: new ( )
69
+ . name ( instrument. name . clone ( ) )
70
+ . description ( "graphql response duration" )
71
+ // Currently we could not ingest metrics with Arregation::Base2ExponentialHistogram in grafanacloud
72
+ . aggregation (
73
+ opentelemetry_sdk:: metrics:: Aggregation :: ExplicitBucketHistogram {
74
+ // https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#http-server
75
+ boundaries : vec ! [
76
+ 0.005 , 0.01 , 0.025 , 0.05 , 0.075 , 0.1 , 0.25 , 0.5 , 0.75 , 1.0 , 2.5 ,
77
+ 5.0 , 7.5 , 10.0 ,
78
+ ] ,
79
+ record_min_max : false ,
80
+ } ,
81
+ )
82
+ // https://opentelemetry.io/docs/specs/semconv/general/metrics/#instrument-units
83
+ . unit ( Unit :: new ( "s" ) ) ,
84
+ ) ,
85
+ name => {
86
+ tracing:: info!( name, "There is no explicit view" ) ;
87
+ None
88
+ }
89
+ }
90
+ }
35
91
}
0 commit comments