diff --git a/README.md b/README.md index acdc611..ce0e7da 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,153 @@ var config = new CallStackEnricherConfiguration() onException: ex => Console.WriteLine($"Enricher error: {ex.Message}")); ``` +## ASP.NET Core Integration + +### Program.cs Configuration + +```csharp +using Serilog; +using Serilog.Events; + +var builder = WebApplication.CreateBuilder(args); + +// Configure Serilog with CallStack enricher +builder.Host.UseSerilog((context, configuration) => + configuration + .ReadFrom.Configuration(context.Configuration) + .Enrich.WithCallStack(config => config + .WithCallStackFormat(useExceptionLikeFormat: true, maxFrames: 5) + .SkipNamespace("Microsoft.AspNetCore") + .SkipNamespace("System")) + .WriteTo.Console() + .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day)); + +var app = builder.Build(); + +// Add Serilog request logging middleware +app.UseSerilogRequestLogging(options => +{ + options.MessageTemplate = "Handled {RequestPath}"; + options.GetLevel = (httpContext, elapsed, ex) => + ex != null ? LogEventLevel.Error : LogEventLevel.Information; +}); + +app.MapControllers(); +app.Run(); +``` + +### appsettings.json Configuration + +```json +{ + "Serilog": { + "Using": ["Serilog.Enrichers.CallStack"], + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft.AspNetCore": "Warning" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} | {CallStack}{NewLine}{Exception}" + } + } + ], + "Enrich": [ + { + "Name": "WithCallStack", + "Args": { + "useExceptionLikeFormat": true, + "maxFrames": 10, + "skipNamespaces": ["Microsoft.AspNetCore", "System.Threading"] + } + } + ] + } +} +``` + +### Controller Example + +```csharp +[ApiController] +[Route("api/[controller]")] +public class UserController : ControllerBase +{ + private readonly ILogger _logger; + private readonly IUserService _userService; + + public UserController(ILogger logger, IUserService userService) + { + _logger = logger; + _userService = userService; + } + + [HttpGet("{id}")] + public async Task GetUser(int id) + { + _logger.LogInformation("Getting user {UserId}", id); + + try + { + var user = await _userService.GetUserAsync(id); + _logger.LogInformation("Successfully retrieved user {UserId}", id); + return Ok(user); + } + catch (Exception ex) + { + // CallStack enricher will show: UserService.GetUserAsync:45 --> UserController.GetUser:23 + _logger.LogError(ex, "Failed to get user {UserId}", id); + return StatusCode(500); + } + } +} +``` + +### Service Layer Integration + +```csharp +public class UserService : IUserService +{ + private readonly ILogger _logger; + private readonly IUserRepository _repository; + + public UserService(ILogger logger, IUserRepository repository) + { + _logger = logger; + _repository = repository; + } + + public async Task GetUserAsync(int id) + { + _logger.LogInformation("Processing user request for {UserId}", id); + + // This will show the full call chain when logged + var user = await _repository.FindByIdAsync(id); + + if (user == null) + { + _logger.LogWarning("User {UserId} not found", id); + throw new UserNotFoundException($"User {id} not found"); + } + + return user; + } +} +``` + +### Expected Log Output + +``` +[14:30:25 INF] Getting user 123 | UserController.GetUser:20 +[14:30:25 INF] Processing user request for 123 | UserService.GetUserAsync:15 --> UserController.GetUser:25 +[14:30:25 INF] Successfully retrieved user 123 | UserController.GetUser:27 +[14:30:25 INF] Handled /api/user/123 +``` + ## Advanced Configuration Examples ### Minimal Configuration