pub mod circuit_breaker;
pub mod compression;
pub mod console;
#[cfg(any(
feature = "sqlite",
feature = "postgres",
feature = "mysql",
feature = "duckdb"
))]
pub mod database;
pub mod encryption;
#[cfg(any(
feature = "sqlite",
feature = "postgres",
feature = "mysql",
feature = "duckdb"
))]
pub mod entity;
pub mod file;
pub mod middleware;
#[cfg(feature = "net-sink")]
pub mod net;
#[cfg(feature = "otlp")]
pub mod otlp;
pub mod rate_limit;
pub mod registry;
pub mod ring_buffered_file;
pub mod rotation;
pub mod sampling;
pub use circuit_breaker::{CircuitBreaker, CircuitBreakerConfig, CircuitState};
#[cfg(feature = "gzip")]
pub use compression::GzipCompression;
#[cfg(feature = "compression")]
pub use compression::ZstdCompression;
pub use compression::{CompressionStrategy, NoCompression};
pub use console::ConsoleSink;
#[cfg(any(
feature = "sqlite",
feature = "postgres",
feature = "mysql",
feature = "duckdb"
))]
pub use database::DatabaseSink;
pub use file::FileSink;
pub use middleware::{
EnrichMiddleware, LevelFilterMiddleware, MiddlewareChain, MiddlewareSink, MiddlewareVerdict,
RecordMiddleware,
};
#[cfg(feature = "net-sink")]
pub use net::{NetWireFormat, TcpSink, TcpSinkConfig, TlsClientConfig, UdpSink, UdpSinkConfig};
#[cfg(feature = "otlp")]
pub use otlp::{OtlpConfig, OtlpSink};
pub use rate_limit::{
NoOpRateLimit, RateLimitedSink, SinkRateLimit, SinkWriteOutcome, TokenBucketRateLimit,
};
pub use registry::{FileSinkFactory, SinkFactory, SinkMetadata, SinkRegistry};
pub use rotation::{
CompositeRotation, RotationContext, RotationResult, RotationStrategy, SizeBasedRotation,
TimeBasedRotation,
};
pub use sampling::{Sampler, SamplingSink};
use crate::InklogError;
use crate::LogRecord;
use async_trait::async_trait;
pub trait AsyncSink: LogSink {}
impl<T: LogSink + ?Sized> AsyncSink for T {}
#[async_trait]
pub trait LogSink: Send + Sync {
async fn write(&self, record: &LogRecord) -> Result<(), InklogError>;
async fn flush(&self) -> Result<(), InklogError>;
fn is_healthy(&self) -> bool {
true
}
async fn shutdown(&self) -> Result<(), InklogError>;
}
pub trait Rotatable {
fn start_rotation_timer(&self);
fn stop_rotation_timer(&self);
}
pub trait DiskCheckable {
fn check_disk_space(&self) -> Result<bool, InklogError>;
}
#[cfg(test)]
mod tests {
use super::*;
struct DummySink;
#[async_trait]
impl LogSink for DummySink {
async fn write(&self, _record: &LogRecord) -> Result<(), InklogError> {
Ok(())
}
async fn flush(&self) -> Result<(), InklogError> {
Ok(())
}
async fn shutdown(&self) -> Result<(), InklogError> {
Ok(())
}
}
#[test]
fn test_default_is_healthy() {
let sink = DummySink;
assert!(sink.is_healthy());
}
struct RotatableDiskSink;
#[async_trait]
impl LogSink for RotatableDiskSink {
async fn write(&self, _record: &LogRecord) -> Result<(), InklogError> {
Ok(())
}
async fn flush(&self) -> Result<(), InklogError> {
Ok(())
}
async fn shutdown(&self) -> Result<(), InklogError> {
Ok(())
}
}
impl Rotatable for RotatableDiskSink {
fn start_rotation_timer(&self) {}
fn stop_rotation_timer(&self) {}
}
impl DiskCheckable for RotatableDiskSink {
fn check_disk_space(&self) -> Result<bool, InklogError> {
Ok(true)
}
}
#[test]
fn test_rotatable_trait() {
let sink = RotatableDiskSink;
sink.start_rotation_timer();
sink.stop_rotation_timer();
}
#[test]
fn test_disk_checkable_trait() {
let sink = RotatableDiskSink;
let result = sink.check_disk_space();
assert!(result.is_ok());
assert!(result.unwrap());
}
#[test]
fn test_log_sink_does_not_have_rotation_or_disk() {
let sink = DummySink;
assert!(sink.is_healthy());
}
}