Language Page

ktrace for Rust

This page is assembled from markdown in ktools-rust. GitHub links point to the workspace repo and the relevant source files or directories.

5 markdown sections
QM-Code/ktools-rust primary repo
HTML static output

ktrace-rust

ktools-rust/ktrace/README.md

ktools-rust/ktrace/ is the Rust implementation of ktrace.

It provides:

  • namespaced trace channels through TraceLogger
  • operator-facing info, warn, and error logging
  • selector-based runtime enablement through Logger
  • kcli inline parser integration for --trace* controls

Documentation

Quick Start

use ktrace::{Logger, TraceLogger, ktrace_info, ktrace_trace};

let logger = Logger::new();
let app_trace = TraceLogger::new("app")?;
app_trace.add_channel("startup", ktrace::color("BrightCyan")?)?;

logger.add_trace_logger(app_trace.clone())?;
logger.enable_channel("app.startup", "")?;

ktrace_trace!(app_trace, "startup", "starting {}", "demo")?;
ktrace_info!(app_trace, "operator-visible message")?;
# Ok::<(), ktrace::TraceError>(())

API Model

TraceLogger is the library-facing source object. Construct it with an explicit namespace and declare channels on it:

let trace = ktrace::TraceLogger::new("alpha")?;
trace.add_channel("net", ktrace::color("DeepSkyBlue1")?)?;
trace.add_channel("cache", ktrace::color("Gold3")?)?;
# Ok::<(), ktrace::TraceError>(())

SDKs typically expose a shared handle from get_trace_logger() so executable code can import registered namespaces and channels without rebuilding them.

Logger is the executable-facing runtime. It imports one or more TraceLoggers, maintains the channel registry, owns selector enablement, and builds the kcli inline parser for --trace* options.

Logging APIs

Channel-based trace output:

trace.trace("channel", "plain trace message")?;
trace.trace_changed("channel", "session:42", "only when key changes")?;
# Ok::<(), ktrace::TraceError>(())

Always-visible operational logging:

trace.info("service started")?;
trace.warn("retrying connection")?;
trace.error("startup failed")?;
# Ok::<(), ktrace::TraceError>(())

Operational logging is independent of channel enablement. Macro helpers use standard Rust format! semantics and capture file, line, and module information automatically.

CLI Integration

Pass the executable's local TraceLogger to make_inline_parser() so leading-dot selectors resolve against the intended namespace:

let logger = ktrace::Logger::new();
let app_trace = ktrace::TraceLogger::new("app")?;
app_trace.add_channel("startup", ktrace::color("BrightCyan")?)?;
logger.add_trace_logger(app_trace.clone())?;

let mut parser = kcli::Parser::new();
parser.add_inline_parser(logger.make_inline_parser(app_trace.clone(), "trace")?)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Common commands:

--trace 'app.startup'
--trace '*.net'
--trace '*.{net,io}'
--trace '*.*.*.*'
--trace-namespaces
--trace-channels
--trace-colors
--trace-files
--trace-functions
--trace-timestamps

Selector Forms

Single-selector APIs on Logger:

  • .channel[.sub[.sub]] for a local channel in the provided local namespace
  • namespace.channel[.sub[.sub]] for an explicit namespace

List APIs on Logger:

  • enable_channels(...)
  • disable_channels(...)
  • selector lists support CSV, *, brace expansion, and leading-dot local selectors
  • list selectors resolve against the channels currently registered at call time
  • empty selector lists are rejected
  • unregistered channels remain disabled even when a selector pattern would otherwise match

Build

From this repo root:

kbuild --build-latest

If kbuild is not on PATH, use the shared workspace copy:

python3 ../../kbuild/kbuild.py --build-latest

Direct Cargo workflow:

cd src
cargo test

SDK staging after kbuild --build-latest:

  • build/latest/sdk/Cargo.toml
  • build/latest/sdk/src/
  • build/latest/sdk/tests/

Demos

  • Bootstrap compile/link check: demo/bootstrap/
  • SDK demos: demo/sdk/{alpha,beta,gamma}
  • Executable demos: demo/exe/{core,omega}

After kbuild --build-latest, staged demo outputs appear under:

  • demo/bootstrap/build/latest/
  • demo/sdk/alpha/build/latest/
  • demo/sdk/beta/build/latest/
  • demo/sdk/gamma/build/latest/
  • demo/exe/core/build/latest/
  • demo/exe/omega/build/latest/

Useful demo commands:

./demo/bootstrap/build/latest/bootstrap
./demo/sdk/alpha/build/latest/sdk_alpha
./demo/sdk/beta/build/latest/sdk_beta
./demo/sdk/gamma/build/latest/sdk_gamma
./demo/exe/core/build/latest/core --trace
./demo/exe/omega/build/latest/omega --trace '*.*'
./demo/exe/omega/build/latest/omega --trace-namespaces
./demo/exe/omega/build/latest/omega --trace-colors

Repository Layout

  • Public API: src/src/lib.rs
  • Color catalog: src/src/colors.rs
  • Demo binaries: src/src/bin/
  • Shared demo helpers: src/src/demo/
  • Behavior coverage: src/tests/

Ktrace Rust Documentation

ktools-rust/ktrace/docs/index.md

ktrace is the Rust tracing and operator-logging layer for the ktools stack.

The Rust implementation is built around two public runtime types:

  • TraceLogger
  • Logger

TraceLogger is the library-facing source object. It owns one trace namespace, declares channels in that namespace, and emits trace or log output.

Logger is the executable-facing runtime. It aggregates one or more TraceLogger instances, enables channels by selector, formats output, and builds the kcli inline parser for --trace* options.

Start Here

Typical Flow

use ktrace::{Logger, TraceLogger, ktrace_trace, ktrace_info};

let logger = Logger::new();
let app_trace = TraceLogger::new("app")?;
app_trace.add_channel("startup", ktrace::color("BrightCyan")?)?;

logger.add_trace_logger(app_trace.clone())?;
logger.enable_channel("app.startup", "")?;

ktrace_trace!(app_trace, "startup", "starting {}", "demo")?;
ktrace_info!(app_trace, "operator-visible message")?;
# Ok::<(), ktrace::TraceError>(())

Core Concepts

Trace namespace

  • A named source domain such as app, alpha, or gamma.
  • Created when a TraceLogger is constructed.

Channel

  • A channel inside one namespace, such as startup, net, or scheduler.tick.
  • Channels must be registered before they can be enabled and traced.

Selector

  • A runtime enablement pattern such as app.startup, .startup, *.*, or *.{net,io}.
  • Selectors are resolved against registered channels only.

Operational log

  • info, warn, and error output is always emitted once a TraceLogger is attached to a Logger.
  • It does not depend on channel enablement.

Working References

API Guide

ktools-rust/ktrace/docs/api.md

This page summarizes the public API exported from src/src/lib.rs.

Core Types

Type Purpose
TraceLogger Library-facing trace source for one namespace.
Logger Executable-facing registry, selector runtime, formatter, and CLI integration point.
OutputOptions Output formatting toggles for file, line, function, and timestamp labels.
SourceLocation Explicit source metadata for low-level trace/log calls.
TraceError Error type used by fallible ktrace operations.
Severity Log severity enum used by low-level logging calls.

Shared Types

ColorId and DEFAULT_COLOR

  • ColorId is an alias for u16.
  • DEFAULT_COLOR means “no explicit channel color”.
  • Use color("Name") to resolve named colors instead of hard-coding ids.

OutputOptions

Field Meaning
filenames Include a source label such as [lib:42].
line_numbers Include the source line when filenames is enabled.
function_names Include the function/module label when filenames is enabled.
timestamps Include a compact epoch-based timestamp label.

TraceLogger

Construction

let trace = ktrace::TraceLogger::new("alpha")?;

Rules:

  • the namespace must be non-empty
  • the namespace may contain ASCII letters, digits, _, and -

Channel Registration

trace.add_channel("net", ktrace::color("DeepSkyBlue1")?)?;
trace.add_channel("cache", ktrace::DEFAULT_COLOR)?;
trace.add_channel("scheduler.tick", ktrace::color("Orange3")?)?;

Rules:

  • channel depth is limited to 3 segments
  • nested channels require their parent to be registered first
  • conflicting explicit colors for the same qualified channel are rejected

Querying

let namespace = trace.namespace();
let enabled = trace.should_trace_channel("net");

should_trace_channel() returns false when:

  • the channel name is invalid
  • the TraceLogger is not attached to a Logger
  • the channel is registered but not enabled

Emitting Trace Output

trace.trace("net", "plain trace message")?;
trace.trace_changed("net", "session:42", "only when key changes")?;

Low-level forms:

  • trace_with_location(channel, location, message)
  • trace_changed_with_location(channel, key, location, message)

trace_changed* suppresses duplicate messages for the same call site, channel, and key.

Emitting Operational Logs

trace.info("service started")?;
trace.warn("retrying connection")?;
trace.error("startup failed")?;

Low-level form:

  • log_with_location(severity, location, message)

Operational logging is independent of channel enablement.

Logger

Construction

let logger = ktrace::Logger::new();

Logger::default() is equivalent.

Attaching Trace Sources

logger.add_trace_logger(app_trace.clone())?;
logger.add_trace_logger(alpha_trace.clone())?;

Rules:

  • one TraceLogger may only be attached to one Logger
  • duplicate namespaces are merged
  • registered channels become visible for selector resolution and help output

Channel Enablement

logger.enable_channel("app.startup", "")?;
logger.enable_channel(".startup", "app")?;
logger.enable_channels("app.*,{alpha,beta}.net", "app")?;

logger.disable_channel("app.startup", "")?;
logger.disable_channels("*.{net,io}", "app")?;

let enabled = logger.should_trace_channel("app.startup", "");

Semantics:

  • exact selectors require namespace.channel or .channel
  • bulk selector APIs resolve only against currently registered channels
  • unmatched selector patterns do not enable phantom channels
  • invalid exact selectors raise TraceError
  • invalid list selectors raise TraceError

Output Control

logger.set_output_options(ktrace::OutputOptions {
    filenames: true,
    line_numbers: true,
    function_names: false,
    timestamps: true,
})?;

let options = logger.get_output_options()?;

Registry Introspection

let namespaces = logger.get_namespaces()?;
let channels = logger.get_channels("alpha")?;

kcli Integration

let parser = logger.make_inline_parser(app_trace.clone(), "trace")?;

This returns a kcli::InlineParser that supports:

  • --trace <selectors>
  • --trace-examples
  • --trace-namespaces
  • --trace-channels
  • --trace-colors
  • --trace-files
  • --trace-functions
  • --trace-timestamps

Public Helper Functions

color(name)

Resolves a named color such as:

  • BrightCyan
  • DeepSkyBlue1
  • Gold3
  • Orange3

available_color_names()

Returns the set of color names supported by color(name).

Macros

These macros capture file!(), line!(), and module_path!() automatically.

Macro Purpose
ktrace_trace!(logger, channel, ...) Trace a formatted message through one channel.
ktrace_trace_changed!(logger, channel, key, ...) Trace only when the key changes at that call site.
ktrace_info!(logger, ...) Emit an info operational log.
ktrace_warn!(logger, ...) Emit a warning operational log.
ktrace_error!(logger, ...) Emit an error operational log.

Examples

ktools-rust/ktrace/docs/examples.md

Minimal Executable

use kcli::Parser;
use ktrace::{Logger, TraceLogger, ktrace_info, ktrace_trace};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let logger = Logger::new();
    let app_trace = TraceLogger::new("app")?;
    app_trace.add_channel("startup", ktrace::color("BrightCyan")?)?;

    logger.add_trace_logger(app_trace.clone())?;

    let mut parser = Parser::new();
    parser.add_inline_parser(logger.make_inline_parser(app_trace.clone(), "trace")?)?;

    let argv = std::env::args().collect::<Vec<_>>();
    parser.parse_or_exit(&argv);

    logger.enable_channel("app.startup", "")?;
    ktrace_trace!(app_trace, "startup", "starting {}", "demo")?;
    ktrace_info!(app_trace, "operator message")?;
    Ok(())
}

Library-Style Shared Trace Source

use ktrace::TraceLogger;

fn get_trace_logger() -> Result<TraceLogger, ktrace::TraceError> {
    let trace = TraceLogger::new("alpha")?;
    trace.add_channel("net", ktrace::color("DeepSkyBlue1")?)?;
    trace.add_channel("net.alpha", ktrace::DEFAULT_COLOR)?;
    trace.add_channel("cache", ktrace::color("Gold3")?)?;
    Ok(trace)
}

Output Formatting

logger.set_output_options(ktrace::OutputOptions {
    filenames: true,
    line_numbers: true,
    function_names: true,
    timestamps: true,
})?;

Example prefix shapes:

  • [app] [startup]
  • [app] [info]
  • [app] [1711500000.123456] [startup] [main:42]
  • [app] [warning] [main:42:run]

Trace-Changed Usage

use ktrace::ktrace_trace_changed;

let trace = TraceLogger::new("app")?;
trace.add_channel("state", ktrace::DEFAULT_COLOR)?;

ktrace_trace_changed!(trace, "state", "connected", "state changed")?;

The second call with the same key at the same call site is suppressed until the key changes.

Where To See Running Examples

Selectors And CLI

ktools-rust/ktrace/docs/selectors.md

ktrace uses selectors to enable or disable registered channels at runtime.

Exact Selectors

Use exact selectors with Logger::enable_channel(), Logger::disable_channel(), and Logger::should_trace_channel().

Forms:

  • namespace.channel
  • .channel

Examples:

  • app.startup
  • alpha.net
  • .startup with local namespace app

Exact selectors must resolve to a valid registered channel path.

Selector Lists

Use selector lists with Logger::enable_channels() and Logger::disable_channels().

Selector lists support:

  • CSV: alpha.net,beta.io
  • wildcard namespace: *.net
  • wildcard channel segments: alpha.*, alpha.*.*, alpha.*.*.*, *.*, *.*.*, *.*.*.*
  • brace expansion: *.{net,io}, {alpha,beta}.scheduler
  • local-namespace shorthand: .startup,.net

Examples:

app.*
app.*.*
*.net
*.{net,io}
{alpha,beta}.scheduler.tick

Resolution Rules

  • selectors are resolved against registered channels only
  • unmatched selectors do not create new channels
  • empty selector lists are rejected
  • invalid selector syntax raises TraceError
  • *.* includes top-level channels across namespaces
  • *.*.* includes channels up to depth 2 across namespaces
  • *.*.*.* includes channels up to depth 3 across namespaces

kcli Inline Parser

Logger::make_inline_parser() exposes the selector system through kcli.

Typical setup:

let logger = ktrace::Logger::new();
let app_trace = ktrace::TraceLogger::new("app")?;
app_trace.add_channel("startup", ktrace::color("BrightCyan")?)?;
logger.add_trace_logger(app_trace.clone())?;

let mut parser = kcli::Parser::new();
parser.add_inline_parser(logger.make_inline_parser(app_trace.clone(), "trace")?)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Common commands:

--trace 'app.startup'
--trace '*.net'
--trace '*.{net,io}'
--trace '*.*.*.*'
--trace-namespaces
--trace-channels
--trace-colors
--trace-files
--trace-functions
--trace-timestamps