#[cfg(feature = "binary")]
use crate::repl::runner::ReplClientAdapter;
#[cfg(feature = "binary")]
use anyhow::Result;
#[cfg(feature = "binary")]
use async_trait::async_trait;
#[cfg(feature = "binary")]
use metrics::{counter, histogram};
#[cfg(feature = "binary")]
use oxur_repl::protocol::{OperationResult, Request, Response};
#[cfg(feature = "binary")]
use std::time::Instant;
#[cfg(feature = "binary")]
#[derive(Debug)]
#[allow(dead_code)] pub struct MetricsClientAdapter<C: ReplClientAdapter> {
inner: C,
request_start: Option<Instant>,
}
#[cfg(feature = "binary")]
#[allow(dead_code)] impl<C: ReplClientAdapter> MetricsClientAdapter<C> {
pub fn new(inner: C) -> Self {
Self { inner, request_start: None }
}
pub fn into_inner(self) -> C {
self.inner
}
}
#[cfg(feature = "binary")]
#[async_trait]
impl<C: ReplClientAdapter> ReplClientAdapter for MetricsClientAdapter<C> {
async fn send_eval(&mut self, request: Request) -> Result<()> {
self.request_start = Some(Instant::now());
let operation = match &request.operation {
oxur_repl::protocol::Operation::CreateSession { .. } => "create_session",
oxur_repl::protocol::Operation::Clone { .. } => "clone",
oxur_repl::protocol::Operation::Eval { .. } => "eval",
oxur_repl::protocol::Operation::Close => "close",
oxur_repl::protocol::Operation::LsSessions => "ls_sessions",
oxur_repl::protocol::Operation::LoadFile { .. } => "load_file",
oxur_repl::protocol::Operation::Interrupt => "interrupt",
oxur_repl::protocol::Operation::Describe { .. } => "describe",
oxur_repl::protocol::Operation::History { .. } => "history",
oxur_repl::protocol::Operation::ClearOutput => "clear_output",
_ => "unknown",
};
counter!("repl.client.requests_total", "operation" => operation).increment(1);
self.inner.send_eval(request).await
}
async fn recv_response(&mut self) -> Result<Response> {
let response = self.inner.recv_response().await?;
if let Some(start) = self.request_start.take() {
let latency_ms = start.elapsed().as_millis() as f64;
histogram!("repl.client.response_latency_ms").record(latency_ms);
}
let status = match &response.result {
OperationResult::Success { .. } => "success",
OperationResult::Error { .. } => "error",
OperationResult::Sessions { .. } => "success",
OperationResult::HistoryEntries { .. } => "success",
_ => "unknown",
};
counter!("repl.client.responses_total", "status" => status).increment(1);
Ok(response)
}
async fn close(&mut self) -> Result<()> {
self.inner.close().await
}
fn current_session(&self) -> &oxur_repl::protocol::SessionId {
self.inner.current_session()
}
async fn handle_special_command(&mut self, input: &str, color_enabled: bool) -> Option<String> {
self.inner.handle_special_command(input, color_enabled).await
}
}
#[cfg(test)]
#[cfg(feature = "binary")]
mod tests {
}