NeonLog.CSharp
0.1.0-ci.78
dotnet add package NeonLog.CSharp --version 0.1.0-ci.78
NuGet\Install-Package NeonLog.CSharp -Version 0.1.0-ci.78
<PackageReference Include="NeonLog.CSharp" Version="0.1.0-ci.78" />
<PackageVersion Include="NeonLog.CSharp" Version="0.1.0-ci.78" />
<PackageReference Include="NeonLog.CSharp" />
paket add NeonLog.CSharp --version 0.1.0-ci.78
#r "nuget: NeonLog.CSharp, 0.1.0-ci.78"
#:package NeonLog.CSharp@0.1.0-ci.78
#addin nuget:?package=NeonLog.CSharp&version=0.1.0-ci.78&prerelease
#tool nuget:?package=NeonLog.CSharp&version=0.1.0-ci.78&prerelease
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 | Versions 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. |
-
.NETStandard 2.0
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 8.0.0)
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 | 51 | 6/8/2026 |
| 0.1.0-ci.75 | 52 | 6/8/2026 |
| 0.1.0-ci.73 | 64 | 6/5/2026 |
| 0.1.0-ci.70 | 64 | 6/5/2026 |
| 0.1.0-ci.66 | 59 | 6/4/2026 |
| 0.1.0-ci.64 | 66 | 6/4/2026 |
| 0.1.0-ci.63 | 54 | 6/4/2026 |
| 0.1.0-ci.61 | 67 | 6/3/2026 |
| 0.1.0-ci.60 | 50 | 6/3/2026 |
| 0.1.0-ci.58 | 57 | 6/3/2026 |
| 0.1.0-ci.55 | 56 | 6/3/2026 |
| 0.1.0-ci.54 | 51 | 6/2/2026 |
| 0.1.0-ci.53 | 46 | 6/2/2026 |
| 0.1.0-ci.51 | 47 | 6/2/2026 |
| 0.1.0-ci.49 | 54 | 6/2/2026 |
| 0.1.0-ci.46 | 49 | 6/2/2026 |
| 0.1.0-ci.40 | 49 | 6/2/2026 |