Skip to main content

hdds_c/
logging.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2// Copyright (c) 2025-2026 naskel.com
3
4//! Logging initialization for HDDS C FFI
5
6use std::ffi::CStr;
7use std::os::raw::c_char;
8
9use super::HddsError;
10
11/// Log level for HDDS logging
12#[repr(C)]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum HddsLogLevel {
15    HddsLogOff = 0,
16    HddsLogError = 1,
17    HddsLogWarn = 2,
18    HddsLogInfo = 3,
19    HddsLogDebug = 4,
20    HddsLogTrace = 5,
21}
22
23impl From<HddsLogLevel> for log::LevelFilter {
24    fn from(level: HddsLogLevel) -> Self {
25        match level {
26            HddsLogLevel::HddsLogOff => log::LevelFilter::Off,
27            HddsLogLevel::HddsLogError => log::LevelFilter::Error,
28            HddsLogLevel::HddsLogWarn => log::LevelFilter::Warn,
29            HddsLogLevel::HddsLogInfo => log::LevelFilter::Info,
30            HddsLogLevel::HddsLogDebug => log::LevelFilter::Debug,
31            HddsLogLevel::HddsLogTrace => log::LevelFilter::Trace,
32        }
33    }
34}
35
36/// Initialize HDDS logging with console output
37///
38/// # Safety
39/// Must be called from a single thread during initialization.
40///
41/// # Arguments
42/// * `level` - Minimum log level to display
43///
44/// # Returns
45/// `HddsError::HddsOk` on success, `HddsError::HddsOperationFailed` if already initialized
46///
47/// # Example (C)
48/// ```c
49/// hdds_logging_init(HDDS_LOG_INFO);
50/// ```
51#[no_mangle]
52pub unsafe extern "C" fn hdds_logging_init(level: HddsLogLevel) -> HddsError {
53    let filter: log::LevelFilter = level.into();
54
55    match env_logger::Builder::new()
56        .filter_level(filter)
57        .format_timestamp_millis()
58        .try_init()
59    {
60        Ok(()) => HddsError::HddsOk,
61        Err(_) => HddsError::HddsOperationFailed, // Already initialized
62    }
63}
64
65/// Initialize HDDS logging with environment variable override
66///
67/// Reads `RUST_LOG` environment variable if set, otherwise uses provided level.
68///
69/// # Safety
70/// Must be called from a single thread during initialization.
71///
72/// # Arguments
73/// * `default_level` - Default log level if `RUST_LOG` is not set
74///
75/// # Returns
76/// `HddsError::HddsOk` on success
77#[no_mangle]
78pub unsafe extern "C" fn hdds_logging_init_env(default_level: HddsLogLevel) -> HddsError {
79    let filter: log::LevelFilter = default_level.into();
80
81    match env_logger::Builder::from_env(
82        env_logger::Env::default().default_filter_or(filter.to_string()),
83    )
84    .format_timestamp_millis()
85    .try_init()
86    {
87        Ok(()) => HddsError::HddsOk,
88        Err(_) => HddsError::HddsOperationFailed,
89    }
90}
91
92/// Initialize HDDS logging with custom filter string
93///
94/// # Safety
95/// - `filter` must be a valid null-terminated C string or NULL.
96///
97/// # Arguments
98/// * `filter` - Log filter string (e.g., "hdds=debug,info")
99///
100/// # Returns
101/// `HddsError::HddsOk` on success
102///
103/// # Example (C)
104/// ```c
105/// hdds_logging_init_with_filter("hdds=debug");
106/// ```
107#[no_mangle]
108pub unsafe extern "C" fn hdds_logging_init_with_filter(filter: *const c_char) -> HddsError {
109    if filter.is_null() {
110        return HddsError::HddsInvalidArgument;
111    }
112
113    let Ok(filter_str) = CStr::from_ptr(filter).to_str() else {
114        return HddsError::HddsInvalidArgument;
115    };
116
117    match env_logger::Builder::new()
118        .parse_filters(filter_str)
119        .format_timestamp_millis()
120        .try_init()
121    {
122        Ok(()) => HddsError::HddsOk,
123        Err(_) => HddsError::HddsOperationFailed,
124    }
125}