> ## Documentation Index
> Fetch the complete documentation index at: https://docs.foveus.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Serilog

Use `Foveus.Serilog` to send structured Serilog logs to Foveus.

This integration is for applications that already use Serilog.

If your application does not use Serilog, you do not need `Foveus.Serilog`. Use `Foveus.SDK` alone.

## How it works

`Foveus.SDK` captures executions, context, metrics, batching, transport, and correlation.

`Foveus.Serilog` adds a Serilog sink so logs written through Serilog can be sent to Foveus.

Use both packages together for Serilog-first applications.

```text theme={null}
Foveus.SDK       → core telemetry, execution capture, batching, transport
Foveus.Serilog   → Serilog sink bridge
```

## Install packages

Install both packages:

```bash theme={null}
dotnet add package Foveus.SDK
dotnet add package Foveus.Serilog
```

<Note>
  During private beta, your package names or package source may be different. Use the package names and feed URL provided during onboarding.
</Note>

## Basic setup

Import the Foveus Serilog extension.

```csharp theme={null}
using Foveus.Serilog;
using Serilog;
```

Configure Foveus first:

```csharp theme={null}
builder.Services.AddFoveus(builder.Configuration);
```

Then configure Serilog and add the Foveus sink:

```csharp theme={null}
builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});
```

Then add Foveus middleware if this is an ASP.NET Core API:

```csharp theme={null}
app.UseFoveus();
```

## Recommended setup

For Serilog-first applications, disable the built-in Foveus `ILogger` provider so logs are not captured twice.

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "EnableFoveusLoggerProvider": false
  }
}
```

Then configure Foveus and Serilog:

```csharp theme={null}
using Foveus.Serilog;
using Serilog;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});

var app = builder.Build();

app.UseFoveus();

app.MapGet("/orders", (ILogger<Program> logger) =>
{
    logger.LogInformation("Orders endpoint called");

    return Results.Ok(new
    {
        status = "ok"
    });
});

app.Run();
```

## Keep using ILogger

You can keep using the standard `.NET` `ILogger<T>` APIs in a Serilog application.

```csharp theme={null}
public sealed class OrderService
{
    private readonly ILogger<OrderService> _logger;

    public OrderService(ILogger<OrderService> logger)
    {
        _logger = logger;
    }

    public void ProcessOrder(string orderId)
    {
        _logger.LogInformation("Order {OrderId} processed", orderId);
    }
}
```

In a Serilog-first app, those logs flow through Serilog’s normal `.NET` logging pipeline.

Foveus captures them through the Serilog sink:

```csharp theme={null}
.WriteTo.Foveus(services)
```

The key point:

```text theme={null}
Disable the Foveus logger provider, not ILogger.
```

## Why disable the built-in logger provider?

In Serilog-first applications, you should usually disable the built-in Foveus `ILogger` provider.

This does **not** mean you stop using `ILogger<T>`.

You can keep writing normal `.NET` logs:

```csharp theme={null}
_logger.LogInformation("Payment completed for {PaymentId}", paymentId);
```

The difference is the path the log takes into Foveus.

### Without Serilog

If you are not using Serilog, Foveus can capture `ILogger<T>` logs through the SDK logger provider.

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "EnableFoveusLoggerProvider": true
  }
}
```

### With Serilog

If your app uses Serilog, `ILogger<T>` logs can flow through Serilog’s normal `.NET` logging pipeline.

Foveus then captures them through the Serilog sink.

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "EnableFoveusLoggerProvider": false
  }
}
```

Then configure the Serilog sink:

```csharp theme={null}
builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});
```

This avoids duplicate log capture.

## Why AddFoveus must run first

`WriteTo.Foveus(services)` uses dependency injection to get the Foveus services it needs.

It pulls dependencies such as:

* `FoveusClient`
* `FoveusOptions`
* `IMetricsCollector`

That means `AddFoveus(...)` must be registered before the Serilog sink is configured.

Correct order:

```csharp theme={null}
builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .WriteTo.Foveus(services);
});
```

Do not build a separate service provider just for Serilog.

## Appsettings example

A typical Serilog-first setup looks like this:

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "ServiceName": "orders-api",
    "CaptureProfile": "Balanced",
    "EnableFoveusLoggerProvider": false,
    "EnableDebugLogging": false,
    "Source": "web"
  },

  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    }
  }
}
```

Then configure the sink in code:

```csharp theme={null}
builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});
```

## What gets captured

For each Serilog log event, Foveus captures structured log data.

| Field               | Description                                                                  |
| ------------------- | ---------------------------------------------------------------------------- |
| `ServiceName`       | From Foveus configuration. Defaults to the project assembly name if not set. |
| `Timestamp`         | The log event timestamp.                                                     |
| `Level`             | The mapped log level.                                                        |
| `Message`           | The rendered log message.                                                    |
| `TraceId`           | Current trace ID, current activity trace ID, or generated fallback.          |
| `SpanId`            | Current span ID, current activity span ID, or generated fallback.            |
| `ExecutionId`       | Current execution ID or generated fallback.                                  |
| `ParentExecutionId` | Current parent execution ID if available.                                    |
| `Exception`         | Exception type, message, stack trace, and inner exception details.           |
| `Properties`        | Serilog structured properties.                                               |
| `Source`            | From Foveus configuration, or `unknown`.                                     |

## Log level mapping

Foveus maps Serilog levels to Foveus log levels.

| Serilog level | Foveus level |
| ------------- | ------------ |
| `Verbose`     | `TRACE`      |
| `Debug`       | `DEBUG`      |
| `Information` | `INFO`       |
| `Warning`     | `WARN`       |
| `Error`       | `ERROR`      |
| `Fatal`       | `FATAL`      |

## Structured logging

Serilog structured properties are sent to Foveus.

This works whether the log call is written through Serilog directly or through `ILogger<T>` in a Serilog-configured application.

Using `ILogger<T>`:

```csharp theme={null}
_logger.LogInformation("Order {OrderId} created", orderId);
```

Using Serilog directly:

```csharp theme={null}
Log.Information("Order {OrderId} created", orderId);
```

Foveus captures:

| Field               | Value                        |
| ------------------- | ---------------------------- |
| Rendered message    | `Order ord_123 created`      |
| Message template    | `Order {OrderId} created`    |
| Structured property | `OrderId = ord_123`          |
| Category            | Logger category or `Serilog` |
| Level               | `INFO`                       |

Use structured properties for values you want to inspect or correlate later.

## Exception logging

Serilog exceptions are captured with the log event.

Using `ILogger<T>`:

```csharp theme={null}
try
{
    ProcessOrder(orderId);
}
catch (Exception ex)
{
    _logger.LogError(ex, "Failed to process order {OrderId}", orderId);
}
```

Using Serilog directly:

```csharp theme={null}
try
{
    ProcessOrder(orderId);
}
catch (Exception ex)
{
    Log.Error(ex, "Failed to process order {OrderId}", orderId);
}
```

Foveus captures:

* exception type
* exception message
* stack trace
* inner exception chain
* rendered message
* structured properties such as `OrderId`

## Correlation

`Foveus.Serilog` tries to attach logs to the same execution, trace, and span as the rest of the telemetry.

It gets correlation from:

1. the current Foveus metrics/execution context
2. `System.Diagnostics.Activity.Current`
3. generated fallback IDs

When used with `Foveus.SDK`, logs can appear connected to requests, executions, traces, and errors in Foveus.

## Using Serilog with ASP.NET Core

A typical setup for an ASP.NET Core API:

```csharp theme={null}
using Foveus.Serilog;
using Serilog;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});

var app = builder.Build();

app.UseFoveus();

app.MapPost("/orders", (
    CreateOrderRequest request,
    ILogger<Program> logger) =>
{
    logger.LogInformation("Creating order for customer {CustomerId}", request.CustomerId);

    return Results.Ok(new
    {
        orderId = "ord_123",
        status = "created"
    });
});

app.Run();
```

## Using Serilog without HTTP middleware

You can use `Foveus.Serilog` in applications that do not receive HTTP requests.

For example:

* console apps
* background jobs
* workers
* queue consumers

In these cases, Foveus can still receive structured logs.

Full worker-service execution capture is not yet fully supported, but Serilog logs can still be sent when configured.

```csharp theme={null}
using Foveus.Serilog;
using Serilog;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddFoveus(builder.Configuration);

builder.Services.AddSerilog((services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(builder.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});

var app = builder.Build();

Log.Information("Worker started");

await app.RunAsync();
```

<Note>
  Worker service support is evolving. `Foveus.Serilog` can send structured logs from workers today, but full worker execution capture is not yet the same as HTTP execution capture.
</Note>

For full worker setup details, see [Worker services](/sdk/worker-services).

## Redaction and safety

Log events can contain sensitive data.

Avoid logging secrets, credentials, tokens, card data, or highly sensitive personal data.

Use structured properties carefully.

```csharp theme={null}
// Good
_logger.LogInformation("Order {OrderId} created", orderId);

// Avoid
_logger.LogInformation("Payment card {CardNumber} used", cardNumber);
```

If sensitive values are logged, they may be sent to Foveus.

Use Serilog destructuring and filtering policies where appropriate, and keep Foveus redaction settings updated.

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "RedactedFields": ["nationalId", "accountNumber"]
  }
}
```

## Troubleshooting

### Logs are duplicated

If the same logs appear twice, both Foveus logging paths may be enabled:

* the Foveus SDK logger provider
* the Foveus Serilog sink

In Serilog-first apps, keep using `ILogger<T>`, but disable the Foveus SDK logger provider.

```json theme={null}
{
  "Foveus": {
    "ApiKey": "fov_test_...",
    "EnableFoveusLoggerProvider": false
  }
}
```

Then route logs to Foveus through:

```csharp theme={null}
.WriteTo.Foveus(services)
```

### Sink throws a setup error

Make sure you call `AddFoveus(...)` before configuring the sink.

```csharp theme={null}
builder.Services.AddFoveus(builder.Configuration);

builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration.WriteTo.Foveus(services);
});
```

The sink needs Foveus services from dependency injection.

### Logs are not correlated to executions

Check that:

* `app.UseFoveus()` is registered for HTTP services
* logs are written during the request or operation
* Activity/correlation context is available
* `WriteTo.Foveus(services)` uses the app service provider
* you are not building a separate service provider for Serilog

### ILogger logs are not appearing

Check that your app is actually routing `ILogger<T>` logs through Serilog.

In ASP.NET Core, make sure Serilog is configured on the host:

```csharp theme={null}
builder.Host.UseSerilog((context, services, loggerConfiguration) =>
{
    loggerConfiguration
        .ReadFrom.Configuration(context.Configuration)
        .ReadFrom.Services(services)
        .WriteTo.Foveus(services);
});
```

Then this should still work:

```csharp theme={null}
_logger.LogInformation("Payment completed for {PaymentId}", paymentId);
```

### Logs do not appear

Check that:

* both `Foveus.SDK` and `Foveus.Serilog` are installed
* `AddFoveus(...)` is called
* `WriteTo.Foveus(services)` is configured
* the API key is valid
* the dashboard is showing the right mode
* the Serilog minimum level allows the event
* the service can reach Foveus

### Too many logs are sent

Adjust Serilog minimum levels.

```json theme={null}
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    }
  }
}
```

You can also use Serilog filters to exclude noisy categories.

## What to do next

* Configure the SDK: [SDK configuration](/sdk/configuration)
* Set up worker services: [Worker services](/sdk/worker-services)
* Review FoveusOptions: [FoveusOptions](/sdk/foveus-options)
* Configure redaction: [Redaction](/sdk/redaction)
* Review performance overhead: [Performance overhead](/sdk/performance-overhead)
