rocketmq_observability/
lib.rs1mod attributes;
16mod config;
17mod environment;
18mod error;
19mod exporter;
20mod exporter_types;
21mod handle;
22mod init;
23mod log_filter;
24mod logging;
25pub mod logs;
26pub mod metrics;
27mod noop;
28mod propagation;
29mod resolver;
30mod resource;
31mod runtime_diagnostics;
32mod sampling;
33pub mod semantic;
34pub mod statistics;
35pub mod stats;
36mod status;
37pub mod trace;
38
39pub use attributes::base_attributes;
40pub use attributes::Attribute;
41pub use attributes::MetricAttributes;
42pub use config::ConsoleLogConfig;
43pub use config::FileLogConfig;
44pub use config::LogFormat;
45pub use config::LogRotation;
46pub use config::LoggingConfig;
47pub use config::LogsExporter;
48pub use config::LogsOverrides;
49pub use config::MetricsExporter;
50pub use config::MetricsOverrides;
51pub use config::NonBlockingLogConfig;
52pub use config::ObservabilityConfig;
53pub use config::ObservabilityOverrides;
54pub use config::OtlpOverrides;
55pub use config::OtlpProtocol;
56pub use config::PrometheusOverrides;
57pub use config::ReloadConfig;
58pub use config::SubscriberInstallPolicy;
59pub use config::SubscriberInstallStatus;
60pub use config::TelemetryBootstrapConfig;
61pub use config::TraceExporter;
62pub use config::TracesConfig;
63pub use config::TracesOverrides;
64pub use environment::apply_standard_otlp_environment;
65pub use environment::apply_standard_otlp_environment_values;
66pub use environment::StandardOtlpEnvironmentStatus;
67pub use environment::OTEL_EXPORTER_OTLP_ENDPOINT;
68pub use environment::OTEL_EXPORTER_OTLP_PROTOCOL;
69pub use error::ObservabilityError;
70pub use error::ObservabilityFailureDetail;
71pub use error::ObservabilityOperation;
72pub use error::ObservabilityResult;
73pub use exporter::outage::*;
74pub use exporter_types::LogExporterType;
75pub use exporter_types::MetricsExporterType;
76pub use exporter_types::TraceExporterType;
77pub use handle::MetricsRuntimePolicy;
78#[cfg(feature = "otel-metrics")]
79pub use handle::ReleaseIdentityRegistrationError;
80pub use handle::TelemetryHandle;
81pub use handle::TelemetryRecorder;
82pub use handle::TelemetryState;
83pub use handle::TracePolicy;
84pub use handle::BROKER_METER_SCOPE;
85pub use handle::CLIENT_METER_SCOPE;
86pub use handle::CONTROLLER_METER_SCOPE;
87pub use handle::DASHBOARD_METER_SCOPE;
88pub use handle::MCP_METER_SCOPE;
89pub use handle::NAMESRV_METER_SCOPE;
90pub use handle::PROXY_METER_SCOPE;
91pub use handle::RUNTIME_METER_SCOPE;
92pub use handle::SRE_CONNECTOR_METER_SCOPE;
93pub use handle::SRE_CONTROL_PLANE_METER_SCOPE;
94pub use handle::STORE_METER_SCOPE;
95pub use handle::TIERED_STORE_METER_SCOPE;
96pub use handle::TRANSPORT_METER_SCOPE;
97pub use init::init_observability;
98pub use init::init_observability_with_service_context;
99pub use log_filter::read_rust_log;
100pub use log_filter::LogFilterHandle;
101pub use log_filter::LogFilterInputs;
102pub use log_filter::LogFilterReloadRequest;
103pub use log_filter::LogFilterResolver;
104pub use log_filter::LogFilterSource;
105pub use log_filter::LoggingOverrideConfig;
106pub use log_filter::LoggingOverrides;
107pub use log_filter::ResolvedLogFilter;
108pub use log_filter::DEFAULT_LOG_FILTER;
109pub use logging::install_global;
110pub use logging::install_global_with_filter;
111pub use logging::install_global_with_filter_and_service_context;
112pub use logging::install_global_with_service_context;
113pub use logging::reserve_telemetry_flush_lease;
114pub use logging::FileLogLayer;
115pub use logging::LoggingGuard;
116pub use logging::TelemetryRuntimeGuard;
117pub use logging::TelemetryShutdownReport;
118pub use metrics::dashboard::DashboardStorageBackend;
119pub use metrics::dashboard::DashboardStorageFailureLabel;
120pub use metrics::dashboard::DashboardStorageMetricsRecorder;
121pub use metrics::dashboard::DashboardStorageOperation;
122pub use metrics::dashboard::DashboardStorageOperationResult;
123pub use metrics::dashboard::DashboardStorageResult;
124pub use metrics::labels::MetricLabelPolicy;
125pub use metrics::labels::METRIC_LABEL_SENTINEL;
126#[cfg(feature = "otel-traces")]
127pub use propagation::add_current_span_event_with_status;
128#[cfg(feature = "otel-traces")]
129#[doc(hidden)]
130pub use propagation::bench_extract_trace_context;
131#[cfg(feature = "otel-traces")]
132pub use propagation::inject_current_context_with_handle;
133#[cfg(feature = "otel-traces")]
134pub use propagation::record_span_parent_assignment_error;
135#[cfg(feature = "otel-traces")]
136pub use propagation::set_span_parent_from_properties_with_handle;
137#[cfg(feature = "otel-traces")]
138pub use propagation::SpanParentError;
139pub use propagation::TRACEPARENT;
140pub use propagation::TRACESTATE;
141pub use resolver::normalize_and_validate;
142pub use resolver::resolve_telemetry_from_env;
143pub use resolver::resolve_telemetry_values;
144pub use resolver::TelemetryEnvironmentSpec;
145pub use resolver::TelemetryEnvironmentValues;
146pub use resolver::TelemetryResolution;
147pub use runtime_diagnostics::start_runtime_diagnostics_endpoint;
148pub use runtime_diagnostics::start_runtime_diagnostics_endpoint_from_env;
149pub use runtime_diagnostics::start_runtime_diagnostics_endpoint_from_env_with_telemetry;
150pub use runtime_diagnostics::RuntimeDiagnosticsEndpointConfig;
151pub use runtime_diagnostics::RuntimeDiagnosticsEndpointHandle;
152pub use runtime_diagnostics::RuntimeDiagnosticsSources;
153pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_ALLOW_INSECURE_HTTP_ENV;
154pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_BIND_ADDR_ENV;
155pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_ENDPOINT_SCHEMA;
156pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_PATH;
157pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_SAMPLE_INTERVAL_SECONDS_ENV;
158pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_SCOPE;
159pub use runtime_diagnostics::RUNTIME_DIAGNOSTICS_TOKEN_FILE_ENV;
160pub use runtime_diagnostics::RUNTIME_METADATA_TARGETS_PATH;
161pub use runtime_diagnostics::{
162 RuntimeDiagnosticsDataProvider, RuntimeDiagnosticsMode, RuntimeDiagnosticsService, RuntimeDiagnosticsStarted,
163 RUNTIME_DIAGNOSTICS_MODE_ENV,
164};
165pub use sampling::SamplingGate;
166pub use status::ObservabilityCompiledFeaturesV1;
167pub use status::ObservabilitySignalStatusV1;
168pub use status::ObservabilityStatusHandle;
169pub use status::ObservabilityStatusValueV1;
170pub use status::ObservabilityStatusViewV1;
171pub use status::ObservabilitySubscriberStatusV1;
172
173#[cfg(feature = "prometheus")]
174#[doc(hidden)]
175pub mod bench_support {
176 use std::time::Duration;
177 use std::time::Instant;
178
179 use opentelemetry::metrics::MeterProvider;
180 use rocketmq_runtime::ChildServiceContext;
181 use rocketmq_runtime::ShutdownReport;
182 use serde::Serialize;
183 use tokio::io::AsyncReadExt;
184 use tokio::io::AsyncWriteExt;
185 use tokio::net::TcpStream;
186
187 use crate::config::MetricsExporter;
188 use crate::config::ObservabilityConfig;
189
190 #[derive(Clone, Debug, Serialize)]
191 pub struct PrometheusLifecycleProbe {
192 pub task_count_before_scrape: usize,
193 pub task_count_before_shutdown: usize,
194 pub response_status_ok: bool,
195 pub response_contains_metric: bool,
196 pub response_bytes: usize,
197 pub shutdown_elapsed_us: u128,
198 pub shutdown_report: ShutdownReport,
199 pub healthy: bool,
200 }
201
202 pub async fn run_prometheus_lifecycle_probe(service_context: ChildServiceContext) -> PrometheusLifecycleProbe {
203 let mut config = ObservabilityConfig {
204 enabled: true,
205 ..ObservabilityConfig::default()
206 };
207 config.metrics.enabled = true;
208 config.metrics.exporter = MetricsExporter::Prometheus;
209 config.prometheus.host = "127.0.0.1".to_string();
210 config.prometheus.port = 0;
211 config.prometheus.path = "/metrics".to_string();
212
213 let prometheus = crate::exporter::prometheus::init_prometheus_metrics(&config)
214 .expect("prometheus metrics should initialize");
215 let meter = prometheus.provider().meter("observability-lifecycle-bench");
216 let counter = meter.u64_counter("rocketmq_observability_lifecycle_total").build();
217 counter.add(1, &[]);
218
219 let handle = crate::exporter::prometheus::spawn_prometheus_http_endpoint(
220 &config,
221 prometheus.registry().clone(),
222 &service_context,
223 )
224 .expect("prometheus HTTP endpoint should start");
225 let task_count_before_scrape = handle.task_count();
226
227 let response = scrape_metrics(handle.local_addr(), config.prometheus.path.as_str()).await;
228 let response_status_ok = response.starts_with("HTTP/1.1 200 OK");
229 let response_contains_metric = response.contains("rocketmq_observability_lifecycle_total");
230 let response_bytes = response.len();
231 let task_count_before_shutdown = handle.task_count();
232
233 let shutdown_started_at = Instant::now();
234 let shutdown_report = handle.shutdown_gracefully(Duration::from_secs(5)).await;
235 let shutdown_elapsed_us = shutdown_started_at.elapsed().as_micros();
236 let parent_report = service_context.task_group().shutdown(Duration::from_secs(1)).await;
237 let finished_accept_tasks = shutdown_report.completed + shutdown_report.cancelled;
238 let healthy = response_status_ok
239 && response_contains_metric
240 && shutdown_report.is_healthy()
241 && parent_report.is_healthy()
242 && finished_accept_tasks >= 1
243 && shutdown_report.leaked == 0
244 && shutdown_report.timed_out == 0;
245
246 PrometheusLifecycleProbe {
247 task_count_before_scrape,
248 task_count_before_shutdown,
249 response_status_ok,
250 response_contains_metric,
251 response_bytes,
252 shutdown_elapsed_us,
253 shutdown_report,
254 healthy,
255 }
256 }
257
258 async fn scrape_metrics(addr: std::net::SocketAddr, path: &str) -> String {
259 let mut stream = TcpStream::connect(addr)
260 .await
261 .expect("prometheus scrape should connect");
262 let request = format!("GET {path} HTTP/1.1\r\nHost: {addr}\r\nConnection: close\r\n\r\n");
263 stream
264 .write_all(request.as_bytes())
265 .await
266 .expect("prometheus scrape request should write");
267 let mut response = Vec::new();
268 stream
269 .read_to_end(&mut response)
270 .await
271 .expect("prometheus scrape response should read");
272 String::from_utf8(response).expect("prometheus response should be utf8")
273 }
274}
275
276#[cfg(all(test, feature = "prometheus"))]
277mod bench_support_tests {
278 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
279 async fn prometheus_lifecycle_probe_reports_clean_shutdown() {
280 let runtime = rocketmq_runtime::RuntimeContext::from_current("prometheus-lifecycle-test");
281 let probe =
282 super::bench_support::run_prometheus_lifecycle_probe(runtime.service_context("prometheus-probe")).await;
283
284 assert!(probe.healthy, "{probe:?}");
285 assert!(probe.response_status_ok, "{probe:?}");
286 assert!(
287 probe.shutdown_report.is_healthy(),
288 "{}",
289 probe.shutdown_report.to_json()
290 );
291 }
292}