API Reference

Source of truth: OzaLog/OzaLog/LOG.cs, generated XML doc shipped in the NuGet package as file.xml.

All public types live in the OzaLog namespace.


1. LOG static class

The single entry point for all logging. No instantiation, no LoggerFactory, no dependency injection.

using OzaLog;

LOG.Info_Log("Hello, OzaLog!");

1.1 LogLevel methods

For each LogLevel value (Trace / Debug / Info / Warn / Error / Fatal), five overloads are provided. Naming convention: <Level>_Log.

// String message
LOG.Info_Log(string message);

// Toggle file write (true=write, false=console-only when EnableConsoleOutput=true)
LOG.Info_Log(string message, bool writeTxt);

// Formatted message with {0}/{1}/... placeholders
LOG.Info_Log(string message, string[] args, bool writeTxt = true, bool immediateFlush = false);

// Object — automatically serialized to JSON
LOG.Info_Log<T>(T obj, bool writeTxt = true, bool immediateFlush = false) where T : class;

// Object with header message
LOG.Info_Log<T>(string message, T obj, bool writeTxt = true, bool immediateFlush = false) where T : class;

Replace Info with Trace, Debug, Warn, Error, or Fatal for the corresponding level.

Automatic immediate flush

Error_Log and Fatal_Log always trigger synchronous immediate flush regardless of the immediateFlush argument. This ensures crash logs reach disk before the process dies. Other levels respect the immediateFlush argument (default false).

Object overload behavior

  • When obj is Exception and level >= Warn, the object is serialized via ExceptionHandler.CreateSerializableException(...), which recursively expands InnerException, Data dictionary, StackTrace, and reflected non-standard properties.
  • Otherwise serialization goes through System.Text.Json with WriteIndented=false, DefaultIgnoreCondition=WhenWritingNull, Encoder=UnsafeRelaxedJsonEscaping.

1.2 CustomName_Log — per-bucket file

Routes the log line to a custom filename instead of the level-based default. Useful for per-symbol files in trading (BTC_Log.txt, ETH_Log.txt).

LOG.CustomName_Log(string name, string message);
LOG.CustomName_Log(string name, string message, bool writeTxt);
LOG.CustomName_Log(string name, string message, string[] args, bool writeTxt = true, bool immediateFlush = false);
LOG.CustomName_Log<T>(string name, T obj, bool writeTxt = true, bool immediateFlush = false) where T : class;
LOG.CustomName_Log<T>(string name, string message, T obj, bool writeTxt = true, bool immediateFlush = false) where T : class;

→ File path: {baseDir}/{LogPath}/{yyyyMMdd}/{CustomPath}/{name}_Log.{ext}

1.3 LOG.Configure(...) — one-time configuration

public static void Configure(Action<LogConfiguration.LogOptions> configure);

Not re-entrant. Second call throws InvalidOperationException("OzaLog 已初始化(Configure 不可重入)"). If Configure is never called, the first log write auto-initializes with default settings.

1.4 LOG.GetCurrentOptions() — read-only config view

public static LogConfiguration.ILogOptions GetCurrentOptions();

Returns a read-only wrapper around the live LogOptions. Useful for diagnostics and verifying the active configuration.


2. LOG.Quote(...) — Quote pipeline (v3.1+)

The Quote pipeline is an independent async pipeline for high-frequency tick/quote data, separate from the main logger. Field names align with the Binance REST API 24hr Ticker schema.

Prerequisite: enable the pipeline at configuration time:

LOG.Configure(o => o.ConfigureQuote(q => q.Enable = true));

Without Enable = true, all LOG.Quote(...) calls are silent no-ops (no background thread is started).

2.1 A2 core API — struct overload

public static void Quote(in QuoteRecord record);

Zero-allocation enqueue. Validates record synchronously on the calling thread and throws ArgumentException for:

  • Symbol or Bucket is null or empty
  • Extras and ExtrasJson both set
  • Extras contains a key matching a reserved field (see §2.4)

2.2 A1 convenience overloads

Internally construct a QuoteRecord and delegate to the struct overload.

// Minimal tick — last price only
LOG.Quote(string symbol, string bucket, long ticks, decimal last);

// With bid/ask
LOG.Quote(string symbol, string bucket, long ticks,
          decimal last, decimal bid, decimal ask);

// With bid/ask + sizes
LOG.Quote(string symbol, string bucket, long ticks,
          decimal last,
          decimal bid, decimal bidQty,
          decimal ask, decimal askQty);

// Full ticker — aligned with Binance REST API /api/v3/ticker/24hr
LOG.QuoteTicker(string symbol, string bucket, long ticks,
                decimal last,
                decimal? lastQty = null,
                decimal? bid = null, decimal? bidQty = null,
                decimal? ask = null, decimal? askQty = null,
                decimal? open = null, decimal? prevClose = null,
                decimal? high = null, decimal? low = null,
                decimal? volume = null, decimal? quoteVolume = null);

// Full ticker with custom Extras dictionary
LOG.QuoteTicker(string symbol, string bucket, long ticks,
                decimal last,
                IReadOnlyDictionary<string, object> extras,
                /* same optional fields as above */);

2.3 QuoteRecord (public readonly struct)

public readonly struct QuoteRecord
{
    // Required
    public readonly string Symbol;     // e.g. "BTCUSDT"
    public readonly string Bucket;     // e.g. "binance_spot"
    public readonly long   Ticks;      // event time, caller-supplied
    public readonly decimal Last;      // last trade price

    // Optional (all decimal?)
    public readonly decimal? LastQty;       // qty of last trade
    public readonly decimal? Bid, BidQty;   // best bid + qty
    public readonly decimal? Ask, AskQty;   // best ask + qty
    public readonly decimal? Open, PrevClose;
    public readonly decimal? High, Low;
    public readonly decimal? Volume;        // cumulative base asset volume
    public readonly decimal? QuoteVolume;   // cumulative quote asset volume

    // Custom fields — mutually exclusive
    public readonly IReadOnlyDictionary<string, object>? Extras;
    public readonly string? ExtrasJson;     // pre-serialized JSON object string
}

Field-name mapping to Binance /api/v3/ticker/24hr response:

QuoteRecordBinance JSONNote
LastlastPricerequired
LastQtylastQtyquantity of the most recent trade
Bid / BidQtybidPrice / bidQtybest bid quote
Ask / AskQtyaskPrice / askQtybest ask quote
Open / PrevClose / High / LowopenPrice / prevClosePrice / highPrice / lowPricesession stats
Volumevolume24h base asset volume
QuoteVolumequoteVolume24h quote asset volume

2.4 Reserved Extras keys

The following keys are reserved by the built-in schema. Putting them in Extras (Dictionary) throws ArgumentException synchronously. Putting them in ExtrasJson (string) throws asynchronously inside the dispatcher (logged to console; record is dropped).

ts, symbol, bucket, last, lastQty, bid, bidQty, ask, askQty, open, prevClose, high, low, volume, quoteVolume, extras

2.5 Filename rules

{baseDir}/{LogPath}/{yyyyMMdd}/{QuotePath}/{Bucket}_{Symbol}_Quote.{ext}
  • No nested subdirectories: Bucket becomes a filename prefix, not a folder.
  • Auto-sanitization: file-system-invalid characters (/ \ : * ? " < > |) in Symbol / Bucket are replaced with - in the filename only. The original strings are preserved in the file content.
  • Day rollover, LRU eviction, and size-based splitting (_part2_Quote.{ext} etc.) all work the same as the main logger but with their own independent QuoteFileStreamPool.

3. LogLevel enum

public enum LogLevel
{
    Trace      = 0,
    Debug      = 1,
    Info       = 2,
    Warn       = 3,
    Error      = 4,
    Fatal      = 5,
    CustomName = 99,   // used internally by LOG.CustomName_Log(...)
}

v3.0 renamed CostomNameCustomName (typo fix, breaking change). LOG.CustomName_Log(...) method was always spelled correctly.


4. LogOutputFormat enum (v3.1+)

Selects the main logger output format. Set via LogOptions.OutputFormat.

public enum LogOutputFormat
{
    Txt  = 0,   // human-readable text, .txt extension (default)
    Log  = 1,   // same content as Txt, .log extension
    Json = 2,   // NDJSON (one JSON object per line), .json extension
}

4.1 Json format schema (NDJSON)

{"ts":1715587425123,"lv":"Info","nm":"","tid":12,"tn":"MainThread","msg":"hello","data":{...}}
FieldTypeAlways present?Meaning
tslong (epoch_ms)yesevent timestamp in milliseconds since Unix epoch
lvstringyes"Trace" / "Debug" / "Info" / "Warn" / "Error" / "Fatal" / "CustomName"
nmstringyeslog name (CustomName value, or empty for level-based logs)
tidintiff ShowThreadId=truecalling thread's ManagedThreadId
tnstringiff ShowThreadName=true AND Thread.Name != nullcalling thread's Thread.Name
msgstringyesmessage text (always emitted even if empty)
dataobjectiff presentparsed JSON of the object-overload payload (Exception or arbitrary object)

5. QuoteOutputFormat enum (v3.1+)

Selects the Quote pipeline output format. Set via LogOptions.QuoteOptions.OutputFormat.

public enum QuoteOutputFormat
{
    Txt  = 0,   // human-readable key=value, .txt extension (default)
    Log  = 1,   // same content as Txt, .log extension
    Json = 2,   // NDJSON, .json extension
}

5.1 Txt / Log format

[2026-05-13 10:23:45.123] binance_spot BTCUSDT last=60123.5 bid=60123.0 ask=60124.0 bidQty=0.5 askQty=1.2
  • ISO 8601 timestamp prefix (human-readable)
  • Null optional fields are skipped (variable line length)
  • Extras dictionary entries are appended as more k=v pairs

5.2 Json format (NDJSON)

{"ts":1715587425123,"symbol":"BTCUSDT","bucket":"binance_spot","last":60123.5,"bid":60123.0,"ask":60124.0,"extras":{"funding":0.0001}}
  • ts = epoch_ms (consistent with main logger)
  • Only non-null fields are emitted
  • Extras is nested under "extras" (not flattened into top level) — keeps a clean schema boundary
  • Quote NDJSON never includes tid / tn (Quote represents market events, not program-internal events)

6. Read-only configuration view

LogConfiguration.ILogOptions current = LOG.GetCurrentOptions();
Console.WriteLine(current.OutputFormat);             // LogOutputFormat
Console.WriteLine(current.TimeFormat);               // "HH:mm:ss.fff" etc.
Console.WriteLine(current.HighPrecisionTimestamp);   // bool
Console.WriteLine(current.QuoteOptions.Enable);      // bool

See Configuration for the full list of properties.


7. Exception serialization (SerializableExceptionInfo)

When you log an Exception at Warn level or higher via Warn_Log<T>(ex) / Error_Log<T>(ex) / Fatal_Log<T>(ex), the runtime expands it into:

class SerializableExceptionInfo
{
    string Type;          // ex.GetType().FullName
    string Message;
    string Source;
    string HelpLink;
    string StackTrace;
    Dictionary<string, string> Data;             // expanded from ex.Data
    SerializableExceptionInfo InnerException;    // recursive
    Dictionary<string, string> AdditionalProperties;  // reflected non-standard props
}

The result is JSON-serialized into the log line (or the data field in Json output mode).


8. Versioning notes

  • v3.1 additions are strictly additive — no public API was removed or renamed.
  • All new options on LogOptions and the new QuoteOptions default to v3.0 behavior — existing code continues to work unchanged.
  • The new ILogOptions interface members (OutputFormat, TimeFormat, ShowThreadId, ShowThreadName, HighPrecisionTimestamp, QuoteOptions) are read-only; library consumers normally only read LOG.GetCurrentOptions(), so this is not a breaking change for typical use.