Language Page

ktrace for C#

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

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

Karma Trace Logging SDK For C#

ktools-csharp/ktrace/README.md

ktrace is the C# tracing and logging layer in the ktools ecosystem.

It provides:

  • channel-based trace output
  • always-visible operational logging through Info, Warn, and Error
  • selector-driven runtime enablement
  • kcli integration through Logger.MakeInlineParser(...)

Quick Start

using Kcli;
using Ktrace;

Logger logger = new Logger();
TraceLogger appTrace = new TraceLogger("core");
appTrace.AddChannel("app", "BrightCyan");

logger.AddTraceLogger(appTrace);

Parser parser = new Parser();
parser.AddInlineParser(logger.MakeInlineParser(appTrace));
parser.ParseOrExit(args);

Documentation

Behavior Highlights

  • Trace channels are registered explicitly on TraceLogger.
  • Runtime enablement happens through exact selectors or selector lists.
  • Unregistered channels never emit, even if a selector pattern would otherwise match.
  • Child channels inherit the nearest registered parent color unless they override it explicitly.
  • Output options apply to both trace output and operational logging.
  • Named colors include Default plus the C++-style xterm 256-color catalog.

Build

kbuild --build-latest

From the workspace root, prefer:

cd ..
kbuild --batch --build-latest

ktrace/ depends on the sibling kcli/ SDK. Component-local ktrace builds expect ../kcli/build/<slot>/sdk/lib/Kcli.dll to already exist.

SDK output:

  • build/latest/sdk/lib/Ktrace.dll
  • build/latest/tests/bin/Ktrace.Tests.dll

Build And Run Demos

# Builds the SDK plus demos listed in .kbuild.json build.defaults.demos.
kbuild --build-latest

# Explicit demo-only run.
kbuild --build-demos

Demo directories:

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

Trace CLI examples:

./demo/exe/core/build/latest/test --trace
./demo/exe/core/build/latest/test --trace '.*'
./demo/exe/omega/build/latest/test --trace '*.*'
./demo/exe/omega/build/latest/test --trace '*.*.*.*'
./demo/exe/omega/build/latest/test --trace '*.{net,io}'
./demo/exe/omega/build/latest/test --trace-namespaces
./demo/exe/omega/build/latest/test --trace-channels
./demo/exe/omega/build/latest/test --trace-colors

Run Tests

dotnet build/latest/tests/bin/Ktrace.Tests.dll

Layout

  • Public API and implementation: src/
  • API tests: tests/src/
  • Demo builds: demo/

Working references:

  • src/Ktrace/TraceLogger.cs
  • src/Ktrace/Logger.cs
  • src/Ktrace/TraceSelector.cs
  • src/Ktrace/TraceFormatter.cs
  • tests/src/Ktrace.Tests/Program.cs
  • demo/sdk/alpha/src/Ktrace/Demo/Alpha/AlphaTrace.cs
  • demo/exe/core/src/Ktrace/Demo/Core/Program.cs
  • demo/exe/omega/src/Ktrace/Demo/Omega/Program.cs

API Model

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

TraceLogger trace = new TraceLogger("alpha");
trace.AddChannel("net", "DeepSkyBlue1");
trace.AddChannel("cache", "Gold3");

SDKs should usually expose a shared handle from GetTraceLogger():

private static readonly TraceLogger Trace = CreateTraceLogger();

public static TraceLogger GetTraceLogger()
{
    return Trace;
}

Logger is the executable-facing runtime. It imports one or more TraceLoggers, maintains the central channel registry, and owns filtering, formatting, and final output:

Logger logger = new Logger();

TraceLogger appTrace = new TraceLogger("core");
appTrace.AddChannel("app", "BrightCyan");
appTrace.AddChannel("startup", "BrightYellow");

logger.AddTraceLogger(appTrace);
logger.AddTraceLogger(AlphaTrace.GetTraceLogger());

Logging APIs

Channel-based trace output:

trace.Trace("channel", "message {}", value);
trace.TraceChanged("channel", key, "message {}", value);

Always-visible operational logging:

trace.Info("message");
trace.Warn("configuration '{}' was not found", path);
trace.Error("fatal startup failure");

Operational logging is independent of channel enablement. It is still namespaced and uses the same formatting options as trace output.

CLI Integration

The inline parser is logger-bound rather than global. Pass the executable's local TraceLogger so leading-dot selectors resolve against the right namespace:

Logger logger = new Logger();
TraceLogger appTrace = new TraceLogger("core");
appTrace.AddChannel("app", "BrightCyan");

logger.AddTraceLogger(appTrace);

Parser parser = new Parser();
parser.AddInlineParser(logger.MakeInlineParser(appTrace));
parser.ParseOrExit(args);

Channel Expression 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:

  • EnableChannels(...)
  • DisableChannels(...)
  • list APIs accept selector patterns such as *, {}, and CSV
  • list APIs resolve selectors against the channels currently registered at call time
  • leading-dot selectors in list APIs resolve against the provided local namespace
  • empty or whitespace selector lists are rejected
  • unregistered channels remain disabled and do not emit, even if a selector pattern would otherwise match

Examples:

  • logger.EnableChannel(appTrace, ".app");
  • logger.EnableChannel("alpha.net");
  • logger.EnableChannels("alpha.*,{beta,gamma}.net.*");
  • logger.EnableChannels(appTrace, ".net.*,otherapp.scheduler.tick");

Formatting options:

  • --trace-files
  • --trace-functions
  • --trace-timestamps

These affect both Trace(...) output and Info()/Warn()/Error() output.

Ktrace C# Documentation

ktools-csharp/ktrace/docs/index.md

ktrace is the C# implementation of the ktools tracing and logging layer.

It is built around two cooperating types:

  • TraceLogger for namespace-scoped trace sources
  • Logger for executable-facing channel registration, filtering, formatting, and output

Start Here

Typical Flow

using Kcli;
using Ktrace;

Logger logger = new Logger();
TraceLogger appTrace = new TraceLogger("core");
appTrace.AddChannel("app", "BrightCyan");

logger.AddTraceLogger(appTrace);

Parser parser = new Parser();
parser.AddInlineParser(logger.MakeInlineParser(appTrace));
parser.ParseOrExit(args);

Core Concepts

TraceLogger

  • Declares one trace namespace and its registered channels.
  • Emits channel-based trace output through Trace() and TraceChanged().
  • Emits always-visible operational logging through Info(), Warn(), and Error().
  • Applies explicit channel colors, with nested channels inheriting their nearest colored parent.

Logger

  • Imports one or more TraceLogger instances.
  • Maintains the runtime registry of namespaces and channels.
  • Enables or disables channels by exact selector or selector list.
  • Owns output formatting and the --trace-* CLI integration surface.

OutputOptions

  • Controls optional filename, line, function, and timestamp output.

TraceFormatter

  • Provides public brace-based message formatting and exposes the named color catalog used by ktrace.

Selector Model

Single-channel APIs accept:

  • .channel[.sub[.sub]] for the local namespace supplied by the caller
  • namespace.channel[.sub[.sub]] for an explicit namespace

Selector-list APIs accept:

  • *
  • brace groups such as {alpha,beta}
  • comma-separated selector lists

Examples:

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

Color Model

  • TraceLogger.AddChannel(name, colorName) accepts Default plus the xterm-style named colors shared with the C++ implementation.
  • Child channels inherit the nearest registered parent color unless they declare their own color.
  • --trace-colors prints the full available catalog at runtime.

Build And Explore

From the workspace root:

kbuild --batch --build-latest

From ktrace/ after ../kcli/ has already been built:

kbuild --build-latest
dotnet build/latest/tests/bin/Ktrace.Tests.dll
./demo/exe/omega/build/latest/test --trace '*.*'
./demo/exe/omega/build/latest/test --trace-functions

Working References

API Guide

ktools-csharp/ktrace/docs/api.md

This page summarizes the public C# API in the src/Ktrace/ implementation, primarily:

Core Types

Type Purpose
TraceLogger Namespace-scoped trace source that declares channels and emits trace/log output.
Logger Runtime registry, channel filter, formatter, and sink for one or more TraceLogger instances.
OutputOptions Output-format options shared by trace output and operational logging.
TraceFormatter Public formatting helper for brace-based trace message formatting.

TraceLogger

Construction

TraceLogger trace = new TraceLogger("alpha");

The namespace must be a non-empty selector identifier.

Channel Registration

trace.AddChannel("net");
trace.AddChannel("cache", "Gold3");
trace.AddChannel("scheduler.tick");

Rules:

  • channel depth is limited to three segments
  • nested channels require their parent channel to be registered first
  • color names are optional
  • child channels inherit the nearest registered parent color unless they override it

Trace APIs

trace.Trace("net", "connected to {}", host);
trace.TraceChanged("scheduler.tick", key, "tick {}", count);

TraceChanged() suppresses duplicate emissions for the same call site and key.

Operational Logging

trace.Info("starting up");
trace.Warn("configuration '{}' was not found", path);
trace.Error("fatal startup failure");

Operational logging is independent of channel enablement.

Query API

bool enabled = trace.ShouldTraceChannel("net");

This returns true only when the trace logger is attached to a Logger, the channel is registered, and the channel is currently enabled.

Logger

Trace Logger Registration

logger.AddTraceLogger(appTrace);
logger.AddTraceLogger(alphaTrace);

Attaching the same TraceLogger to multiple Logger instances is rejected.

Exact Channel Control

logger.EnableChannel("alpha.net");
logger.EnableChannel(appTrace, ".app");
logger.DisableChannel("alpha.net");

Exact selectors that do not match a registered channel are ignored with a warning log.

Selector-List Control

logger.EnableChannels("alpha.*,{beta,gamma}.net.*");
logger.EnableChannels(appTrace, ".net.*,otherapp.scheduler.tick");
logger.DisableChannels("*.*.*");

Rules:

  • empty selector lists are rejected
  • unmatched selectors are ignored with warning logs
  • unregistered channels remain disabled, even if a selector pattern would otherwise match them

Output Formatting

logger.SetOutputOptions(new OutputOptions
{
    Filenames = true,
    LineNumbers = true,
    FunctionNames = true,
    Timestamps = true,
});

OutputOptions options = logger.GetOutputOptions();

FunctionNames and LineNumbers only take effect when Filenames is enabled.

Registry Queries

List<string> namespaces = logger.GetNamespaces();
List<string> channels = logger.GetChannels("alpha");
bool enabled = logger.ShouldTraceChannel("alpha.net");

GetChannels() validates the namespace argument and returns sorted channel names for that namespace.

CLI Integration

Parser parser = new Parser();
parser.AddInlineParser(logger.MakeInlineParser(appTrace));

MakeInlineParser() registers the standard trace CLI surface:

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

The inline parser is logger-bound. Leading-dot selectors resolve against the namespace of the supplied local TraceLogger.

OutputOptions

Field Meaning
Filenames Include a source label in output.
LineNumbers Include source line numbers when Filenames is enabled.
FunctionNames Include member names when Filenames is enabled.
Timestamps Include compact UTC timestamps in output.

TraceFormatter

string text = TraceFormatter.FormatMessage("value {} {}", 7, "done");

Formatting rules:

  • sequential {} placeholders
  • escaped braces {{ and }}
  • bool formats as true or false
  • too few or too many arguments raise ArgumentException

TraceFormatter.ColorNames exposes Default plus the same named 256-color catalog used by the C++ implementation.

API Notes

  • TraceLogger is the library-facing type; Logger is the executable-facing runtime.
  • Channel and namespace validation is strict and intentionally aligned with the broader ktools model.
  • The docs here describe the current C# surface; the authoritative implementation lives under src/Ktrace/.

Behavior Guide

ktools-csharp/ktrace/docs/behavior.md

This page describes the ktrace runtime behavior that matters in practice.

Registration Model

TraceLogger declares namespaces and channels up front.

Rules:

  • namespaces must be non-empty selector identifiers
  • channel depth is limited to three segments
  • nested channels require their parent channel to be registered first
  • adding the same channel again is allowed when the effective color does not conflict
  • conflicting explicit colors for the same namespace and channel are rejected

Enablement Model

Logger controls runtime trace enablement.

Exact selector APIs:

  • EnableChannel(...)
  • DisableChannel(...)
  • ShouldTraceChannel(...)

Selector-list APIs:

  • EnableChannels(...)
  • DisableChannels(...)

Important details:

  • exact selectors that do not resolve to a registered channel are ignored with a warning log
  • selector lists resolve against channels registered at the time of the call
  • unmatched selectors in a list are ignored with warning logs
  • unregistered channels remain disabled, even if a wildcard selector would otherwise match them

Selector Forms

Exact selectors accept:

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

Selector lists also accept:

  • *
  • brace groups such as {alpha,beta}
  • comma-separated selector expressions

Examples:

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

Logging Behavior

TraceLogger.Trace(...)

  • emits only when the channel is registered, attached to a Logger, and enabled

TraceLogger.TraceChanged(...)

  • suppresses repeated emissions when the same call site repeats the same key
  • keeps its duplicate-suppression state per trace logger

TraceLogger.Info()/Warn()/Error()

  • always emit when the trace logger is attached to a Logger
  • do not depend on channel enablement

Colors

Color registration rules:

  • channel colors are optional
  • Default means no explicit color
  • child channels inherit the nearest registered parent color unless they declare their own color
  • the named color surface matches the C++ implementation's xterm-style catalog

Runtime behavior:

  • ANSI colors are disabled when stdout is redirected
  • --trace-colors prints the full available color catalog

Output Options

Logger.SetOutputOptions(...) controls formatting shared by trace output and operational logging.

Fields:

  • Filenames
  • LineNumbers
  • FunctionNames
  • Timestamps

Important details:

  • LineNumbers and FunctionNames only take effect when Filenames is enabled
  • --trace-files, --trace-functions, and --trace-timestamps toggle the same runtime output settings

Examples

ktools-csharp/ktrace/docs/examples.md

This page shows a few common ktrace patterns. For complete compiling examples, also see:

Minimal Executable

using Kcli;
using Ktrace;

Logger logger = new Logger();
TraceLogger appTrace = new TraceLogger("core");
appTrace.AddChannel("app", "BrightCyan");

logger.AddTraceLogger(appTrace);

Parser parser = new Parser();
parser.AddInlineParser(logger.MakeInlineParser(appTrace));
parser.ParseOrExit(args);

Imported SDK Pattern

Logger logger = new Logger();
TraceLogger appTrace = new TraceLogger("omega");
appTrace.AddChannel("app", "BrightCyan");
appTrace.AddChannel("orchestrator", "BrightYellow");

logger.AddTraceLogger(appTrace);
logger.AddTraceLogger(AlphaTrace.GetTraceLogger());
logger.AddTraceLogger(BetaTrace.GetTraceLogger());

This keeps local executable tracing separate from imported SDK trace namespaces.

Selector Examples

logger.EnableChannel(appTrace, ".app");
logger.EnableChannel("alpha.net");
logger.EnableChannels("alpha.*,{beta,gamma}.metrics");
logger.DisableChannels(appTrace, ".orchestrator");

Output Options

logger.SetOutputOptions(new OutputOptions
{
    Filenames = true,
    LineNumbers = true,
    FunctionNames = true,
    Timestamps = true,
});

This affects both Trace(...) output and Info()/Warn()/Error() output.

Color Inheritance

TraceLogger trace = new TraceLogger("alpha");
trace.AddChannel("net", "DeepSkyBlue1");
trace.AddChannel("net.retry");
trace.AddChannel("net.retry.deep");

Here, net.retry and net.retry.deep inherit DeepSkyBlue1 until a more specific color is registered.