BnLog
Namespace: BlazorNative.Core
The framework's one logging seam: a level threshold, a sink, and five level methods.
public static class BnLog
Inheritance Object → BnLog
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
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
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
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
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
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.