use std::sync::Arc;
use std::time::Instant;
use tracing::Span;
use crate::metrics::MetricsHandle;
use crate::tracer::set_operation_attributes;
pub struct OperationContext {
service_name: String,
operation_name: String,
request_id: String,
user_id: String,
start_time: Instant,
metrics: Option<Arc<MetricsHandle>>,
}
impl OperationContext {
pub fn new(
service: impl Into<String>,
operation: impl Into<String>,
request_id: impl Into<String>,
user_id: impl Into<String>,
) -> Self {
Self {
service_name: service.into(),
operation_name: operation.into(),
request_id: request_id.into(),
user_id: user_id.into(),
start_time: Instant::now(),
metrics: None,
}
}
#[must_use]
pub fn with_metrics(mut self, metrics: Arc<MetricsHandle>) -> Self {
self.metrics = Some(metrics);
self
}
#[must_use]
pub fn service_name(&self) -> &str {
&self.service_name
}
#[must_use]
pub fn operation_name(&self) -> &str {
&self.operation_name
}
#[must_use]
pub fn request_id(&self) -> &str {
&self.request_id
}
#[must_use]
pub fn user_id(&self) -> &str {
&self.user_id
}
pub fn start_span(&self, name: &str) -> Span {
let span = tracing::info_span!("operation", otel.name = name);
set_operation_attributes(
&span,
&self.service_name,
&self.operation_name,
&self.request_id,
);
span
}
pub fn end_operation(&self, status: &str, error: Option<&rskit_errors::AppError>) {
let duration = self.elapsed();
tracing::info!(
service = %self.service_name,
operation = %self.operation_name,
request_id = %self.request_id,
status = status,
duration_ms = duration.as_millis() as u64,
error = error.map(|e| e.to_string()).as_deref(),
"operation completed"
);
}
pub fn elapsed(&self) -> std::time::Duration {
self.start_time.elapsed()
}
}