Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserController> _logger;
private readonly IUserService _userService;

public UserController(ILogger<UserController> logger, IUserService userService)
{
_logger = logger;
_userService = userService;
}

[HttpGet("{id}")]
public async Task<IActionResult> 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<UserService> _logger;
private readonly IUserRepository _repository;

public UserService(ILogger<UserService> logger, IUserRepository repository)
{
_logger = logger;
_repository = repository;
}

public async Task<User> 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
Expand Down
Loading