Skip to the content.

MS.Microservice.Logging

Logging 负责应用日志上下文与后端接入,不负责业务身份验证,也不替代 Trace/Metrics。

打开 MS.Microservice.Logging.slnx: 源码在 src、对应测试在 test,设计说明在 docs。 在本目录执行 dotnet test MS.Microservice.Logging.slnx -c Release。

Core 不依赖 ASP.NET Core 或具体日志后端,AspNetCore 负责请求边界, NLog/Serilog 是可选后端。这样 Worker 可以只使用 Core,Web 可以按需选择中间件和后端, 无需为切换日志后端修改业务代码。

以下保留各包的详细注册和配置说明。


MS.Microservice.Logging

Provider-agnostic structured request logging for .NET, with first-class NLog and Serilog support.

Packages

Package Purpose
MS.Microservice.Logging.Core Ambient request log context, high-performance log extensions. No ASP.NET / NLog / Serilog dependency.
MS.Microservice.Logging.AspNetCore ASP.NET Core middleware that captures headers, timing, and status into the ambient context. Optional — skip for Worker/Console hosts.
MS.Microservice.Logging.NLog NLog provider with custom layout renderers (${requestId}, ${platformId}, ${userflag}, ${RequestDuration}, …). Supports nlog.config and automatic fallback.
MS.Microservice.Logging.Serilog Serilog provider with a RequestLogContextEnricher that pushes ambient context as structured properties. Supports appsettings.json and code configuration.

Architecture

┌─────────────────────────────────────────────────────┐
│                  Your Application                   │
├─────────────────────────────────────────────────────┤
│  MS.Microservice.Logging.AspNetCore                 │
│    - MsRequestLoggingMiddleware                     │
│    - Captures headers, timing, status               │
│    - Stores a clearable scope in AsyncLocal          │
├─────────────────────────────────────────────────────┤
│  MS.Microservice.Logging.Core                        │
│    - RequestLogContext (POCO)                        │
│    - RequestLogScope (AsyncLocal ambient context)    │
│    - LoggerExtensions (high-perf logging helpers)    │
├──────────────────┬──────────────────────────────────┤
│  NLog Provider   │  Serilog Provider                │
│  LayoutRenderers │  RequestLogContextEnricher         │
│  read from       │  reads from                       │
│  RequestLogScope │  RequestLogScope                   │
└──────────────────┴──────────────────────────────────┘

Key design: provider-agnostic ambient context

The middleware pushes a RequestLogContext through a clearable holder in AsyncLocal. Both NLog layout renderers and the Serilog enricher read from RequestLogScope.Current — they don’t know or care whether the data came from HTTP headers, gRPC metadata, or a message bus envelope. The holder is cleared when the scope ends, including for child execution contexts that inherited it. See the lifetime explanation for the distinction from storing the context directly.

Quick Start — ASP.NET Core + NLog

  1. Install packages:
dotnet add package MS.Microservice.Logging.Core
dotnet add package MS.Microservice.Logging.AspNetCore
dotnet add package MS.Microservice.Logging.NLog
  1. In Program.cs:
using MS.Microservice.Logging.AspNetCore;
using MS.Microservice.Logging.NLog;

var builder = WebApplication.CreateBuilder(args);

// Step 1 — register request logging middleware services
builder.Services.AddMsRequestLogging();

// Step 2 — configure NLog
builder.ConfigureMsNLog(options =>
{
    // options.ConfigurationFilePath = "nlog.config";   // default
    // options.MinimumLevel = LogLevel.Information;      // default
});

var app = builder.Build();

// Step 3 — add middleware (order: before endpoints, after auth if needed)
app.UseMsRequestLogging();

app.MapGet("/", () => "Hello");
app.Run();
  1. Place nlog.config in your project root (set CopyToOutputDirectory). See the sample config in src/MS.Microservice.Logging.NLog/nlog.sample.config.

  2. Send a request with headers:

curl -H "requestId: req-001" -H "platformId: mobile" -H "userflag: internal" http://localhost:5000/orders/42

NLog output includes requestId=req-001 platformId=mobile userflag=internal dur=12ms.

Quick Start — Worker/Console + NLog (no ASP.NET)

using MS.Microservice.Logging.Core;
using MS.Microservice.Logging.NLog;

var builder = Host.CreateApplicationBuilder(args);
builder.ConfigureMsNLog();

// Manually push context for background jobs
using (RequestLogScope.Push(new RequestLogContext
{
    RequestId = Guid.NewGuid().ToString("N"),
    Action = "process-order",
}))
{
    // All log events inside this block carry the context
}

Quick Start — ASP.NET Core + Serilog

using MS.Microservice.Logging.AspNetCore;
using MS.Microservice.Logging.Serilog;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMsRequestLogging();
builder.ConfigureMsSerilog(options =>
{
    // options.ReadFromConfiguration = true;  // default, reads Serilog section from appsettings.json
    // options.UseConsoleSink = true;         // default
});

var app = builder.Build();
app.UseMsRequestLogging();
app.MapGet("/", () => "Hello");
app.Run();

Customizing Header Names

builder.Services.AddMsRequestLogging(options =>
{
    options.RequestIdHeaderName = "x-request-id";
    options.PlatformIdHeaderName = "x-platform-id";
    options.UserFlagHeaderName = "x-user-flag";
    options.EmitCompletionLog = true; // set false to suppress "HTTP GET /path -> 200 in 5ms"
});

Testing

The ambient context is designed for testability:

// Unit test — no HttpContext needed
using (RequestLogScope.Push(new RequestLogContext
{
    RequestId = "test-001",
    ElapsedMilliseconds = 42,
}))
{
    var renderer = new RequestDurationLayoutRenderer();
    var sb = new StringBuilder();
    renderer.Append(sb, LogEventInfo.CreateNullEvent());
    sb.ToString().Should().Be("42ms");
}

From this module directory, test projects exist for all four packages under test/. Run with:

dotnet test test/MS.Microservice.Logging.Core.Tests
dotnet test test/MS.Microservice.Logging.AspNetCore.Tests
dotnet test test/MS.Microservice.Logging.NLog.Tests
dotnet test test/MS.Microservice.Logging.Serilog.Tests

Package Dependencies (Consumer View)

Host Type Required Packages
ASP.NET Core Core + AspNetCore + one of NLog / Serilog
Worker / Console Core + one of NLog / Serilog (no AspNetCore)
Library / Shared Core only (for LoggerExtensions and RequestLogScope)