Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion docs/docs/operator/deployment.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Deployment
description: Deploying your KubeOps Operator
sidebar_position: 6
sidebar_position: 7
---

# Deployment
Expand Down
177 changes: 177 additions & 0 deletions docs/docs/operator/logging.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
title: Logging
description: Logging, Tracing, and OpenTelemetry
sidebar_position: 6
---

# Logging, Tracing, and OpenTelemetry

## 1. Logging with `ILogger` and Scopes

This project uses Microsoft's [`ILogger`](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging) interface for logging. It provides a standardized and extensible way to capture events within the application.

Using *scopes* enables hierarchical organization of log messages and allows contextual information to be attached to each entry.

### 1.1 ILogger Basics

The `ILogger` interface is part of [`Microsoft.Extensions.Logging`](https://www.nuget.org/packages/Microsoft.Extensions.Logging) and provides methods to log messages at various severity levels (e.g., `Information`, `Warning`, `Error`).

Logging can be enabled using either `WebApplication.CreateBuilder`, `Host.CreateDefaultBuilder`, or the `AddLogging` extension method on the `IServiceCollection`.

You can log from your code by injecting `ILogger<MyEntityController>` (or a similar type) into your component.

### 1.2 Using Scopes

Scopes define a logical boundary in which all log entries are automatically enriched with contextual metadata. This is especially useful for correlating logs related to a specific request or operation.

By default, the [ResourceWatcher](https://github.com/buehler/dotnet-operator-sdk/blob/main/src/KubeOps.Operator/Watcher/ResourceWatcher%7BTEntity%7D.cs) starts a new scope for every watch event it processes. Each scope includes:

- `EventType`: Type of the received watch event (`Added`, `Modified`, `Deleted`, `Error`, `Bookmark`)
- `Kind`: Custom Resource Definition (CRD) kind
- `Namespace`: CRD namespace
- `Name`: CRD name
- `ResourceVersion`: CRD resource version

You can create additional scopes in your code using `logger.BeginScope(state)`, where `state` can be either a string or a custom object.

To include scopes in the logging output, they must be explicitly enabled either via configuration or code:

**`appsettings.json`:**

```json
"Logging": {
"Console": {
"FormatterName": "Simple",
"FormatterOptions": {
"IncludeScopes": true
}
},
"LogLevel": {
"Default": "Information",
"KubeOps": "Trace"
}
}
```

**Programmatic configuration:**

```csharp
builder
.ConfigureLogging((hostBuilderContext, loggingBuilder) =>
{
loggingBuilder
.AddSimpleConsole(options => options.IncludeScopes = true);
});
```

:::tip
To enable scopes with OpenTelemetry, configure it as follows:

```json
"OpenTelemetry": {
"IncludeScopes": true,
"ParseStateValues": true,
"IncludeFormattedMessage": true
}
```

The scope state must be an `IReadOnlyDictionary<string, object?>` to ensure correct serialization and inclusion in log entries.
:::

## 2. Tracing with `System.Diagnostics` and `ActivitySource`

For [distributed tracing](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-concepts), this project uses `System.Diagnostics` in combination with `ActivitySource`.
Activities can be started using `ActivitySource.StartActivity`.

The operator registers an `ActivitySource` instance with the operator name in the dependency injection (DI) container. To use a custom `ActivitySource`, simply register your own, the DI will provide the last registered instance when requested.

:::tip
You can configure the operator name (and thus the `ActivitySource` name) via `OperatorSettings`:

```csharp
const string OperatorName = "my-operator";

builder
.Services
.AddKubernetesOperator(settings => settings.Name = OperatorName);
```

If you're using OpenTelemetry, tracing must be explicitly configured in code. Make sure to add the same source name used when creating the `ActivitySource`.

Also, create a `ResourceBuilder` to name your service properly in trace output:

```csharp
builder.Services
.AddOpenTelemetry()
.WithTracing(tracerProviderBuilder =>
tracerProviderBuilder
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: OperatorName, serviceVersion: "1.0.0"))
.AddSource(OperatorName));
```
:::

## 3. OpenTelemetry Configuration for Azure Logging

To use OpenTelemetry with Azure, it is recommended to adopt the [Azure Monitor OpenTelemetry Distro](https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-enable).
You can enable it via code:

```csharp
builder.Services
.AddOpenTelemetry()
.UseAzureMonitor();
```

### 3.2 Full Example Configuration in `Program.cs` (or `Startup.cs`)

A complete setup with logging, tracing, and OpenTelemetry might look like this:

**`appsettings.json`:**

```json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"KubeOps": "Trace"
},
"Console": {
"FormatterName": "Simple",
"FormatterOptions": {
"IncludeScopes": true,
"SingleLine": true
}
},
"OpenTelemetry": {
"IncludeScopes": true,
"ParseStateValues": true,
"IncludeFormattedMessage": true
}
}
}
```

**`Program.cs`:**

```csharp
const string OperatorName = "my-platform-operator";

var builder = WebApplication.CreateBuilder(args);

builder
.Services
.AddKubernetesOperator(settings => settings.Name = OperatorName)
.RegisterComponents();

builder
.Services
.AddOpenTelemetry()
.WithTracing(tracerProviderBuilder =>
tracerProviderBuilder
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: OperatorName, serviceVersion: "1.0.0"))
.AddSource(OperatorName))
.UseAzureMonitor();
```
2 changes: 1 addition & 1 deletion docs/docs/operator/testing/_category_.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"position": 7,
"position": 8,
"label": "Testing",
"collapsible": true,
"collapsed": true
Expand Down