appcore-log 1.0.0-rc.1

Structured, bounded, security-first operational logging for AppCore
Documentation

appcore-log

Português | Français

appcore-log provides structured, bounded, and security-first operational logging for AppCore. It has no global logger, hidden queue, or background worker. The caller explicitly chooses filtering, destinations, retention, and durability.

Quick start

use appcore_log::{LogOutputMode, LoggerConfig};

fn main() -> Result<(), appcore_log::LogConfigError> {
    let logger = LoggerConfig {
        output: LogOutputMode::Terminal,
        ..LoggerConfig::default()
    }
    .build()?;

    let log = logger.dispatcher().event(0, "application");

    log.info("application started");
    log.warn("connection is slow");

    Ok(())
}

Applications using appcore-sdk configure the same logger with App::logging and emit through app.log(...) or app.logger().

Output modes

Mode Normal execution File required
Terminal Human-readable terminal output No
File Structured bounded JSONL Yes
TerminalAndFile Terminal and JSONL Yes
Disabled No sink work or message conversion No
CrashOnly Bounded sanitized memory ring Yes, created only by dump_crash

CrashOnly does not install a panic handler. Call dump_crash once from the application's controlled crash boundary.

Bounded file output

use appcore_log::{
    FileArchiveConfig, FileSinkConfig, LogOutputMode, LoggerConfig,
    LOG_SIZE_8_MIB,
};

fn main() -> Result<(), appcore_log::LogConfigError> {
    let logger = LoggerConfig {
        output: LogOutputMode::TerminalAndFile,
        file: Some(FileSinkConfig {
            path: "logs/runtime.jsonl".into(),
            max_bytes: LOG_SIZE_8_MIB,
            sync_each_write: false,
            retention: 2,
            archive: Some(FileArchiveConfig {
                directory: "logs/archive".into(),
                max_files: 120,
            }),
        }),
        ..LoggerConfig::default()
    }
    .build()?;

    logger.dispatcher().event(0, "application").info("ready");

    Ok(())
}

The active directory contains runtime.jsonl, runtime.jsonl.1, and runtime.jsonl.2. Older rotations move to archive/YYYY/MM until the complete archive reaches max_files. The file name is application-defined. Create the active file's parent directory during application setup; archive year/month directories are created during rotation. File and archive destinations reject symbolic links instead of following them.

Set sync_each_write: true when every event must be flushed to storage before returning. false avoids that syscall and favors throughput. Common limits are available from LOG_SIZE_1_MIB through LOG_SIZE_64_MIB; custom nonzero u64 values remain valid.

Severity, verbosity, and components

Severity describes impact, from Trace to Critical. Verbosity describes detail, from V1 to V9. A V4 policy accepts V1 through V4; it does not mean "severity four". Component overrides are hierarchical, so an override for sync also applies to sync.transport unless a more specific one exists.

Security boundary

Safe and Diagnostic policies redact typed secrets and alias typed paths before ordinary sinks receive an event. Use LogEvent::secret and LogEvent::path; never put credentials in free-form messages. Full paths require a separate explicit policy decision.

Sensitive diagnostics require Sensitivity::Sensitive and an explicitly wired SensitiveDntSink. They are authenticated and encrypted as DNT and never fall back to terminal, JSONL, or ordinary memory sinks. Secret fields remain redacted even there.

Limits and failure behavior

  • Event text: 4 KiB per text or identity field.
  • Structured fields: 32 per event.
  • Field keys: 128 bytes; field values: 4 KiB.
  • Active rotations: at most 32.
  • Archived files: from 1 to 10,000.
  • Rings: always bounded by both event count and estimated retained bytes.
  • Sink failures: counted by the dispatcher and never logged recursively.

Use stats() for aggregate filtering/failure counters and sink_stats() for per-destination failures. Use FixedLogClock for deterministic tests.

See the English guide and the executable examples in examples/.

Benchmark

Run the seven hardware-aware workloads with:

cargo run -p appcore-dev -- bench --name appcore-log \
  --output target/appcore-log-benchmark.json

The report records timing distributions, CPU time, peak/retained RSS, and host CPU, RAM, GPU, OS, and filesystem context. Compare compatible reports with appcore-dev bench compare.

Stable documentation

Stable ID: ACR-027. See the supplemental architecture and integration guide. This permanent ID remains valid if the wiki page moves.