inklog 0.3.0-rc.4

Enterprise-grade Rust logging infrastructure
// Copyright (c) 2026 Kirky.X
// SPDX-License-Identifier: MIT
#![doc(html_root_url = "https://docs.rs/inklog/0.3.0-rc.3")]
#![cfg_attr(test, allow(clippy::field_reassign_with_default))]

//! # inklog - 企业级 Rust 日志基础设施
//!
//! inklog 是一个高性能、可扩展的日志库,专为生产环境设计。
//!
//! ## 功能特性
//!
//! - **多输出目标**: 支持 Console、File、Database 三种输出通道
//! - **日志轮转**: 支持按大小和按时间轮转
//! - **压缩与加密**: 支持 Zstandard 压缩和 AES-256-GCM 加密
//! - **批量写入**: 数据库批量写入,可配置批次大小和刷新间隔
//! - **降级机制**: DB → File → Console 三级降级
//! - **健康监控**: HTTP 端点暴露健康状态和 Prometheus 指标
//!
//! ## 快速开始
//!
//! ### 基础用法
//!
//! ```rust,no_run
//! use inklog::{LoggerManager, InklogConfig};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // 使用默认配置初始化
//!     let _logger = LoggerManager::new().await?;
//!     
//!     // 使用 tracing 宏记录日志
//!     tracing::info!("Hello, inklog!");
//!     
//!     Ok(())
//! }
//! ```
//!
//! ### 使用 Builder 模式配置
//!
//! ```rust,no_run
//! # #[cfg(not(feature = "http"))]
//! # fn main() {}
//! # #[cfg(feature = "http")]
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     use inklog::LoggerManager;
//!
//!     let _logger = LoggerManager::builder()
//!         .level("debug")
//!         .console(true)
//!         .file("logs/app.log")
//!         .enable_http_server(true)
//!         .http_port(9090)
//!         .build()
//!         .await?;
//!
//!     Ok(())
//! }
//! ```
//!
//! ### 从配置文件加载
//!
//! ```rust,no_run
//! use inklog::LoggerManager;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // 从指定文件加载
//!     let _logger = LoggerManager::from_file("config.toml").await?;
//!     
//!     // 或自动搜索配置文件
//!     // let _logger = LoggerManager::load().await?;
//!     
//!     Ok(())
//! }
//! ```
//!
//! ### 使用依赖注入模式
//!
//! ```rust,ignore
//! use std::sync::Arc;
//! use inklog::{LoggerManager, LoggerDependencies, InklogContainer};
//! use inklog::integrations::{OxCacheAdapter, InklogConfigAdapter};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // 方式 1: 使用依赖注入容器
//!     let container = InklogContainer::new()?;
//!     let logger = container.create_logger().await?;
//!     
//!     // 方式 2: 使用 Builder 模式注入依赖
//!     let logger = LoggerManager::builder()
//!         .cache(Arc::new(OxCacheAdapter::new()?))
//!         .config(Arc::new(InklogConfigAdapter::new()?))
//!         .build().await?;
//!     
//!     // 方式 3: 使用 with_dependencies
//!     let deps = LoggerDependencies {
//!         cache: Some(Arc::new(OxCacheAdapter::new()?)),
//!         config: Some(Arc::new(InklogConfigAdapter::new()?)),
//!         ..Default::default()
//!     };
//!     let logger = LoggerManager::with_dependencies(deps).await?;
//!     
//!     Ok(())
//! }
//! ```
//!
//! ## 配置文件示例 (TOML)
//!
//! ```toml
//! [global]
//! level = "info"
//!
//! [console_sink]
//! enabled = true
//!
//! [file_sink]
//! enabled = true
//! path = "logs/app.log"
//! max_size = "100MB"
//! rotation = "daily"
//!
//! [http_server]
//! enabled = true
//! host = "127.0.0.1"
//! port = 8080
//! ```

mod error;
mod log_level;
mod validation;

// Internationalization — core feature, always compiled
pub mod i18n;

// Emit a clear compile error when the `kit` feature is enabled without any
// database driver.  DbNexusAdapter and InklogModule require at least
// one of sqlite / postgres / mysql / duckdb to function.
#[cfg(all(
    feature = "kit",
    not(any(
        feature = "sqlite",
        feature = "postgres",
        feature = "mysql",
        feature = "duckdb"
    ))
))]
compile_error!(
    "The 'kit' feature requires at least one database driver feature: \
     \"sqlite\", \"postgres\", \"mysql\", or \"duckdb\". Enable one or more \
     of these features alongside 'kit'."
);

// Backwards compatibility - expose modules at root level
pub use domain::config;
pub use domain::types::log_record;
pub use support::io::sink;
pub use support::processing::template;

// Domain layer
pub mod domain;

// Support layer
pub mod support;

// Sink 中间件链
pub use support::io::sink::middleware::{
    EnrichMiddleware, LevelFilterMiddleware, MiddlewareChain, MiddlewareSink, MiddlewareVerdict,
    RecordMiddleware,
};
#[cfg(feature = "otlp")]
pub use support::io::sink::otlp::{OtlpConfig, OtlpSink};

// 网络转发 sink(net-sink feature)
#[cfg(feature = "net-sink")]
pub use support::io::sink::net::{
    NetWireFormat, TcpSink, TcpSinkConfig, TlsClientConfig, UdpSink, UdpSinkConfig,
};

// KMS 密钥提供者(kms feature)
#[cfg(feature = "kms")]
pub use support::security::{
    ConfersKeyProvider, EnvKeyProvider, KeyProvider, VaultTransitConfig, vault_transit_provider,
};

// Sink trait and type re-exports for public API completeness
#[cfg(feature = "gzip")]
pub use support::io::sink::GzipCompression;
pub use support::io::sink::SinkWriteOutcome;
#[cfg(feature = "compression")]
pub use support::io::sink::ZstdCompression;
#[cfg(feature = "compression")]
pub use support::io::sink::compression::{compress_data, compress_file, compress_string};
pub use support::io::sink::encryption::{derive_key_from_password, get_encryption_key};
pub use support::io::sink::ring_buffered_file::{
    BackpressureStrategy, ChannelBufferedConfig, ChannelBufferedFileSink, ChannelBufferedMetrics,
};
pub use support::io::sink::{
    AsyncSink, CircuitBreaker, CircuitBreakerConfig, CircuitState, CompositeRotation,
    CompressionStrategy, DiskCheckable, FileSinkFactory, LogSink, NoCompression, NoOpRateLimit,
    RateLimitedSink, Rotatable, RotationContext, RotationResult, RotationStrategy, Sampler,
    SamplingSink, SinkFactory, SinkMetadata, SinkRateLimit, SinkRegistry, SizeBasedRotation,
    TimeBasedRotation, TokenBucketRateLimit,
};

// Re-export masking for benchmarks
pub use support::processing::masking;

// Integrations layer
pub mod integrations;

// Re-export types from domain layer for backwards compatibility
pub use domain::config::{
    ArchiveFormat, ChannelStrategy, ConsoleSinkConfig, DatabaseDriver, DatabaseSinkConfig,
    FileSinkConfig, GlobalConfig, HttpAuthConfig, HttpErrorMode, HttpServerConfig, InklogConfig,
    ParquetConfig, PartitionStrategy, PerformanceConfig, TlsConfig,
};
pub use domain::types::log_record::LogRecord;
pub use error::InklogError;
pub use error::InklogResult;
#[cfg(any(
    feature = "sqlite",
    feature = "postgres",
    feature = "mysql",
    feature = "duckdb"
))]
pub use integrations::DbNexusAdapter;
#[cfg(all(
    feature = "kit",
    any(
        feature = "sqlite",
        feature = "postgres",
        feature = "mysql",
        feature = "duckdb"
    )
))]
pub use integrations::InklogModule;

// Infrastructure trait and adapter re-exports for dependency injection
pub use integrations::{
    Cache, Config, Database, InklogConfigAdapter, OxCacheAdapter, OxCacheAdapterBuilder,
};
// Mock 实现仅对测试面可见(src 内联测试经 cfg(test),外部消费者需显式 test-utils)
#[cfg(all(
    feature = "kit",
    any(
        feature = "sqlite",
        feature = "postgres",
        feature = "mysql",
        feature = "duckdb"
    )
))]
pub use integrations::{InklogBuildObserver, create_inklog_scope, populate_inklog_scope};
#[cfg(any(test, feature = "test-utils"))]
pub use integrations::{MockCache, MockConfig, MockDatabaseAdapter};

pub use domain::core::{
    InklogContainer, InklogContainerBuilder, LoggerBuilder, LoggerDependencies, LoggerManager,
};

pub use log_level::{LogLevel, LogLevelParseError};
pub use support::io::{LogAdapter, LogLogger};
pub use support::observability::{
    FallbackAction, FallbackConfig, FallbackState, GaugeF64, HealthStatus, Metrics, SinkHealth,
    SinkHealthMonitor, SinkStatus,
};
pub use support::processing::{
    DataMasker, DataMaskerBuilder, LogTemplate, MaskRule, MaskRuleBuilder, MaskRuleRegistry,
    ObjectPool, ObjectPoolConfig, OutputFormat, RateLimiter, get_log_record, get_string_buffer,
    put_log_record, put_string_buffer,
};
pub use validation::{
    EscapeMode, LogSanitizer, PathValidator, PathValidatorConfig, SanitizerConfig,
    ValidationResult, create_validated_file, open_validated_file,
};

// Re-export underlying dependencies used in public API type signatures.
//
// Scope: only type references (L1) — e.g. `use inklog::tracing::Level`,
// `use inklog::chrono::DateTime`. Macro attributes (L2, `#[tokio::main]`)
// and macro invocations (L3, `tracing::info!`) reference absolute crate
// paths at expansion time and cannot be routed through a re-export alias;
// downstream crates must still declare direct dependencies for those uses.
// This re-export therefore narrows the direct-dependency surface to the
// macro path only; it does not eliminate it.
pub use chrono;
pub use serde;
pub use tokio;
pub use tracing;

// ============================================================================
// Convenience init functions with singleton semantics
// ============================================================================

use std::sync::OnceLock;

/// Global sentinel for singleton init semantics.
static INIT_SENTINEL: OnceLock<()> = OnceLock::new();

/// Initialize the inklog logger with default configuration.
///
/// This is a convenience wrapper around [`LoggerManager::with_config`] that
/// installs the tracing subscriber globally and enforces **singleton
/// semantics**: calling this function more than once returns
/// `Err(InklogError::ConfigError)` instead of silently re-initializing.
///
/// For custom configuration, use [`init_inklog_logger_with_config`].
///
/// # Errors
///
/// Returns `Err` if the logger has already been initialized in this process,
/// or if configuration loading / subscriber installation fails.
///
/// # Example
///
/// ```rust,ignore
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     inklog::init_inklog_logger().await?;
///     tracing::info!("logger is ready");
///     Ok(())
/// }
/// ```
pub async fn init_inklog_logger() -> Result<(), InklogError> {
    init_inklog_logger_with_config(InklogConfig::default()).await
}

/// Initialize the inklog logger with explicit configuration.
///
/// Singleton semantics: the first call installs the global subscriber;
/// subsequent calls return `Err(InklogError::ConfigError)` regardless of
/// whether the config differs.
///
/// # Errors
///
/// - `InklogError::ConfigError` if already initialized (singleton violation)
/// - Propagates errors from [`LoggerManager::with_config`]
///
/// # Example
///
/// ```rust,ignore
/// use inklog::{InklogConfig, init_inklog_logger_with_config};
/// use std::collections::HashMap;
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let mut config = InklogConfig::default();
///     config.target_levels = HashMap::from([
///         ("hyper".into(), "warn".into()),
///         ("my_crate".into(), "debug".into()),
///     ]);
///     init_inklog_logger_with_config(config).await?;
///     Ok(())
/// }
/// ```
pub async fn init_inklog_logger_with_config(config: InklogConfig) -> Result<(), InklogError> {
    // 先初始化、后占哨兵:初始化失败时不污染单例状态,调用方可修正配置后重试。
    let manager = LoggerManager::with_config(config).await?;
    INIT_SENTINEL.set(()).map_err(|_| {
        InklogError::ConfigError(
            "inklog logger already initialized; init_inklog_logger() is a singleton — \
             only the first call succeeds"
                .into(),
        )
    })?;
    // 管理器持有 sink worker 线程与 channel 接收端:必须跨进程存活期保留
    //(mem::forget 抑制 Drop),否则 Drop→shutdown 会停掉全部 worker,
    // 初始化完成后的日志会被静默丢弃。
    std::mem::forget(manager);
    Ok(())
}