rskit_observability/
context.rs1use std::sync::Arc;
4use std::time::Instant;
5
6use tracing::Span;
7
8use crate::metrics::MetricsHandle;
9use crate::tracer::set_operation_attributes;
10
11pub struct OperationContext {
15 service_name: String,
16 operation_name: String,
17 request_id: String,
18 user_id: String,
19 start_time: Instant,
20 metrics: Option<Arc<MetricsHandle>>,
21}
22
23impl OperationContext {
24 pub fn new(
26 service: impl Into<String>,
27 operation: impl Into<String>,
28 request_id: impl Into<String>,
29 user_id: impl Into<String>,
30 ) -> Self {
31 Self {
32 service_name: service.into(),
33 operation_name: operation.into(),
34 request_id: request_id.into(),
35 user_id: user_id.into(),
36 start_time: Instant::now(),
37 metrics: None,
38 }
39 }
40
41 #[must_use]
43 pub fn with_metrics(mut self, metrics: Arc<MetricsHandle>) -> Self {
44 self.metrics = Some(metrics);
45 self
46 }
47
48 #[must_use]
50 pub fn service_name(&self) -> &str {
51 &self.service_name
52 }
53
54 #[must_use]
56 pub fn operation_name(&self) -> &str {
57 &self.operation_name
58 }
59
60 #[must_use]
62 pub fn request_id(&self) -> &str {
63 &self.request_id
64 }
65
66 #[must_use]
71 pub fn user_id(&self) -> &str {
72 &self.user_id
73 }
74
75 pub fn start_span(&self, name: &str) -> Span {
77 let span = tracing::info_span!("operation", otel.name = name);
78 set_operation_attributes(
79 &span,
80 &self.service_name,
81 &self.operation_name,
82 &self.request_id,
83 );
84 span
85 }
86
87 pub fn end_operation(&self, status: &str, error: Option<&rskit_errors::AppError>) {
89 let duration = self.elapsed();
90 tracing::info!(
91 service = %self.service_name,
92 operation = %self.operation_name,
93 request_id = %self.request_id,
94 status = status,
95 duration_ms = duration.as_millis() as u64,
96 error = error.map(|e| e.to_string()).as_deref(),
97 "operation completed"
98 );
99 }
100
101 pub fn elapsed(&self) -> std::time::Duration {
103 self.start_time.elapsed()
104 }
105}