Skip to main content

BnLog

Namespace: BlazorNative.Core

The framework's one logging seam: a level threshold, a sink, and five level methods.

public static class BnLog

Inheritance ObjectBnLog
Attributes NullableContextAttribute, NullableAttribute

Fields

DefaultLevel

The threshold applied when nothing sets one — deliberately a RUNTIME default and deliberately not #if DEBUG (see the file header). Errors and warnings ship in Release; everything else does not.

public static BnLogLevel DefaultLevel;

LinePrefix

The line prefix marker the Gate B/C stderr pumps parse. One constant per language; the drift pin holds them equal.

public static string LinePrefix;

Properties

Level

The current threshold: a message at this level or MORE SEVERE (numerically lower) is emitted.

public static BnLogLevel Level { get; set; }

Property Value

BnLogLevel

Remarks:

THREE PLACES SET THIS, and the last write wins:

Assigning BnLogLevel.Unset or an out-of-range value resolves to BnLog.DefaultLevel — the same safe non-lying rule Exports.ToPlatformKind applies to the neighbouring ordinal.

Sink

The one sink every framework line goes through. (the default) means the built-in level-tagged Console.Error writer of BnLog.FormatLine(BnLogLevel, String, String).

public static Action<BnLogLevel, string, string>? Sink { get; set; }

Property Value

Action<BnLogLevel, String, String>

Remarks:

Deliberately the NARROWEST extension point that works — level, category, message. A consumer wanting structured sinks (Serilog, OpenTelemetry, JSON-per-line) builds on this; the framework does not grow an ILoggerProvider ecosystem to host them (design §12). A sink that THROWS is swallowed: a logger that faults its caller is worse than a logger that is quiet.

Methods

SetLevelFromOrdinal(Int32)

Maps a raw ordinal — the value a shell put in the init-input struct — onto the threshold.

public static void SetLevelFromOrdinal(int ordinal)

Parameters

ordinal Int32

Remarks:

Ordinal 0 (unset, i.e. a shell that predates the field and left the tail padding zero) and any out-of-range value resolve to BnLog.DefaultLevel. This is the exact shape of Exports.ToPlatformKind, and for the exact same reason: the field is filled by a hand-written mirror in two other languages.

IsEnabled(BnLogLevel)

Would a message at level be emitted?

public static bool IsEnabled(BnLogLevel level)

Parameters

level BnLogLevel

Returns

Boolean

Remarks:

Public because it is how a call site AVOIDS BUILDING a message it will not emit. Interpolation happens at the call site, before the call, so a site below the default threshold — anything on the frame/patch path — must guard itself: if (BnLog.IsEnabled(BnLogLevel.Debug)) BnLog.Debug(...).

Error(String, String)

A fault.

public static void Error(string category, string message)

Parameters

category String

message String

Error(String, String, Exception)

A fault, with the exception rendered per the current verbosity (see BnLog.FormatException(Exception, BnLogLevel)).

public static void Error(string category, string message, Exception exception)

Parameters

category String

message String

exception Exception

Warn(String, String)

A dropped wire, or a bent host contract.

public static void Warn(string category, string message)

Parameters

category String

message String

Warn(String, String, Exception)

A dropped wire, or a bent host contract.

public static void Warn(string category, string message, Exception exception)

Parameters

category String

message String

exception Exception

Info(String, String)

Success narration. Suppressed in Release.

public static void Info(string category, string message)

Parameters

category String

message String

Debug(String, String)

Developer detail. Suppressed in Release.

public static void Debug(string category, string message)

Parameters

category String

message String

Verbose(String, String)

Per-frame tracing. Suppressed in Release; guard with BnLog.IsEnabled(BnLogLevel) before building the message.

public static void Verbose(string category, string message)

Parameters

category String

message String

Write(BnLogLevel, String, String)

Emits at an arbitrary level — the entry point NativeRendererLoggerFactory uses to funnel Blazor's own ILogger calls through this one threshold.

public static void Write(BnLogLevel level, string category, string message)

Parameters

level BnLogLevel

category String

message String

FormatLine(BnLogLevel, String, String)

THE LINE FORMAT (design §5.5) — [BN|E|category] message.

public static string FormatLine(BnLogLevel level, string category, string message)

Parameters

level BnLogLevel

category String

message String

Returns

String

Remarks:

A pure function, and it has to be: Gate B/C's stderr pump sees formatted BYTES on fd 2, not levels, so it recovers the level by parsing this prefix back. A one-character drift silently downgrades every framework line to the pump's unprefixed fallback and NOTHING LOOKS BROKEN — which is why the round-trip is pinned in both directions rather than asserted in prose.

Tag(BnLogLevel)

The single-character level tag inside BnLog.FormatLine(BnLogLevel, String, String)'s prefix. BnLogLevel.Unset can never reach a line (the gate rejects it) and maps to W defensively.

public static char Tag(BnLogLevel level)

Parameters

level BnLogLevel

Returns

Char

FormatException(Exception, BnLogLevel)

Renders an exception at the given verbosity — design §7's information-disclosure rule, which LEVEL GATING ALONE DOES NOT ACHIEVE.

public static string FormatException(Exception exception, BnLogLevel verbosity)

Parameters

exception Exception

verbosity BnLogLevel

Returns

String

Remarks:

#155 ends with "no internal exception detail / paths leaked at default Release verbosity", and an Error ships in Release BY DESIGN — so gating changes which messages appear, not what is inside the ones that do. At the Release default this emits the exception TYPE, its MESSAGE and the TOP managed frame: enough to identify the fault and the component, not a map of the assembly. The full ToString() — inner chain and stack — requires BnLogLevel.Debug.

One documented exception stays verbatim and is NOT routed here: blazornative_init's failure path deliberately returns ex.ToString() to the shell, because for the real NativeAOT trim failure modes (TypeLoadException, MissingMethodException) the message alone hides the offending type. That is a one-shot boot failure on a binary that is already not going to run.