Skip to content

feat(core): add OpenCV-style logging facade (cv::utils::logging equivalent) #80

Description

@kalwalt

Is your feature request related to a problem? Please describe.

purecv already depends on the log facade and exposes thin set_log_level / get_log_level wrappers in core::utils, but it has no structured logging API comparable to OpenCV's cv::utils::logging (the CV_LOG_* family in opencv2/core/utils/logger.hpp).

Two concrete gaps:

  1. Porting friction. OpenCV C/C++ sources are littered with CV_LOG_INFO(tag, ...), CV_LOG_WARNING(tag, ...), CV_LOG_ONCE_*, CV_LOG_IF_*, etc. Without 1:1 counterparts, every ported site has to be rewritten by hand, which is error-prone and loses the per-subsystem tag.
  2. No subsystem tagging. There is currently no consistent way to attribute log messages to a module (core, imgproc, features2d, ...) so users can filter them.
    Describe the solution you'd like

Add a dedicated core::logging module that mirrors cv::utils::logging, built on top of the existing log facade (so the output backend stays the application's choice — env_logger / fern / tracing / console_log on WASM). The OpenCV tag maps onto the log target:, so downstream filtering uses standard tooling, e.g. RUST_LOG=purecv::imgproc=debug,purecv::core=warn.

Proposed surface:

  • A LogLevel enum mirroring cv::utils::logging::LogLevel (Silent, Fatal, Error, Warning, Info, Debug, Verbose). Since log has five levels, Fatal collapses onto Error and Verbose onto Trace (documented).
  • set_log_level(LogLevel) -> LogLevel (returns the previous level, matching setLogLevel) and get_log_level() -> LogLevel.
  • A tags submodule with one &'static str per subsystem, following the module_path!() convention ("purecv", "purecv::core", "purecv::imgproc", ...).
  • #[macro_export] macros providing OpenCV parity:
    • levels: cv_log_fatal!, cv_log_error!, cv_log_warning!, cv_log_info!, cv_log_debug!, cv_log_verbose!(tag, v, ...)
    • once-per-call-site: cv_log_once_warning!, cv_log_once_info! (implemented with a core::sync::atomic::AtomicBool, no_std-friendly)
    • conditional: cv_log_if_error!, cv_log_if_warning!, cv_log_if_info!
      Mapping summary:
OpenCV purecv
CV_LOG_ERROR(tag, ...) cv_log_error!(tag, ...)
CV_LOG_WARNING(tag, ...) cv_log_warning!(tag, ...)
CV_LOG_INFO(tag, ...) cv_log_info!(tag, ...)
CV_LOG_DEBUG(tag, ...) cv_log_debug!(tag, ...)
CV_LOG_VERBOSE(tag, v, ...) cv_log_verbose!(tag, v, ...)
CV_LOG_ONCE_* cv_log_once_*!
CV_LOG_IF_* cv_log_if_*!
setLogLevel / getLogLevel set_log_level / get_log_level
tag (NULL, "global") target: (&str, see tags)
CV_LOG_STRIP_LEVEL log cargo features max_level_* / release_max_level_*

Example:

use purecv::core::logging::{self, tags, LogLevel};
 
logging::set_log_level(LogLevel::Info);
purecv::cv_log_info!(tags::IMGPROC, "gaussian blur, ksize = {}", 5);
purecv::cv_log_if_warning!(tags::CORE, ksize % 2 == 0, "even kernel size: {}", ksize);

Describe alternatives you've considered

  • Use bare log::info!(target: ..., ...) everywhere. Idiomatic, but offers no ONCE/IF/VERBOSE variants and no source-level parity with the OpenCV macros, so ports stay manual.

  • Reimplement OpenCV's LogTagManager (in-library per-tag levels). Heavier and redundant: in the Rust ecosystem per-target filtering is the backend's job (RUST_LOG). Per-tag levels inside the library can be added later as an optional log::Log filter layer if a real need appears — out of scope here.

  • Adopt tracing instead of log. More powerful (spans), but a larger dependency and a departure from what the crate already uses. Not warranted for now.
    Additional context

  • A drop-in src/core/logging.rs already exists as a prototype; it compiles and passes unit + doc-tests against log 0.4 on edition 2021.

  • Open decision: core::utils already defines set_log_level / get_log_level taking log::LevelFilter. To avoid two diverging APIs, the LogLevel-based versions should be canonical in core::logging, with core::utils re-exporting them (pub use crate::core::logging::{get_log_level, set_log_level};). This changes the existing signature from log::LevelFilter to LogLevel — flagging it explicitly.

  • WASM (crates/wasm): the core stays backend-agnostic; the wasm entry point should initialize a console backend once (e.g. console_log / wasm-logger) so cv_log_* reach the browser console. Can be a follow-up.
    Tasks:

  • Add src/core/logging.rs (LogLevel, set/get_log_level, tags, macros)

  • Register pub mod logging; in src/core.rs

  • Re-export set_log_level / get_log_level from core::utils (or keep both — decide)

  • Optionally surface LogLevel / tags in the crate prelude

  • Unit tests for level round-trip and macro expansion (in module tests)

  • Document CV_LOG_STRIP_LEVELlog release_max_level_* in the README

  • Follow-up: console logger init in crates/wasm
    Verification per CONTRIBUTING.md: cargo test, cargo fmt -- --check, cargo clippy -- -D warnings. PR against dev.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Fields

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions