Skip to content

Integration Guides

thushxr edited this page Jun 27, 2026 · 1 revision

Integration Guides

Thushar.Logging works the same everywhere: configure once at startup, then log. Below are copy-paste setups for the most common hosts.


Console / Worker app

Configure at the top of Main, then use the logger anywhere:

using Thushar.Logging;

Log.Configure(o => o
    .SetMinimumLevel(LogLevel.Debug)
    .AddTraceId());

Log.Information("Worker starting");

using (Log.BeginTraceScope())
{
    Log.Debug("Loading config");
    Log.Information("Ready");
}

For production/cloud, switch to JSON so your aggregator can parse it:

Log.Configure(o => o.UseStructured());

ASP.NET Core / Web API

Configure in Program.cs, then add a tiny middleware that opens a trace scope per request so every log line in a request shares one id.

using Thushar.Logging;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// 1. Configure the static logger once at startup.
Log.Configure(o => o
    .UseStructured()
    .SetMinimumLevel(LogLevel.Information)
    .AddTraceId());

// 2. One trace scope per request. Reuse an incoming correlation id if present.
app.Use(async (context, next) =>
{
    var correlationId = context.Request.Headers["X-Correlation-ID"].FirstOrDefault()
                        ?? context.TraceIdentifier;

    using (Log.BeginTraceScope(correlationId))
    {
        Log.Information("{method} {path}", context.Request.Method, context.Request.Path);
        await next();
        Log.Information("Responded {statusCode}", context.Response.StatusCode);
    }
});

app.MapGet("/orders/{id}", (int id) =>
{
    Log<OrdersEndpoint>.Information("Fetching order");   // adds class + method
    return Results.Ok(new { id });
});

app.Run();

class OrdersEndpoint { }

Every line within a request now carries the same traceId, so you can pull up the full story of a single request in your log tool.


AWS Lambda

Lambda has no DI container, which is exactly where a static logger shines. Configure in the function constructor — it runs once on cold start and is reused across warm invocations — then open a trace scope per invocation using the request id.

using Amazon.Lambda.Core;
using Thushar.Logging;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace MyLambda;

public class Function
{
    public Function()
    {
        // Runs on cold start. JSON is ideal for CloudWatch Logs Insights.
        Log.Configure(o => o
            .UseStructured()
            .SetMinimumLevel(LogLevel.Information)
            .AddColorIcon(false)        // CloudWatch doesn't need emoji
            .AddTraceId());
    }

    public string FunctionHandler(string input, ILambdaContext context)
    {
        using (Log.BeginTraceScope(context.AwsRequestId))
        {
            Log<Function>.Information("Received input");

            if (string.IsNullOrWhiteSpace(input))
            {
                Log.Warning("Empty input received");
                return string.Empty;
            }

            return input.ToUpperInvariant();
        }
    }
}

Because the entries are JSON with a shared traceId, CloudWatch Logs Insights queries like fields @timestamp, message | filter traceId = "…" reconstruct a single invocation instantly.

Tip: turn off the color icon (AddColorIcon(false)) for CloudWatch and other text sinks that don't render emoji cleanly.


Class libraries

A library can log without forcing any logging dependency on its consumers — there's nothing to inject. Just call Log / Log<T>:

namespace Acme.Payments;

public class PaymentProcessor
{
    public void Charge(decimal amount)
    {
        Log<PaymentProcessor>.Information("Charging");   // class + method context
        // ...
    }
}

The application at the top decides output format and level via Log.Configure(...). If the app never configures it, the library's logs simply use the defaults. (If you're writing a widely-distributed library, consider whether a static logger is appropriate for your consumers — see the FAQ.)

Clone this wiki locally