NeonLog.CSharp 0.1.0-ci.73

This is a prerelease version of NeonLog.CSharp.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package NeonLog.CSharp --version 0.1.0-ci.73
                    
NuGet\Install-Package NeonLog.CSharp -Version 0.1.0-ci.73
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NeonLog.CSharp" Version="0.1.0-ci.73" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NeonLog.CSharp" Version="0.1.0-ci.73" />
                    
Directory.Packages.props
<PackageReference Include="NeonLog.CSharp" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NeonLog.CSharp --version 0.1.0-ci.73
                    
#r "nuget: NeonLog.CSharp, 0.1.0-ci.73"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NeonLog.CSharp@0.1.0-ci.73
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NeonLog.CSharp&version=0.1.0-ci.73&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=NeonLog.CSharp&version=0.1.0-ci.73&prerelease
                    
Install as a Cake Tool

C# Wrapper for neonlog-c

This directory contains a thin C# P/Invoke wrapper for the native neonlog-c library (see include/neonlog/neonlog.h). It exposes the full native ABI through managed types, supports structured message templates, built-in enrichers, log scopes, HTTP request context, Redis and console sinks, and integrates with Microsoft.Extensions.Logging.

Projects

Project Target Description
NeonLog.CSharp netstandard2.0 Managed wrapper assembly — public API, P/Invoke interop, enrichers, scope, HTTP context. Packed as NuGet with bundled win-x64 and linux-x64 native assets.
NeonLog.CSharp.AspNetCore net8.0 ASP.NET Core request logging middleware. Writes structured completion events per request with dynamic level selection. Populates NeonLogHttpRequestContext for downstream enrichers.
NeonLog.CSharp.Sample net8.0 Console app that reads appsettings.json and exercises the factory + Redis + ILogger integration.
NeonLog.CSharp.PackageTests net8.0 xUnit consumer tests that reference the packed NuGet (not the source project). Run after packing.
NeonLog.CSharp.Examples net8.0 Example tour demonstrating every API feature — see examples/ directory.

Quick start

Build the native library and run the examples:

cmake -S . -B build
cmake --build build --config Debug
# Make neonlog.dll discoverable (add build/Debug/ to PATH, or copy next to the managed exe):
$env:PATH += ";$pwd\build\Debug"
dotnet run --project bindings/dotnet/examples/NeonLog.CSharp.Examples.csproj

API Reference

1. Core Types

NeonLogLevel — log severity (0–5)
Value Name Meaning
0 Verbose Detailed diagnostic trace
1 Debug Debugging information
2 Information Normal application progress
3 Warning Potential issue
4 Error Recoverable failure
5 Fatal Unrecoverable / critical
NeonLogValue — typed log value

Wraps the native neonlog_value_t union. Supports implicit conversions from common .NET types:

NeonLogValue v1 = "hello";     // String
NeonLogValue v2 = -42L;        // Int64
NeonLogValue v3 = 42UL;        // UInt64
NeonLogValue v4 = 3.14;        // Double
NeonLogValue v5 = true;        // Bool
NeonLogValue v6 = NeonLogValue.Null; // Null

// Smaller integer types widen automatically:
int i = 123;    -> Int64
uint u = 456;   -> UInt64
short s = 7;    -> Int64
float f = 2.5f; -> Double
NeonLogProperty — named property
new NeonLogProperty("UserName", "Alice")
new NeonLogProperty("Count", 42L)
new NeonLogProperty("Enabled", true)
NeonLogStatus — native operation result
Value Meaning
Ok Success
InvalidArgument Null or out-of-range parameter
OutOfMemory Allocation failure
NotSupported Feature not yet implemented
IoError Socket / file error
NeonLogRedisMode — Redis data structure
Value Meaning
Stream XADD (stream, default)
List RPUSH (list)

2. Runtime: NeonLogRuntime

uint abiVersion = NeonLogRuntime.GetAbiVersion();           // e.g. 3
NeonLogRuntime.EnsureCompatibleAbi();                        // throws if mismatch
string statusName = NeonLogRuntime.GetStatusName(status);    // "OK", "INVALID_ARGUMENT"...
string levelName  = NeonLogRuntime.GetLevelName(level);      // "INF", "ERR"...

3. Direct Logger: NeonLogger (simple API)

Create a standalone logger with NeonLogger.Create(NeonLogLoggerOptions):

var options = new NeonLogLoggerOptions
{
    MinimumLevel = NeonLogLevel.Debug,
    ConsoleEnabled = true,
};
options.Properties.Add(new NeonLogProperty("App", "my-app"));
options.Enrichers.Add(NeonLogBuiltInEnricher.Timestamp);

using var logger = NeonLogger.Create(options);

Log methods:

logger.Log(NeonLogLevel.Information, "Hello {Name}", "world");
logger.Verbose("Verbose {X}", 1);
logger.Debug("Debug {Flag}", true);
logger.Information("User {Name} logged in", "Alice");
logger.Warning("Warning {Value}", 0.95);
logger.Error("Error {Code}", 500, "TimeoutException: ...");
logger.Fatal("Fatal {Reason}", "out of memory");

// With errorMessage (exception detail):
logger.Log(NeonLogLevel.Error, "Query failed for {Id}", "qry-1", "Timeout after 30s");

Other members:

bool enabled = logger.IsEnabled(NeonLogLevel.Debug);
using var child = logger.ForContext(new NeonLogProperty("Scope", "handler"));
using IDisposable scope = logger.BeginScope(new NeonLogProperty("Tenant", "acme"));
logger.Flush();
logger.Dispose();

4. Factory Logger: NeonLoggerFactory (advanced API)

Manages a shared native pipeline (sinks + static properties). Creates multiple loggers from it:

var factoryOptions = new NeonLogLoggerFactoryOptions
{
    MinimumLevel = NeonLogLevel.Debug,
};
factoryOptions.Properties.Add(new NeonLogProperty("Application", "my-app"));
factoryOptions.ConsoleSinks.Add(new NeonLogConsoleSinkOptions { Enabled = true, UseColors = true });
factoryOptions.RedisSinks.Add(new NeonLogRedisSinkOptions { Host = "127.0.0.1", Key = "neonlog:app", ... });

using var factory = NeonLoggerFactory.Create(factoryOptions);
using var logger = factory.CreateLogger();
using var child = logger.ForContext(new NeonLogProperty("Scope", "request"));

// Flush at the factory level drains all loggers.
factory.Flush();
NeonLogConsoleSinkOptions
Property Type Default Description
Enabled bool true Enable this sink
UseColors bool true ANSI color output
StderrMinLevel NeonLogLevel Error Messages at or above this level go to stderr
OutputTemplate string? null Custom format, e.g. "[{timestamp}] [{level}] {message}"
NeonLogRedisSinkOptions
Property Type Default Description
Enabled bool true Enable this sink
Host string "127.0.0.1" Redis hostname
Port ushort 6379 Redis port
Password string? null AUTH password
Database int 0 Redis DB index
Key string "neonlog" List or stream key
Mode NeonLogRedisMode List List (RPUSH) or Stream (XADD)
StreamMaxLength uint 0 Max stream length (0 = no trim)
TtlSeconds uint 0 TTL per entry (0 = no expiry)
BatchSize uint 100 Events per batch flush
FlushIntervalMilliseconds uint 1000 Periodic flush interval
ConnectTimeoutMilliseconds uint 0 Socket connect timeout
FallbackToConsoleOnFailure bool false Emit to console if Redis unreachable
MaxBufferedEvents uint 0 Buffer cap before dropping (0 = unlimited)

5. Built-in Enrichers: NeonLogBuiltInEnricher

Enrichers add properties automatically to every log event. There are 4 types:

Enum Value Config Name Properties Added When Resolved
Timestamp "Timestamp" Timestamp (ISO 8601) Per event
ProcessInfo "ProcessInfo" ProcessId, MachineName Once at plan creation
Environment "Environment" Environment (from DOTNET_ENVIRONMENT / ASPNETCORE_ENVIRONMENT / NODE_ENV / "development") Once at plan creation
LogScope "LogScope" All active scope properties Per event
HttpRequest "HttpRequest" RequestMethod, RequestPath, RequestId, UserAgent, ClientIp, ContentType, Host, Protocol, StatusCode Per event

Usage:

options.Enrichers.Add(NeonLogBuiltInEnricher.Timestamp);
options.Enrichers.Add(NeonLogBuiltInEnricher.ProcessInfo);
options.Enrichers.Add(NeonLogBuiltInEnricher.Environment);
options.Enrichers.Add(NeonLogBuiltInEnricher.LogScope);
options.Enrichers.Add(NeonLogBuiltInEnricher.HttpRequest);

6. Scopes: NeonLogScope

Push ambient properties onto an AsyncLocal stack. Paired with the LogScope enricher.

using (logger.BeginScope(new NeonLogProperty("RequestId", "req-123")))
using (NeonLogScope.Push(new NeonLogProperty("Tenant", "acme")))
{
    // Both properties are attached to every log event within this scope.
    logger.Information("Processing order {OrderId}", 42);
}

// Run a callback within a scope:
NeonLogScope.Run(new[] { new NeonLogProperty("Scope", "test") }, () =>
{
    logger.Information("Inside scope");
});

7. HTTP Request Context: NeonLogHttpRequestContext

Attach HTTP request data to the ambient AsyncLocal context. Requires the HttpRequest enricher.

var request = new NeonLogHttpRequestData
{
    RequestMethod = "POST",
    RequestPath = "/api/orders",
    RequestId = "req-abc",
    UserAgent = "MyClient/1.0",
    ClientIp = "10.0.0.1",
    Host = "example.com",
};

using (NeonLogHttpRequestContext.Enter(request))
{
    logger.Information("Processing order");
    NeonLogHttpRequestContext.SetStatusCode(200);
}

// Async variant:
await NeonLogHttpRequestContext.RunAsync(request, async () =>
{
    logger.Information("Inside async context");
    await Task.CompletedTask;
});

8. ASP.NET Core Request Logging Middleware: NeonLog.CSharp.AspNetCore

A separate package that integrates with the ASP.NET Core pipeline. Writes a structured completion log event for every HTTP request.

Registration
using NeonLog.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Register NeonLog as the logging provider
builder.Logging.AddNeonLog(builder.Configuration.GetSection("NeonLog"));

var app = builder.Build();

// Add the middleware early in the pipeline (after error handling, before routing)
app.UseNeonLogRequestLogging();

app.MapControllers();
app.Run();
Dynamic log level

The GetLevel delegate receives the HttpContext, elapsed time in milliseconds, and any exception. Default logic matches the Serilog UseSerilogRequestLogging example:

app.UseNeonLogRequestLogging(options =>
{
    options.GetLevel = (httpContext, elapsedMs, ex) =>
    {
        if (ex != null) return NeonLogLevel.Error;
        if (httpContext.Response.StatusCode > 499) return NeonLogLevel.Error;

        var path = httpContext.Request?.Path.Value?.ToLowerInvariant();
        if (path == "/" || (path?.StartsWith("/health") ?? false))
            return NeonLogLevel.Verbose;

        return NeonLogLevel.Information;
    };
});
Enrichment

Custom properties from HttpContext can be added via EnrichDiagnosticContext:

app.UseNeonLogRequestLogging(options =>
{
    options.EnrichDiagnosticContext = (props, ctx) =>
    {
        props["CorrelationId"] = ctx.TraceIdentifier;
    };
});

Because the middleware populates NeonLogHttpRequestContext, the HttpRequest enricher automatically attaches request properties (method, path, user-agent, client IP, status code, elapsed) to every downstream log event within the request scope.

Options
Member Type Default Description
GetLevel Func<HttpContext, long, Exception?, NeonLogLevel>? Adaptive default Log level per request
EnrichDiagnosticContext Action<IDictionary<string, object?>, HttpContext>? null Extra properties from HttpContext
MessageTemplate string "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {ElapsedMilliseconds}ms" Structured template

9. Configuration from IConfiguration: NeonLogConfigurationOptions

Parse the "NeonLog" config section (appsettings.json, env vars, etc.) into typed options:

var section = config.GetSection("NeonLog");
var options = NeonLogConfigurationOptions.FromConfiguration(section);
var factoryOptions = options.ToFactoryOptions();

Accepts both wrapper-native sections (ConsoleSinks, RedisSinks, Properties, Enrich) and the original NeonLog compatibility shape (WriteTo, Properties object map, Enrich string array).

Example appsettings.json:

{
  "NeonLog": {
    "MinimumLevel": { "Default": "Debug" },
    "Properties": { "Application": "my-app" },
    "Enrich": ["Timestamp", "ProcessInfo", "Environment", "LogScope"],
    "ConsoleSinks": [
      {
        "Enabled": true,
        "UseColors": true,
        "OutputTemplate": "[{timestamp}] [{level}] {message}"
      }
    ],
    "RedisSinks": [
      {
        "Enabled": false,
        "Host": "127.0.0.1",
        "Key": "neonlog:app",
        "Mode": "Stream"
      }
    ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": { "useColors": "true", "outputTemplate": "[{level}] {message}" }
      }
    ]
  }
}

10. Microsoft.Extensions.Logging Integration

Register NeonLog as the standard ILogger<T> provider:

// Option A: from config section
builder.Logging.AddNeonLog(builder.Configuration.GetSection("NeonLog"));

// Option B: from delegate
builder.Logging.AddNeonLog(options =>
{
    options.MinimumLevel = NeonLogLevel.Debug;
    options.Enrich.Add("Timestamp");
});

// Option C: from factory options directly
builder.Logging.AddNeonLog(factoryOptions);

Mapping from ILogger<T>:

Microsoft.Extension Native equivalent
ILogger<T> category SourceContext property
Structured message template Native neonlog_logger_log template + arguments
BeginScope properties Per-event context properties (merged with LogScope enricher)
EventId.Id EventId property
EventId.Name EventName property
LogLevel.Trace Verbose
LogLevel.Debug Debug
LogLevel.Information Information
LogLevel.Warning Warning
LogLevel.Error Error
LogLevel.Critical Fatal

11. Error Handling

All native operations throw NeonLogException on failure:

try
{
    using var logger = NeonLogger.Create(options);
    logger.Information("Hello");
}
catch (NeonLogException ex)
{
    Console.WriteLine($"Operation failed: {ex.Message}");
    Console.WriteLine($"Status code: {ex.Status}");
}

The runtime also validates ABI compatibility at the start of every creation method. If the loaded native library reports a different ABI version than the wrapper expects, EnsureCompatibleAbi() throws NotSupportedException.


12. NuGet Packaging

Stage native assets for both platforms, then pack:

# Windows:
./bindings/dotnet/scripts/build-and-stage-native.ps1 -Configuration Release

# Linux:
./bindings/dotnet/scripts/build-and-stage-native.sh Release

# Pack (requires both win-x64 and linux-x64 staged):
dotnet pack bindings/dotnet/NeonLog.CSharp/NeonLog.CSharp.csproj -c Release

The package version defaults to 0.1.0 (from Directory.Build.props). Override with:

dotnet pack ... /p:NeonLogPackageVersion=1.0.0

The pack target fails fast if either native asset is missing.

Packing NeonLog.CSharp.AspNetCore
dotnet pack bindings/dotnet/NeonLog.CSharp.AspNetCore/NeonLog.CSharp.AspNetCore.csproj -c Release

The AspNetCore package has no native assets — it depends on NeonLog.CSharp for the native runtime. Both packages are produced by CI and published to GitHub Packages on version tags.

13. Running Tests

Package consumer tests validate against the packed NuGet (not source):

# After packing:
dotnet test bindings/dotnet/NeonLog.CSharp.PackageTests/NeonLog.CSharp.PackageTests.csproj -c Release

Examples

The examples/ project contains self-contained, runnable examples:

File Demonstrates
Example01_DirectLogger.cs Direct logger creation, all level methods, IsEnabled, Flush
Example02_FactoryLogger.cs Factory API, child loggers via ForContext, custom output template
Example03_AllValueKinds.cs All NeonLogValue types and implicit conversions
Example04_EnrichersAndScopes.cs 4 built-in enrichers, BeginScope, nested scopes
Example05_HttpRequestContext.cs HttpRequest enricher, Enter, SetStatusCode
Example06_RedisSink.cs Redis List and Stream sink configuration
Example07_ConfigurationFromJson.cs IConfiguration parsing, FromConfiguration, ToFactoryOptions
Example08_MicrosoftLogging.cs Microsoft.Extensions.Logging integration with ILogger<T>

Run:

dotnet run --project bindings/dotnet/examples/NeonLog.CSharp.Examples.csproj

Build from source

# 1. Build the native library
cmake -S . -B build
cmake --build build --config Debug

# 2. Make neonlog.dll discoverable
$env:PATH += ";$pwd\build\Debug"

# 3. Build and run the sample
dotnet run --project bindings/dotnet/NeonLog.CSharp.Sample/NeonLog.CSharp.Sample.csproj

# 4. Build and run the examples
dotnet run --project bindings/dotnet/examples/NeonLog.CSharp.Examples.csproj

# 5. Stage native assets + pack NuGet (requires .NET 8 SDK)
./bindings/dotnet/scripts/build-and-stage-native.ps1 -Configuration Release
dotnet pack bindings/dotnet/NeonLog.CSharp/NeonLog.CSharp.csproj -c Release

# 6. Run package consumer tests
dotnet test bindings/dotnet/NeonLog.CSharp.PackageTests/NeonLog.CSharp.PackageTests.csproj -c Release
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on NeonLog.CSharp:

Package Downloads
NeonLog.CSharp.AspNetCore

ASP.NET Core request logging middleware for neonlog-c.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-ci.78 0 6/8/2026
0.1.0-ci.75 0 6/8/2026
0.1.0-ci.73 53 6/5/2026
0.1.0-ci.70 55 6/5/2026
0.1.0-ci.66 51 6/4/2026
0.1.0-ci.64 57 6/4/2026
0.1.0-ci.63 46 6/4/2026
0.1.0-ci.61 59 6/3/2026
0.1.0-ci.60 42 6/3/2026
0.1.0-ci.58 49 6/3/2026
0.1.0-ci.55 48 6/3/2026
0.1.0-ci.54 42 6/2/2026
0.1.0-ci.53 38 6/2/2026
0.1.0-ci.51 39 6/2/2026
0.1.0-ci.49 46 6/2/2026
0.1.0-ci.46 41 6/2/2026
0.1.0-ci.40 40 6/2/2026