use crate::channel::registry::EffectiveTraceConfig;
use crate::config::TraceStorageMode;
use crate::metrics;
use crate::storage::repositories::traces::TraceCompletedRow;
use super::{TracePersistenceQueue, TracePersistenceTask};
pub(crate) struct CompletedTrace<'a> {
pub(crate) mode: &'a str,
pub(crate) channel: &'a str,
pub(crate) channel_id: Option<&'a str>,
pub(crate) input_json: Option<&'a str>,
pub(crate) response_json: &'a str,
pub(crate) duration_ms: f64,
pub(crate) has_errors: bool,
pub(crate) task_trace_json: Option<&'a str>,
}
pub(crate) async fn route_store_completed(
cfg: &EffectiveTraceConfig,
trace_repo: &dyn crate::storage::repositories::traces::TraceSink,
persistence_queue: &TracePersistenceQueue,
trace: &CompletedTrace<'_>,
) {
if matches!(cfg.mode, TraceStorageMode::Sync) {
if let Err(e) = trace_repo
.store_completed(crate::storage::repositories::traces::TraceCompletedRef {
channel: trace.channel,
channel_id: trace.channel_id,
mode: trace.mode,
input_json: trace.input_json,
result_json: trace.response_json,
duration_ms: trace.duration_ms,
task_trace_json: trace.task_trace_json,
})
.await
{
tracing::warn!(error = %e, "Failed to store sync processing result");
}
} else {
let task = TracePersistenceTask::StoreCompleted(TraceCompletedRow {
channel: trace.channel.to_string(),
channel_id: trace.channel_id.map(str::to_string),
mode: trace.mode.to_string(),
input_json: trace.input_json.map(str::to_string),
result_json: trace.response_json.to_string(),
duration_ms: trace.duration_ms,
task_trace_json: trace.task_trace_json.map(str::to_string),
});
persistence_queue.submit(task).await;
}
}
pub(crate) enum TracePlan {
Persist,
Drop,
}
impl TracePlan {
pub(crate) fn decide(cfg: &EffectiveTraceConfig, has_errors: bool) -> Self {
match cfg.should_drop(has_errors, cfg.draw_sample()) {
Some(reason) => {
metrics::record_trace_dropped(reason);
Self::Drop
}
None => Self::Persist,
}
}
pub(crate) fn persists(&self) -> bool {
matches!(self, Self::Persist)
}
}