#![allow(clippy::module_name_repetitions)]
use crate::util;
use std::io::{Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use arraystring::{typenum::U64, ArrayString};
use csv::Writer;
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct FlushEvent {
timestamp: u128,
target_id: ArrayString<U64>,
written: usize,
success: bool,
}
impl FlushEvent {
#[must_use]
pub fn new<A: AsRef<str>>(result: &IoResult<usize>, id: A) -> Self {
let success = result.is_ok();
let written = *result.as_ref().unwrap_or(&0);
Self {
timestamp: util::nano_ts(),
target_id: ArrayString::from_str_truncate(id),
written,
success,
}
}
}
pub struct FlushLog {
pub path: PathBuf,
pub events: Vec<FlushEvent>,
}
impl FlushLog {
#[must_use]
pub fn new<A: AsRef<Path>>(event_log_path: A, capacity: usize) -> Self {
Self {
path: event_log_path.as_ref().to_path_buf(),
events: Vec::with_capacity(capacity),
}
}
pub fn write(&mut self) -> IoResult<usize> {
let mut writer = Writer::from_path(&self.path)?;
let event_count = self.events.len();
for event in self.events.drain(..) {
writer.serialize(event)?;
}
writer.flush()?;
Ok(event_count)
}
}
pub struct FlushLogger<T: Write> {
log: Option<Arc<Mutex<FlushLog>>>,
id: String,
writer: T,
}
impl<T: Write> FlushLogger<T> {
#[must_use]
pub fn new(writer: T, id: String, log: Option<Arc<Mutex<FlushLog>>>) -> Self {
Self { log, id, writer }
}
}
impl<T: Write> Write for FlushLogger<T> {
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let result = self.writer.write(buf);
if let Some(log_lock) = &self.log {
let event = FlushEvent::new(&result, &self.id);
let mut log = log_lock.lock().unwrap();
log.events.push(event);
}
result
}
fn flush(&mut self) -> IoResult<()> { self.writer.flush() }
}