use opentelemetry::metrics::{Counter, Histogram, Meter, UpDownCounter};
use std::time::Duration;
#[derive(Clone)]
pub struct AwaMetrics {
pub jobs_inserted: Counter<u64>,
pub jobs_completed: Counter<u64>,
pub jobs_failed: Counter<u64>,
pub jobs_retried: Counter<u64>,
pub jobs_cancelled: Counter<u64>,
pub jobs_claimed: Counter<u64>,
pub claim_batches: Counter<u64>,
pub claim_batch_size: Histogram<u64>,
pub claim_duration_seconds: Histogram<f64>,
pub job_duration_seconds: Histogram<f64>,
pub completion_flushes: Counter<u64>,
pub completion_flush_batch_size: Histogram<u64>,
pub completion_flush_duration_seconds: Histogram<f64>,
pub promotion_batches: Counter<u64>,
pub promotion_batch_size: Histogram<u64>,
pub promotion_duration_seconds: Histogram<f64>,
pub jobs_in_flight: UpDownCounter<i64>,
pub heartbeat_batches: Counter<u64>,
pub maintenance_rescues: Counter<u64>,
pub jobs_waiting_external: Counter<u64>,
}
impl AwaMetrics {
pub fn new(meter: &Meter) -> Self {
Self {
jobs_inserted: meter
.u64_counter("awa.job.inserted")
.with_description("Number of jobs inserted")
.with_unit("{job}")
.build(),
jobs_completed: meter
.u64_counter("awa.job.completed")
.with_description("Number of jobs completed successfully")
.with_unit("{job}")
.build(),
jobs_failed: meter
.u64_counter("awa.job.failed")
.with_description("Number of jobs that failed terminally")
.with_unit("{job}")
.build(),
jobs_retried: meter
.u64_counter("awa.job.retried")
.with_description("Number of jobs marked retryable")
.with_unit("{job}")
.build(),
jobs_cancelled: meter
.u64_counter("awa.job.cancelled")
.with_description("Number of jobs cancelled")
.with_unit("{job}")
.build(),
jobs_claimed: meter
.u64_counter("awa.job.claimed")
.with_description("Number of jobs claimed for execution")
.with_unit("{job}")
.build(),
claim_batches: meter
.u64_counter("awa.dispatch.claim_batches")
.with_description("Number of dispatcher claim queries executed")
.with_unit("{batch}")
.build(),
claim_batch_size: meter
.u64_histogram("awa.dispatch.claim_batch_size")
.with_description("Dispatcher claim batch size")
.with_unit("{job}")
.build(),
claim_duration_seconds: meter
.f64_histogram("awa.dispatch.claim_duration")
.with_description("Dispatcher claim query duration")
.with_unit("s")
.build(),
job_duration_seconds: meter
.f64_histogram("awa.job.duration")
.with_description("Job execution duration")
.with_unit("s")
.build(),
completion_flushes: meter
.u64_counter("awa.completion.flushes")
.with_description("Number of completion batch flushes")
.with_unit("{batch}")
.build(),
completion_flush_batch_size: meter
.u64_histogram("awa.completion.flush_batch_size")
.with_description("Completion batch flush size")
.with_unit("{job}")
.build(),
completion_flush_duration_seconds: meter
.f64_histogram("awa.completion.flush_duration")
.with_description("Completion batch flush duration")
.with_unit("s")
.build(),
promotion_batches: meter
.u64_counter("awa.maintenance.promote_batches")
.with_description("Number of scheduled/retryable promotion batches")
.with_unit("{batch}")
.build(),
promotion_batch_size: meter
.u64_histogram("awa.maintenance.promote_batch_size")
.with_description("Promotion batch size")
.with_unit("{job}")
.build(),
promotion_duration_seconds: meter
.f64_histogram("awa.maintenance.promote_duration")
.with_description("Promotion batch duration")
.with_unit("s")
.build(),
jobs_in_flight: meter
.i64_up_down_counter("awa.job.in_flight")
.with_description("Current number of in-flight jobs")
.with_unit("{job}")
.build(),
heartbeat_batches: meter
.u64_counter("awa.heartbeat.batches")
.with_description("Number of heartbeat batch updates sent")
.with_unit("{batch}")
.build(),
maintenance_rescues: meter
.u64_counter("awa.maintenance.rescues")
.with_description("Number of jobs rescued by maintenance")
.with_unit("{job}")
.build(),
jobs_waiting_external: meter
.u64_counter("awa.job.waiting_external")
.with_description("Number of jobs parked for external callback")
.with_unit("{job}")
.build(),
}
}
pub fn from_global() -> Self {
let meter = opentelemetry::global::meter("awa");
Self::new(&meter)
}
pub fn record_job_completed(&self, kind: &str, queue: &str, duration: Duration) {
let attrs = [
opentelemetry::KeyValue::new("awa.job.kind", kind.to_string()),
opentelemetry::KeyValue::new("awa.job.queue", queue.to_string()),
];
self.jobs_completed.add(1, &attrs);
self.job_duration_seconds
.record(duration.as_secs_f64(), &attrs);
}
pub fn record_job_failed(&self, kind: &str, queue: &str, terminal: bool) {
let attrs = [
opentelemetry::KeyValue::new("awa.job.kind", kind.to_string()),
opentelemetry::KeyValue::new("awa.job.queue", queue.to_string()),
opentelemetry::KeyValue::new("awa.job.terminal", terminal),
];
self.jobs_failed.add(1, &attrs);
}
pub fn record_job_retried(&self, kind: &str, queue: &str) {
let attrs = [
opentelemetry::KeyValue::new("awa.job.kind", kind.to_string()),
opentelemetry::KeyValue::new("awa.job.queue", queue.to_string()),
];
self.jobs_retried.add(1, &attrs);
}
pub fn record_job_claimed(&self, queue: &str, batch_size: u64) {
let attrs = [opentelemetry::KeyValue::new(
"awa.job.queue",
queue.to_string(),
)];
self.jobs_claimed.add(batch_size, &attrs);
}
pub fn record_claim_batch(&self, queue: &str, batch_size: u64, duration: Duration) {
let attrs = [opentelemetry::KeyValue::new(
"awa.job.queue",
queue.to_string(),
)];
self.claim_batches.add(1, &attrs);
self.claim_batch_size.record(batch_size, &attrs);
self.claim_duration_seconds
.record(duration.as_secs_f64(), &attrs);
}
pub fn record_completion_flush(&self, shard: usize, batch_size: u64, duration: Duration) {
let attrs = [opentelemetry::KeyValue::new(
"awa.completion.shard",
shard as i64,
)];
self.completion_flushes.add(1, &attrs);
self.completion_flush_batch_size.record(batch_size, &attrs);
self.completion_flush_duration_seconds
.record(duration.as_secs_f64(), &attrs);
}
pub fn record_promotion_batch(&self, state: &str, batch_size: u64, duration: Duration) {
let attrs = [opentelemetry::KeyValue::new(
"awa.job.state",
state.to_string(),
)];
self.promotion_batches.add(1, &attrs);
self.promotion_batch_size.record(batch_size, &attrs);
self.promotion_duration_seconds
.record(duration.as_secs_f64(), &attrs);
}
pub fn record_in_flight_change(&self, queue: &str, delta: i64) {
let attrs = [opentelemetry::KeyValue::new(
"awa.job.queue",
queue.to_string(),
)];
self.jobs_in_flight.add(delta, &attrs);
}
}
impl Default for AwaMetrics {
fn default() -> Self {
Self::from_global()
}
}