1#![deny(
2 explicit_outlives_requirements,
3 macro_use_extern_crate,
4 missing_debug_implementations,
5 trivial_casts,
6 trivial_numeric_casts,
7 unreachable_pub,
8 unsafe_code,
9 unused_qualifications,
10 unused_results,
11 variant_size_differences,
12 unused_variables,
13 clippy::complexity,
14 clippy::nursery,
15 clippy::pedantic,
16 clippy::perf,
17 clippy::style,
18 clippy::suspicious,
19 clippy::clone_on_ref_ptr,
20 clippy::create_dir,
21 clippy::dbg_macro,
22 clippy::default_numeric_fallback,
23 clippy::else_if_without_else,
24 clippy::empty_structs_with_brackets,
25 clippy::expect_used,
26 clippy::get_unwrap,
27 clippy::let_underscore_must_use,
28 clippy::map_err_ignore,
29 clippy::multiple_inherent_impl,
30 clippy::panic,
31 clippy::panic_in_result_fn,
32 clippy::pub_use,
33 clippy::rc_mutex,
34 clippy::rest_pat_in_fully_bound_structs,
35 clippy::same_name_method,
36 clippy::self_named_module_files,
37 clippy::shadow_reuse,
38 clippy::shadow_same,
39 clippy::shadow_unrelated,
40 clippy::unseparated_literal_suffix,
41 clippy::string_to_string,
42 clippy::todo,
43 clippy::unimplemented,
44 clippy::unreachable,
45 clippy::unwrap_in_result,
46 clippy::unwrap_used,
47 clippy::use_debug,
48 clippy::verbose_file_reads,
49 clippy::wildcard_enum_match_arm
50)]
51
52pub mod tracing {
53 use eyre::{eyre, Result};
54 use tracing_subscriber::EnvFilter;
55
56 pub fn init() -> Result<()> {
63 tracing_subscriber::fmt()
64 .with_env_filter(EnvFilter::from_default_env())
65 .try_init()
66 .map_err(|error| eyre!("failed to initialize subscriber: {}", error))
67 }
68}
69
70pub mod otlp_tracing {
71 use eyre::Result;
74 use opentelemetry::KeyValue;
75 use opentelemetry_otlp::WithExportConfig;
76 use opentelemetry_sdk::{
77 runtime,
78 trace::{BatchConfig, RandomIdGenerator, Sampler},
79 Resource,
80 };
81 use opentelemetry_semantic_conventions::{
82 resource::{SERVICE_NAME, SERVICE_VERSION},
83 SCHEMA_URL,
84 };
85 use serde::Deserialize;
86 use tracing::instrument;
87 use tracing_opentelemetry::OpenTelemetryLayer;
88 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
89
90 pub const DEFAULT_OTLP_GRPC_ENDPOINT: &str = "http://localhost:4317";
91
92 #[derive(Clone, Debug, Deserialize)]
93 #[serde(default)]
94 pub struct Configuration {
95 pub otlp_grpc_endpoint: String,
96 }
97
98 pub fn try_init(service_name: &'static str) -> Result<()> {
106 let configuration = Configuration::from_env()?;
107 tracing_subscriber::registry()
108 .with(EnvFilter::from_default_env())
109 .with(tracing_subscriber::fmt::layer())
110 .with(OpenTelemetryLayer::new(
111 opentelemetry_otlp::new_pipeline()
112 .tracing()
113 .with_trace_config(
114 opentelemetry_sdk::trace::Config::default()
115 .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(1.0))))
116 .with_id_generator(RandomIdGenerator::default())
117 .with_resource(Resource::from_schema_url(
118 [
119 KeyValue::new(SERVICE_NAME, service_name),
120 KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
121 ],
122 SCHEMA_URL,
123 )),
124 )
125 .with_batch_config(BatchConfig::default())
126 .with_exporter(
127 opentelemetry_otlp::new_exporter()
128 .tonic()
129 .with_endpoint(configuration.otlp_grpc_endpoint),
130 )
131 .install_batch(runtime::Tokio)?,
132 ))
133 .try_init()?;
134 Ok(())
135 }
136
137 impl Configuration {
138 #[instrument(err(Debug), ret, level = "trace")]
139 pub fn from_env() -> Result<Self> {
140 Ok(envy::prefixed("OBSERVABILITY_").from_env::<Self>()?)
141 }
142 }
143
144 impl Default for Configuration {
145 fn default() -> Self {
146 Self {
147 otlp_grpc_endpoint: DEFAULT_OTLP_GRPC_ENDPOINT.to_string(),
148 }
149 }
150 }
151}