use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TelemetryEvent {
#[serde(rename = "type")]
pub event_type: String,
pub payload: Value,
}
impl TelemetryEvent {
#[must_use]
pub fn new(event_type: impl Into<String>, payload: Value) -> Self {
Self {
event_type: event_type.into(),
payload,
}
}
}
#[async_trait]
pub trait TelemetrySink: Send + Sync {
async fn track(&self, event: TelemetryEvent) -> crate::AuthResult<()>;
}
#[derive(Clone, Default)]
pub struct TelemetryConfig {
enabled: bool,
sink: Option<Arc<dyn TelemetrySink>>,
}
impl std::fmt::Debug for TelemetryConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TelemetryConfig")
.field("enabled", &self.enabled)
.finish_non_exhaustive()
}
}
impl TelemetryConfig {
#[must_use]
pub fn new(sink: impl TelemetrySink + 'static) -> Self {
Self {
enabled: true,
sink: Some(Arc::new(sink)),
}
}
#[must_use]
pub const fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
pub(crate) fn is_enabled(&self) -> bool {
self.enabled && self.sink.is_some()
}
pub(crate) async fn publish(&self, event: TelemetryEvent) {
if self.enabled
&& let Some(sink) = &self.sink
&& sink.track(event).await.is_err()
{
tracing::warn!("Authentication telemetry delivery failed");
}
}
}