Skip to content

Releases: Dtronix/Logsmith

Logsmith v0.6.0 Released

Choose a tag to compare

@github-actions github-actions released this 17 Apr 16:13

Logsmith v0.6.0 Release Notes

Highlights

This release introduces a new ILogger API alongside the existing [LogMessage] source-generator pattern, both unified under a single dispatch pipeline. It also delivers a zero-allocation hot path for enabled log calls, DPanic correctness guards, structured timing operations, and a full DocFX documentation site at dtronix.github.io/Logsmith.


New Features

ILogger API with Compile-Time Interceptors

A new ergonomic logging surface built on C# interpolated string handlers and source-generator interceptors. Both the attribute-driven [LogMessage] pattern and the ILogger API now flow through the same unified ILogSink / DispatchInfo pipeline.

ILogger logger = LoggerContext.Root.GetLogger("MyService");
logger.Information($"Processing {count} items for user {userId}");
logger.When(condition).Debug($"Diagnostic: {expensiveValue}");
using (logger.Scoped("RequestId", requestId)) { /* ... */ }
using (logger.TimedOperation("ProcessOrder")) { /* ... */ }
  • ILogger, ILogger<T>, NullLogger — core interface plus typed and null-object variants
  • LoggerContext — hierarchical path resolution with cached UTF-8 path bytes
  • LogScope — struct-based scoped property push/pop (replaces the prior AsyncLocal type)
  • TimingOperation — disposable timer that emits operation/outcome/elapsed_ms as structured JSON
  • Static Log classLog.Information(...) etc. with [Conditional]-stripped call sites at Trace/Debug
  • Generator Stage 2 interceptors — bake caller info, event IDs, and chain carrier propagation into call sites at compile time
  • New diagnostic LSMITH013 — flags broken chains where chain method results are stored in a variable

DPanic Correctness Guards

ILogger gains four DPanic overloads (string + handler, with/without exception). DPanic dispatches at Error level and optionally throws via the new ThrowOnDPanic config flag — useful for "this should never happen" assertions that are loud in development and observable in production.

builder.ThrowOnDPanic = true; // typically dev/test only
logger.DPanic($"Unexpected state: {state}");

Log Static Exception Overloads

Four new exception overloads on the static Log class (Trace, Debug, Information, Warning) round out the existing Error/Critical pattern, all with appropriate [Conditional] attributes.

DI Integration

Logsmith.Extensions.Logging adds services.AddLogsmith(...) for native Logsmith DI registration, separate from the existing MEL bridge.

DocFX Documentation Site

A full DocFX-based documentation site replaces the previously inline README content. Published to GitHub Pages on every push to master, with auto-generated API reference for Logsmith and Logsmith.Extensions.Logging.

  • 12 articles covering installation, modes, sinks, formatting, scoped context, performance, testing, MEL bridge, and configuration
  • Internals section covering architecture and compile-time diagnostics
  • README slimmed from ~1,400 lines to ~110

Performance

Hot-path allocations introduced by the ILogger rework have been eliminated:

  • LogHandlerCoreArrayBufferWriter<byte> and Utf8JsonWriter instances are now pooled via [ThreadStatic] slots in ThreadBuffer. Removes 2–3 heap allocations per enabled log call after thread-local warmup.
  • PathNode.WriteUtf8Path — eliminates a string[] heap allocation via a two-pass offset algorithm that writes directly into the destination span.
  • LoggerContext.GetCachedPathBytes — adds acquire/release Volatile.Read/Write ordering on the cached path version to ensure a thread observing the new version also observes the corresponding byte array.

Result: zero-allocation hot path for enabled log calls (after warmup); [Conditional]-stripped sites compile to nothing at all. Validated by new ConditionalStrippingTests that assert IL-level call-site removal via PEReader/MetadataReader.


Breaking Changes

The unified dispatch pipeline reshapes the sink and formatter contracts. Custom sinks and formatters require updates.

  • ILogSink.Write signature changed: Write(in LogEntry, ReadOnlySpan<byte>)Write(in DispatchInfo)
  • LogEntry removed — replaced by DispatchInfo (structured data is exposed via info.Utf8Json)
  • IStructuredLogSink removed — folded into the unified ILogSink (any sink can opt into structured payloads through DispatchInfo)
  • IStructuredLogsmithLogger removed (Abstraction mode) — the abstraction surface is now ILogsmithLogger plus the new ILogger interface
  • WriteProperties<TState> removed — structured property writes now flow through the JSON path on DispatchInfo
  • StructuredPathEmitter removed — structured JSON emission is now inline in MethodEmitter
  • LogScope (the prior AsyncLocal type) replaced with the new struct-based LogScope. Use logger.Scoped(...) instead of LogScope.Push() / LogScope.Current.
  • ILogFormatter signature updated to accept DispatchInfo

Note: README anchor links from prior versions (e.g., #sinks, #log-levels-and-conditional-compilation) no longer resolve — that content now lives at dtronix.github.io/Logsmith.


Migration Guide

  1. Custom sinks — implement Write(in DispatchInfo info); read structured JSON from info.Utf8Json if needed:

    public void Write(in DispatchInfo info)
    {
        // info.Level, info.Timestamp, info.Message (Utf8 span), info.Utf8Json
    }
  2. Structured sinks — drop IStructuredLogSink; the same sink implementation now handles both text and structured payloads via DispatchInfo.

  3. Custom formatters — update ILogFormatter methods to accept DispatchInfo.

  4. Scoped context — replace LogScope.Push("key", value) with logger.Scoped("key", value). The struct-based scope is allocation-free.

  5. Abstraction mode consumers — replace references to IStructuredLogsmithLogger and WriteProperties<TState> with ILogger plus interpolated string handlers.

  6. ProjectReference consumers of the generator — add the interceptor namespace to your csproj to opt into Stage 2 interceptors:

    <PropertyGroup>
        <InterceptorsNamespaces>$(InterceptorsNamespaces);Logsmith.Generated</InterceptorsNamespaces>
    </PropertyGroup>
  7. DPanic — opt into throw behavior in development/test builds:

    builder.ThrowOnDPanic = true;

Other Changes

  • Sample projects updated to demonstrate the ILogger API alongside [LogMessage]
  • MEL bridge updated for the unified dispatch path (heap fallback for messages exceeding the thread-local buffer)
  • DefaultLogFormatter made bounds-safe for partial buffers
  • Source-generator emitted .g.cs files no longer tracked in source control (**/Generated/, *.g.cs added to .gitignore)

Full Changelog: v0.5.0...v0.6.0

Logsmith v0.5.0 Released

Choose a tag to compare

@github-actions github-actions released this 20 Mar 20:02

Logsmith v0.5.0 Release Notes

Highlights

This release introduces explicit mode selection via the <LogsmithMode> MSBuild property, Abstraction Mode for library authors, and restructures Logsmith.Generator as a thin meta-package.


New Features

Unified <LogsmithMode> Property

Mode selection is now controlled by a single MSBuild property:

Mode Default for Description
Shared Logsmith package Uses public types from the runtime assembly
Standalone Logsmith.Generator package Emits all types as internal, zero runtime dependency
Abstraction Explicit opt-in Public logging interfaces for library authors, internal infrastructure
<PropertyGroup>
    <LogsmithMode>Standalone</LogsmithMode>
</PropertyGroup>

Abstraction Mode for Library Authors

Library authors can now expose a logging contract without imposing Logsmith.dll on consumers. The generator emits public interfaces in a configurable namespace while keeping all infrastructure internal.

  • ILogsmithLogger — text-only logging interface
  • IStructuredLogsmithLogger — extends with typed property access via WriteProperties<TState>
  • LogsmithOutput.Logger — static wiring point for consumers
  • Configurable namespace via <LogsmithNamespace> or defaults to {RootNamespace}.Logging
  • New diagnostic LSMITH008: warns when ILogSink explicit sink parameter is used in abstraction mode (use ILogsmithLogger instead)

Package Restructuring

  • Logsmith now ships both the runtime DLL (lib/) and the source generator (analyzers/dotnet/cs/), plus .props files in build/ and buildTransitive/
  • Logsmith.Generator is now a thin meta-package with no DLLs — depends on Logsmith with asset filtering (analyzers and build assets only)
  • NuGet props evaluation order ensures correct default precedence: Shared when both packages are present

PrivateAssets Build Validation (LSMITH010)

A new build warning is emitted when LogsmithMode is Standalone or Abstraction but the Logsmith package reference is missing PrivateAssets="all". This prevents accidental leaking of the runtime DLL to consumers.


Breaking Changes

  • Logsmith.Generator package model changed — it is now a meta-package depending on Logsmith with asset filtering, not a standalone analyzer package. The package reference no longer needs OutputItemType="Analyzer" or ReferenceOutputAssembly="false".
  • Mode is now property-driven — the generator no longer auto-detects Shared vs Standalone from assembly references. Mode is determined by <LogsmithMode>.

Migration Guide

  1. Standalone mode is now explicit (previously auto-detected from missing assembly reference):

    • If using Logsmith.Generator package: no change needed (defaults to Standalone)
    • If using Logsmith package in standalone mode: add <LogsmithMode>Standalone</LogsmithMode>
  2. Add PrivateAssets="all" when using Standalone or Abstraction mode:

    <PackageReference Include="Logsmith" Version="0.5.0" PrivateAssets="all" />
  3. Logsmith.Generator package reference simplified:

    <!-- Before -->
    <PackageReference Include="Logsmith.Generator" Version="0.4.2"
        OutputItemType="Analyzer"
        ReferenceOutputAssembly="false" />
    
    <!-- After -->
    <PackageReference Include="Logsmith.Generator" Version="0.5.0" />

Other Changes

  • Updated GitHub Actions to v5 for Node.js 24 compatibility
  • Added structured logging demonstrations to all sample projects
  • Updated README with Operating Modes, Abstraction Mode, and Flushing/Shutdown documentation

Full Changelog: v0.4.2...v0.5.0

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 05 Mar 20:35

What's Changed

  • Fix STA sync-context deadlock in Shutdown() and Dispose() by @DJGosnell in #17

Full Changelog: v0.4.1...v0.4.2

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 05 Mar 19:55

What's Changed

  • Fix CS0315 for non-IUtf8SpanFormattable types (bool, enum, custom structs) by @DJGosnell in #16

Full Changelog: v0.4.0...v0.4.1

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 03 Mar 20:03

What's Changed

  • Add LogManager shutdown, sink ownership, and drain timeout by @DJGosnell in #12
  • Add IFlushableLogSink interface and LogManager.FlushAsync by @DJGosnell in #13
  • Move CaptureUnhandledExceptions into config builder by @DJGosnell in #14
  • Add BufferedLogSink drop visibility (counter + error handler) by @DJGosnell in #15

Full Changelog: v0.3.2...v0.4.0

v0.3.2

Choose a tag to compare

@github-actions github-actions released this 20 Feb 14:40

What's Changed

  • Fix silent data loss when log message exceeds stackalloc buffer by @DJGosnell in #7

Full Changelog: v0.3.1...v0.3.2

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 19 Feb 19:10

What's Changed

  • Fix ANSI escape codes leaking into redirected console output by @DJGosnell in #6
  • Add benchmark warmup/iteration caps, scoped context benchmark, and results doc by @DJGosnell in #5

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 19 Feb 03:47

What's Changed

  • Add scoped context, sampling, dynamic levels, exception handler, and MEL bridge by @DJGosnell in #4

Full Changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 19 Feb 03:44

What's Changed

  • Add class modifier and nesting support to source generator by @DJGosnell in #2
  • Add generic SetMinimumLevel() and per-category filtering by @DJGosnell in #1
  • Perf: reduce allocations and syscalls in hot logging paths by @DJGosnell in #3

Full Changelog: v0.1.3...v0.2.0

v0.1.3

Choose a tag to compare

@github-actions github-actions released this 18 Feb 22:40

Full Changelog: v0.1.2...v0.1.3