fn init_metrics()

in src/lib.rs [227:339]


fn init_metrics(config: Config) -> (Option<PrometheusRegistry>, SdkMeterProvider) {
    let mut keys = vec![KeyValue::new(SERVICE_NAME_KEY, config.service_name.clone())];
    if let Some(resource_attributes) = config.resource_attributes {
        for attribute in resource_attributes {
            keys.push(KeyValue::new(attribute.key, attribute.value));
        }
    }
    let mut meter_provider_builder = SdkMeterProvider::builder().with_resource(Resource::new(keys));

    // Setup Prometheus Registry if configured
    let prometheus_registry = if let Some(prometheus_config) = config.prometheus_config {
        let registry = prometheus::Registry::new();
        match opentelemetry_prometheus::exporter()
            .with_registry(registry.clone())
            .build()
        {
            Ok(exporter) => {
                meter_provider_builder = meter_provider_builder.with_reader(exporter);
                Some(PrometheusRegistry {
                    registry,
                    port: prometheus_config.port,
                })
            }
            Err(e) => {
                error!("unable to setup prometheus endpoint due to: {:?}", e);
                None
            }
        }
    } else {
        None
    };

    // Add Metrics Exporters
    if let Some(export_targets_list) = config.metrics_export_targets {
        for export_target in export_targets_list {
            let export_config = ExportConfig {
                endpoint: export_target.url.clone(),
                timeout: Duration::from_secs(export_target.timeout),
                protocol: Protocol::Grpc,
            };

            let temporality_selector: Box<dyn TemporalitySelector> =
                if let Some(temporality) = export_target.temporality {
                    match temporality {
                        Temporality::Delta => Box::new(DeltaTemporalitySelector::new()),
                        _ => Box::new(DefaultTemporalitySelector::new()),
                    }
                } else {
                    Box::new(DefaultTemporalitySelector::new())
                };

            let mut exporter_builder = opentelemetry_otlp::new_exporter().tonic();
            if let Some(bearer_token_provider_fn) = export_target.bearer_token_provider_fn {
                let auth_interceptor = AuthIntercepter {
                    bearer_token_provider_fn,
                };
                exporter_builder = exporter_builder.with_interceptor(auth_interceptor);
            }
            exporter_builder = match handle_tls(
                exporter_builder,
                &export_target.url,
                export_target.ca_cert_path,
                Duration::from_secs(export_target.timeout),
            ) {
                Ok(exporter_builder) => exporter_builder,
                Err(_) => {
                    continue;
                }
            };

            let exporter = match exporter_builder
                .with_export_config(export_config)
                .build_metrics_exporter(
                    // TODO: Make this also part of config?
                    Box::new(DefaultAggregationSelector::new()),
                    temporality_selector,
                ) {
                Ok(exporter) => exporter,
                Err(e) => {
                    error!(
                        "unable to set export to {} due to {:?}",
                        export_target.url, e
                    );
                    continue;
                }
            };

            let reader = PeriodicReader::builder(exporter, runtime::Tokio)
                .with_interval(Duration::from_secs(export_target.interval_secs))
                .build();
            meter_provider_builder = meter_provider_builder.with_reader(reader);
        }
    }

    if config.emit_metrics_to_stdout {
        let exporter = MetricsExporterBuilder::default()
            .with_encoder(|writer, data| {
                if let Err(e) = serde_json::to_writer_pretty(writer, &data) {
                    error!("writing metrics to log failed due to: {:?}", e);
                }
                Ok(())
            })
            .build();

        let reader = PeriodicReader::builder(exporter, runtime::Tokio).build();
        meter_provider_builder = meter_provider_builder.with_reader(reader);
    }

    let meter_provider = meter_provider_builder.build();
    global::set_meter_provider(meter_provider.clone());

    (prometheus_registry, meter_provider)
}