use std::time::Duration;
use tokio::sync::mpsc::error::TrySendError;
use crate::plugins::response_cache::ErrorCode;
use crate::plugins::response_cache::invalidation::InvalidationKind;
use crate::plugins::response_cache::storage;
pub(crate) const CACHE_INFO_SUBGRAPH_CONTEXT_KEY: &str =
"apollo::router::response_cache::cache_info_subgraph";
pub(crate) struct CacheMetricContextKey(String);
impl CacheMetricContextKey {
pub(crate) fn new(subgraph_name: String) -> Self {
Self(subgraph_name)
}
}
impl From<CacheMetricContextKey> for String {
fn from(val: CacheMetricContextKey) -> Self {
format!("{CACHE_INFO_SUBGRAPH_CONTEXT_KEY}_{}", val.0)
}
}
pub(super) fn record_fetch_error(error: &storage::Error, subgraph_name: &str) {
if error.is_row_not_found() {
return;
}
u64_counter_with_unit!(
"apollo.router.operations.response_cache.fetch.error",
"Errors when fetching data from cache",
"{error}",
1,
"subgraph.name" = subgraph_name.to_string(),
"code" = error.code()
);
tracing::debug!(error = %error, "unable to fetch data from response cache");
}
pub(super) fn record_fetch_duration(duration: Duration, subgraph_name: &str, batch_size: usize) {
f64_histogram_with_unit!(
"apollo.router.operations.response_cache.fetch",
"Time to fetch data from cache",
"s",
duration.as_secs_f64(),
"subgraph.name" = subgraph_name.to_string(),
"batch.size" = batch_size_str(batch_size)
);
}
pub(super) fn record_insert_error(error: &storage::Error, subgraph_name: &str) {
u64_counter_with_unit!(
"apollo.router.operations.response_cache.insert.error",
"Errors when inserting data in cache",
"{error}",
1,
"subgraph.name" = subgraph_name.to_string(),
"code" = error.code()
);
tracing::debug!(error = %error, "unable to insert data in response cache");
}
pub(super) fn record_insert_duration(duration: Duration, subgraph_name: &str, batch_size: usize) {
f64_histogram_with_unit!(
"apollo.router.operations.response_cache.insert",
"Time to insert new data in cache",
"s",
duration.as_secs_f64(),
"subgraph.name" = subgraph_name.to_string(),
"batch.size" = batch_size_str(batch_size)
);
}
pub(super) fn record_maintenance_success(entries: u64) {
u64_counter_with_unit!(
"apollo.router.operations.response_cache.maintenance.removed_cache_tag_entries",
"Counter for removed items",
"{entry}",
entries
);
}
pub(super) fn record_maintenance_error(error: &storage::Error) {
u64_counter_with_unit!(
"apollo.router.operations.response_cache.maintenance.error",
"Errors while removing expired entries from cache tag set",
"{error}",
1,
"code" = error.code()
);
tracing::debug!(error = %error, "unable to perform maintenance on cache tag set in response cache");
}
pub(super) fn record_maintenance_duration(duration: Duration) {
f64_histogram_with_unit!(
"apollo.router.operations.response_cache.maintenance",
"Time to remove expired entries from cache tag set",
"s",
duration.as_secs_f64()
);
}
pub(super) fn record_maintenance_queue_error<T>(error: &TrySendError<T>) {
let kind = match error {
TrySendError::Closed(_) => "channel closed",
TrySendError::Full(_) => "channel full",
};
u64_counter_with_unit!(
"apollo.router.operations.response_cache.maintenance.queue.error",
"Error while sending cache tag to maintenance queue",
"{error}",
1,
"error" = kind
);
}
pub(super) fn record_invalidation_duration(
duration: Duration,
invalidation_kind: InvalidationKind,
) {
f64_histogram_with_unit!(
"apollo.router.operations.response_cache.invalidation",
"Time to invalidate data in cache",
"s",
duration.as_secs_f64(),
"kind" = invalidation_kind
);
}
fn batch_size_str(batch_size: usize) -> &'static str {
if batch_size == 0 {
"0"
} else if batch_size <= 10 {
"1-10"
} else if batch_size <= 20 {
"11-20"
} else if batch_size <= 50 {
"21-50"
} else {
"51+"
}
}