Repository: funkysi1701/funkysi1701.github.io
Pull request #1717: Add blog post on integrating OpenTelemetry with Grafana
Author: login: funkysi1701
Created: 2025-04-14T21:16:28Z | Merged: 2025-04-14T21:23:36Z

Introduce a new blog post detailing the integration of OpenTelemetry logs with Grafana using Loki and Alloy. The post covers setup instructions, configuration examples, and highlights the benefits of centralized log aggregation and monitoring for .NET applications. Include relevant images and make minor tweaks for clarity and presentation.


Diff:
diff --git a/content/posts/2025/opentelemetry-logs.md b/content/posts/2025/opentelemetry-logs.md
new file mode 100644
index 000000000..2bf9c68b7
--- /dev/null
+++ b/content/posts/2025/opentelemetry-logs.md
@@ -0,0 +1,137 @@
++++
+title = "Integrating OpenTelemetry Logs with Grafana Using Loki and Alloy"
+date = "2025-04-14T20:00:00Z"
+year = "2025"
+month= "2025-04"
+author = "funkysi1701"
+authorTwitter = "funkysi1701" #do not include @
+cover = "/images/grafana-loki-arch.png"
+images =['/images/grafana-loki-arch.png']
+tags = ["OpenTelemetry", "Grafana", "Loki", "Alloy", "Logging", "Monitoring", "Docker", "DotNet", "Tech"]
+category="tech"
+description = "Learn how to integrate OpenTelemetry logs with Grafana using Loki and Alloy for efficient log aggregation and monitoring in your .NET applications."
+showFullContent = false
+readingTime = true
+copyright = false
+featured = false
+draft = false
+aliases = [
+    "/adding-opentelemetry-logs-to-grafana",
+    "/posts/adding-opentelemetry-logs-to-grafana",
+    "/posts/2025/04/14/adding-opentelemetry-logs-to-grafana",
+    "/2025/04/14/adding-opentelemetry-logs-to-grafana" 
+]
++++
+Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I'll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.
+
+I have blogged about [Grafana](/posts/2025/setting-up-grafana/) before but until now I haven't added logs to Grafana let's have a look at how that works.
+
+My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.
+
+Grafana has several tools that can help with logs.
+
+- **Loki**: A log aggregation system designed to store and query logs from applications and infrastructure.
+- **Alloy**: An OpenTelemetry collector that processes and forwards telemetry data.
+- **OpenTelemetry**: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.
+
+I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.
+
+## Setting Up Loki and Alloy with Docker Compose
+
+To start off let's add Alloy and Loki to my docker compose file.
+
+### Docker Compose Configuration
+
+The `docker-compose.yml` file defines the services for Loki and Alloy. Here's what each section does:
+
+- **Loki**: Runs the Loki container on port 3100 and uses a local configuration file.
+- **Alloy**: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.
+
+```docker-compose.yml
+# Docker Compose configuration for Loki and Alloy
+    command: -config.file=/etc/loki/local-config.yaml # Specifies the configuration file for Loki
+
+  alloy:
+    image: grafana/alloy:v1.8.1
+    container_name: monitoring_alloy
+    ports:
+      - 12345:12345 # HTTP server for Alloy
+      - 4317:4317   # gRPC endpoint for OpenTelemetry
+      - 4319:4318   # HTTP endpoint for OpenTelemetry
+    volumes:
+      - ./config.alloy:/etc/alloy/config.alloy # Mount Alloy configuration
+    command: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy
+    depends_on:
+      - loki
+```
+
+Here is the config file for Alloy.
+
+```alloy.config
+otelcol.receiver.otlp "default" {
+  http {}
+  grpc {}
+
+  output {
+    logs    = [otelcol.processor.batch.default.input]
+  }
+}
+
+otelcol.processor.batch "default" {
+    output {
+        logs = [
+          otelcol.exporter.otlphttp.loki.input,
+        ]
+    }
+}
+
+otelcol.exporter.otlphttp "loki" {
+  client {
+    endpoint = "http://loki:3100/otlp"
+  }
+}
+```
+
+### How the Components Work Together
+
+1. **Application Logs**: The .NET application generates logs and sends them to Alloy on port 4317.
+2. **Alloy Processing**: Alloy processes the logs and forwards them to Loki on port 3100.
+3. **Loki Storage**: Loki stores the logs, making them available for querying.
+4. **Grafana Visualization**: Grafana connects to Loki as a data source, allowing you to visualize and analyze the logs.
+
+![Architecture Diagram](/images/grafana-loki-arch.png)
+
+
+### Handling Aspire Dashboard Logs
+
+By default, sending logs to Alloy and Loki means Aspire Dashboard will no longer receive them. To resolve this, you can configure the `AddOpenTelemetryExporters` method in your .NET application to send logs to multiple destinations.
+
+```Extensions.cs
+if (useOtlpExporter)
+{
+    // The following lines enable the OTLP exporter (requires the OpenTelemetry.Exporter.OpenTelemetryProtocol package)
+    builder.Services.AddOpenTelemetry()
+    .WithLogging(logging => logging.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }))
+    .WithLogging(logging => logging.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["GrafanaExporter"]);
+    }))
+    .WithMetrics(metrics => metrics.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }))
+    .WithTracing(tracing => tracing.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }));
+}
+```
+
+If I update the AddOpenTelemetryExporters method in my Extensions.cs file in my .Net Aspire ServiceDefaults project, I can get my logs (or traces/metrics) to be sent to as many different places as I want. In my case I am sending to Allot and Aspire Dashboard.
+
+## Conclusion
+
+Integrating OpenTelemetry logs with Grafana using Loki and Alloy provides a powerful solution for centralized log aggregation and monitoring. This setup simplifies debugging and enhances visibility into your application's behaviour. If you haven't tried it yet, give it a go and let me know your thoughts in the comments!
diff --git a/static/images/grafana-loki-arch.png b/static/images/grafana-loki-arch.png
new file mode 100644
index 000000000..2da69b90f
Binary files /dev/null and b/static/images/grafana-loki-arch.png differ


Reviews:
user: login: gemini-code-assist[bot]
body: Hello @funkysi1701, I'm Gemini Code Assist[^1]! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

## Summary of Changes
This pull request introduces a new blog post detailing how to integrate OpenTelemetry logs with Grafana using Loki and Alloy. The post provides setup instructions, configuration examples, and explains the benefits of using these tools for centralized log aggregation and monitoring of .NET applications. It includes a Docker Compose configuration for Loki and Alloy, along with configuration details for each. The post also addresses how to handle logs from the Aspire Dashboard by configuring the `AddOpenTelemetryExporters` method to send logs to multiple destinations.

### Highlights
* **New Blog Post**: Adds a comprehensive guide on integrating OpenTelemetry logs with Grafana using Loki and Alloy.
* **Docker Compose Configuration**: Provides a `docker-compose.yml` file setup for Loki and Alloy, including necessary configurations.
* **Handling Aspire Dashboard Logs**: Explains how to configure the .NET application to send logs to both Alloy/Loki and the Aspire Dashboard.

### Changelog
* **content/posts/2025/opentelemetry-logs.md**
  * Added a new blog post on integrating OpenTelemetry logs with Grafana using Loki and Alloy.
  * Included setup instructions for Loki and Alloy using Docker Compose.
  * Provided configuration examples for Loki and Alloy.
  * Explained how to send logs to multiple destinations, including Aspire Dashboard.
  * Added an architecture diagram illustrating the log flow.


<details>

<summary><b>Using Gemini Code Assist</b></summary>
<br>

The full guide for Gemini Code Assist can be found on our [documentation page](https://developers.google.com/gemini-code-assist/docs/review-github-code), here are some quick tips.

<b>Invoking Gemini</b>

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either `/gemini <command>` or `@gemini-code-assist <command>`. Below is a summary of the supported commands.

Feature | Command | Description
--- | --- | ---
Code Review | `/gemini review` | Performs a code review for the current pull request in its current state.
Pull Request Summary | `/gemini summary` | Provides a summary of the current pull request in its current state.
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments.
Help | `/gemini help` | Displays a list of available commands.

<b>Customization</b>

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a `.gemini/` folder in the base of the repository. Detailed instructions can be found [here](https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github).

<b>Limitations & Feedback</b>

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments to provide feedback.

</details>

<b>You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the [Gemini Code Assist IDE Extension](https://cloud.google.com/products/gemini/code-assist).</b>


[^1]: Review the [Privacy Notices](https://policies.google.com/privacy), [Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy), [Terms of Service](https://policies.google.com/terms), and learn how to configure Gemini Code Assist in GitHub [here](https://developers.google.com/gemini-code-assist/docs/review-github-code). Gemini can make mistakes, so double check it and [use code with caution](https://support.google.com/legal/answer/13505487).

---

> Logs flow, a Grafana stream,
> Loki stores, a data dream.
> Alloy guides the way,
> Insights dawn each day,
> Telemetry's vibrant gleam.


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:16:36Z
user: login: gemini-code-assist[bot]
body: ## Code Review
This pull request introduces a new blog post detailing the integration of OpenTelemetry logs with Grafana using Loki and Alloy. The post includes setup instructions, configuration examples, and highlights the benefits of centralized log aggregation and monitoring for .NET applications. The content is well-structured and provides a practical guide for users looking to implement this integration. However, there are a few areas that could be improved for clarity and completeness.

### Summary of Findings
* **Clarity on Configuration Files**: The blog post mentions configuration files for both Loki and Alloy but only shows the Alloy configuration. Including the Loki configuration would provide a more complete picture for readers.
* **Explanation of Docker Socket Mount**: The Docker Compose configuration includes mounting the Docker socket. A brief explanation of why this is necessary and what it enables would be beneficial.
* **Handling Aspire Dashboard Logs - Configuration Details**: The section on handling Aspire Dashboard logs could benefit from more detailed instructions or a link to a resource explaining how to configure the `AddOpenTelemetryExporters` method to send logs to multiple destinations.

### Merge Readiness
The pull request is a valuable addition to the blog, providing a practical guide to integrating OpenTelemetry logs with Grafana. However, addressing the issues raised in the review comments would enhance the clarity and completeness of the post. I am unable to approve the pull request, and users should have others review and approve this code before merging. I recommend addressing the comments before merging.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:16:46Z

Review comments:
diff_hunk: @@ -0,0 +1,143 @@
++++
+title = "Integrating OpenTelemetry Logs with Grafana Using Loki and Alloy"
+date = "2025-04-14T20:00:00Z"
+year = "2025"
+month= "2025-04"
+author = "funkysi1701"
+authorTwitter = "funkysi1701" #do not include @
+cover = "/images/grafana-loki-arch.png"
+images =['/images/grafana-loki-arch.png']
+tags = ["OpenTelemetry", "Grafana", "Loki", "Alloy", "Logging", "Monitoring", "Docker", "DotNet", "Tech"]
+category="tech"
+description = "Learn how to integrate OpenTelemetry logs with Grafana using Loki and Alloy for efficient log aggregation and monitoring in your .NET applications."
+showFullContent = false
+readingTime = true
+copyright = false
+featured = false
+draft = false
+aliases = [
+    "/adding-opentelemetry-logs-to-grafana",
+    "/posts/adding-opentelemetry-logs-to-grafana",
+    "/posts/2025/04/14/adding-opentelemetry-logs-to-grafana",
+    "/2025/04/14/adding-opentelemetry-logs-to-grafana" 
+]
++++
+Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I'll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.
+
+I have blogged about [Grafana](/posts/2025/setting-up-grafana/) before but until now I haven't added logs to Grafana let's have a look at how that works.
+
+My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.
+
+Grafana has several tools that can help with logs.
+
+- **Loki**: A log aggregation system designed to store and query logs from applications and infrastructure.
+- **Alloy**: An OpenTelemetry collector that processes and forwards telemetry data.
+- **OpenTelemetry**: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.
+
+I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.
+
+## Setting Up Loki and Alloy with Docker Compose
+
+To start off let's add Alloy and Loki to my docker compose file.
+
+### Docker Compose Configuration
+
+The `docker-compose.yml` file defines the services for Loki and Alloy. Here's what each section does:
+
+- **Loki**: Runs the Loki container on port 3100 and uses a local configuration file.
+- **Alloy**: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.
+
+```docker-compose.yml
+# Docker Compose configuration for Loki and Alloy
+  loki:
+    image: grafana/loki:3.4.3
+    container_name: monitoring_loki2
+    ports:
+      - "3100:3100" # Expose Loki on port 3100
+    command: -config.file=/etc/loki/local-config.yaml    
path: content/posts/2025/opentelemetry-logs.md
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

It would be helpful to include a brief explanation of what this command does, specifically `-config.file=/etc/loki/local-config.yaml`. This provides context for readers who may be unfamiliar with Loki's configuration options.

```suggestion
    command: -config.file=/etc/loki/local-config.yaml # Specifies the configuration file for Loki
```
created_at: 2025-04-14T21:16:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
++++
+title = "Integrating OpenTelemetry Logs with Grafana Using Loki and Alloy"
+date = "2025-04-14T20:00:00Z"
+year = "2025"
+month= "2025-04"
+author = "funkysi1701"
+authorTwitter = "funkysi1701" #do not include @
+cover = "/images/grafana-loki-arch.png"
+images =['/images/grafana-loki-arch.png']
+tags = ["OpenTelemetry", "Grafana", "Loki", "Alloy", "Logging", "Monitoring", "Docker", "DotNet", "Tech"]
+category="tech"
+description = "Learn how to integrate OpenTelemetry logs with Grafana using Loki and Alloy for efficient log aggregation and monitoring in your .NET applications."
+showFullContent = false
+readingTime = true
+copyright = false
+featured = false
+draft = false
+aliases = [
+    "/adding-opentelemetry-logs-to-grafana",
+    "/posts/adding-opentelemetry-logs-to-grafana",
+    "/posts/2025/04/14/adding-opentelemetry-logs-to-grafana",
+    "/2025/04/14/adding-opentelemetry-logs-to-grafana" 
+]
++++
+Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I'll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.
+
+I have blogged about [Grafana](/posts/2025/setting-up-grafana/) before but until now I haven't added logs to Grafana let's have a look at how that works.
+
+My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.
+
+Grafana has several tools that can help with logs.
+
+- **Loki**: A log aggregation system designed to store and query logs from applications and infrastructure.
+- **Alloy**: An OpenTelemetry collector that processes and forwards telemetry data.
+- **OpenTelemetry**: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.
+
+I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.
+
+## Setting Up Loki and Alloy with Docker Compose
+
+To start off let's add Alloy and Loki to my docker compose file.
+
+### Docker Compose Configuration
+
+The `docker-compose.yml` file defines the services for Loki and Alloy. Here's what each section does:
+
+- **Loki**: Runs the Loki container on port 3100 and uses a local configuration file.
+- **Alloy**: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.
+
+```docker-compose.yml
+# Docker Compose configuration for Loki and Alloy
+  loki:
+    image: grafana/loki:3.4.3
+    container_name: monitoring_loki2
+    ports:
+      - "3100:3100" # Expose Loki on port 3100
+    command: -config.file=/etc/loki/local-config.yaml    
+
+  alloy:
+    image: grafana/alloy:v1.8.1
+    container_name: monitoring_alloy
+    ports:
+      - 12345:12345 # HTTP server for Alloy
+      - 4317:4317   # gRPC endpoint for OpenTelemetry
+      - 4319:4318   # HTTP endpoint for OpenTelemetry
+    volumes:
+      - ./config.alloy:/etc/alloy/config.alloy # Mount Alloy configuration
+      - /var/run/docker.sock:/var/run/docker.sock # Access Docker socket
path: content/posts/2025/opentelemetry-logs.md
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Could you add a brief explanation of why the Docker socket is being mounted? This might not be obvious to all readers. What does this enable?

```suggestion
      - /var/run/docker.sock:/var/run/docker.sock # Access Docker socket to allow Alloy to monitor Docker containers
```
created_at: 2025-04-14T21:16:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
++++
+title = "Integrating OpenTelemetry Logs with Grafana Using Loki and Alloy"
+date = "2025-04-14T20:00:00Z"
+year = "2025"
+month= "2025-04"
+author = "funkysi1701"
+authorTwitter = "funkysi1701" #do not include @
+cover = "/images/grafana-loki-arch.png"
+images =['/images/grafana-loki-arch.png']
+tags = ["OpenTelemetry", "Grafana", "Loki", "Alloy", "Logging", "Monitoring", "Docker", "DotNet", "Tech"]
+category="tech"
+description = "Learn how to integrate OpenTelemetry logs with Grafana using Loki and Alloy for efficient log aggregation and monitoring in your .NET applications."
+showFullContent = false
+readingTime = true
+copyright = false
+featured = false
+draft = false
+aliases = [
+    "/adding-opentelemetry-logs-to-grafana",
+    "/posts/adding-opentelemetry-logs-to-grafana",
+    "/posts/2025/04/14/adding-opentelemetry-logs-to-grafana",
+    "/2025/04/14/adding-opentelemetry-logs-to-grafana" 
+]
++++
+Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I'll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.
+
+I have blogged about [Grafana](/posts/2025/setting-up-grafana/) before but until now I haven't added logs to Grafana let's have a look at how that works.
+
+My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.
+
+Grafana has several tools that can help with logs.
+
+- **Loki**: A log aggregation system designed to store and query logs from applications and infrastructure.
+- **Alloy**: An OpenTelemetry collector that processes and forwards telemetry data.
+- **OpenTelemetry**: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.
+
+I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.
+
+## Setting Up Loki and Alloy with Docker Compose
+
+To start off let's add Alloy and Loki to my docker compose file.
+
+### Docker Compose Configuration
+
+The `docker-compose.yml` file defines the services for Loki and Alloy. Here's what each section does:
+
+- **Loki**: Runs the Loki container on port 3100 and uses a local configuration file.
+- **Alloy**: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.
+
+```docker-compose.yml
+# Docker Compose configuration for Loki and Alloy
+  loki:
+    image: grafana/loki:3.4.3
+    container_name: monitoring_loki2
+    ports:
+      - "3100:3100" # Expose Loki on port 3100
+    command: -config.file=/etc/loki/local-config.yaml    
+
+  alloy:
+    image: grafana/alloy:v1.8.1
+    container_name: monitoring_alloy
+    ports:
+      - 12345:12345 # HTTP server for Alloy
+      - 4317:4317   # gRPC endpoint for OpenTelemetry
+      - 4319:4318   # HTTP endpoint for OpenTelemetry
+    volumes:
+      - ./config.alloy:/etc/alloy/config.alloy # Mount Alloy configuration
+      - /var/run/docker.sock:/var/run/docker.sock # Access Docker socket
+    command: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy
+    depends_on:
+      - loki
+```
+
+Both Loki and Alloy have config files so let's have a look at them as well.
path: content/posts/2025/opentelemetry-logs.md
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

It would be beneficial to include the Loki configuration file as well for completeness. This gives the reader a full picture of the configurations required.
created_at: 2025-04-14T21:16:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
++++
+title = "Integrating OpenTelemetry Logs with Grafana Using Loki and Alloy"
+date = "2025-04-14T20:00:00Z"
+year = "2025"
+month= "2025-04"
+author = "funkysi1701"
+authorTwitter = "funkysi1701" #do not include @
+cover = "/images/grafana-loki-arch.png"
+images =['/images/grafana-loki-arch.png']
+tags = ["OpenTelemetry", "Grafana", "Loki", "Alloy", "Logging", "Monitoring", "Docker", "DotNet", "Tech"]
+category="tech"
+description = "Learn how to integrate OpenTelemetry logs with Grafana using Loki and Alloy for efficient log aggregation and monitoring in your .NET applications."
+showFullContent = false
+readingTime = true
+copyright = false
+featured = false
+draft = false
+aliases = [
+    "/adding-opentelemetry-logs-to-grafana",
+    "/posts/adding-opentelemetry-logs-to-grafana",
+    "/posts/2025/04/14/adding-opentelemetry-logs-to-grafana",
+    "/2025/04/14/adding-opentelemetry-logs-to-grafana" 
+]
++++
+Logs are a critical part of monitoring and debugging modern applications. By integrating OpenTelemetry logs with Grafana using Loki and Alloy, you can centralize your log data, making it easier to analyze and monitor your .NET applications. In this blog, I'll walk you through the setup process and share how these tools work together to streamline log aggregation and visualization.
+
+I have blogged about [Grafana](/posts/2025/setting-up-grafana/) before but until now I haven't added logs to Grafana let's have a look at how that works.
+
+My dotnet application makes use of OpenTelemetry. I have been sending this telemetry to an Aspire Dashboard running in Docker. This allows me to view logs, metrics and traces.
+
+Grafana has several tools that can help with logs.
+
+- **Loki**: A log aggregation system designed to store and query logs from applications and infrastructure.
+- **Alloy**: An OpenTelemetry collector that processes and forwards telemetry data.
+- **OpenTelemetry**: A set of APIs, libraries, and tools for collecting and exporting telemetry data like logs, metrics, and traces.
+
+I am using Alloy to collect OpenTelemetry from my application and send it to Loki, The logs in Loki can then be read by Grafana.
+
+## Setting Up Loki and Alloy with Docker Compose
+
+To start off let's add Alloy and Loki to my docker compose file.
+
+### Docker Compose Configuration
+
+The `docker-compose.yml` file defines the services for Loki and Alloy. Here's what each section does:
+
+- **Loki**: Runs the Loki container on port 3100 and uses a local configuration file.
+- **Alloy**: Runs the Alloy container, exposing ports for receiving telemetry data and processing logs.
+
+```docker-compose.yml
+# Docker Compose configuration for Loki and Alloy
+  loki:
+    image: grafana/loki:3.4.3
+    container_name: monitoring_loki2
+    ports:
+      - "3100:3100" # Expose Loki on port 3100
+    command: -config.file=/etc/loki/local-config.yaml    
+
+  alloy:
+    image: grafana/alloy:v1.8.1
+    container_name: monitoring_alloy
+    ports:
+      - 12345:12345 # HTTP server for Alloy
+      - 4317:4317   # gRPC endpoint for OpenTelemetry
+      - 4319:4318   # HTTP endpoint for OpenTelemetry
+    volumes:
+      - ./config.alloy:/etc/alloy/config.alloy # Mount Alloy configuration
+      - /var/run/docker.sock:/var/run/docker.sock # Access Docker socket
+    command: run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy
+    depends_on:
+      - loki
+```
+
+Both Loki and Alloy have config files so let's have a look at them as well.
+
+```alloy.config
+otelcol.receiver.otlp "default" {
+  http {}
+  grpc {}
+
+  output {
+    logs    = [otelcol.processor.batch.default.input]
+  }
+}
+
+otelcol.processor.batch "default" {
+    output {
+        logs = [
+          otelcol.exporter.otlphttp.loki.input,
+        ]
+    }
+}
+
+otelcol.exporter.otlphttp "loki" {
+  client {
+    endpoint = "http://loki:3100/otlp"
+  }
+}
+```
+
+### How the Components Work Together
+
+1. **Application Logs**: The .NET application generates logs and sends them to Alloy on port 4317.
+2. **Alloy Processing**: Alloy processes the logs and forwards them to Loki on port 3100.
+3. **Loki Storage**: Loki stores the logs, making them available for querying.
+4. **Grafana Visualization**: Grafana connects to Loki as a data source, allowing you to visualize and analyze the logs.
+
+![Architecture Diagram](/images/grafana-loki-arch.png)
+
+
+### Handling Aspire Dashboard Logs
+
+By default, sending logs to Alloy and Loki means Aspire Dashboard will no longer receive them. To resolve this, you can configure the `AddOpenTelemetryExporters` method in your .NET application to send logs to multiple destinations.
+
+```Extensions.cs
+if (useOtlpExporter)
+{
+    // The following lines enable the OTLP exporter (requires the OpenTelemetry.Exporter.OpenTelemetryProtocol package)
+    builder.Services.AddOpenTelemetry()
+    .WithLogging(logging => logging.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }))
+    .WithLogging(logging => logging.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["GrafanaExporter"]);
+    }))
+    .WithMetrics(metrics => metrics.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }))
+    .WithTracing(tracing => tracing.AddOtlpExporter(options =>
+    {
+        options.Endpoint = new Uri(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+    }));
+}
+```
+
+If I update the AddOpenTelemetryExporters method in my Extensions.cs file in my .Net Aspire ServiceDefaults project, I can get my logs (or traces/metrics) to be sent to as many different places as I want. In my case I am sending to Allot and Aspire Dashboard.
path: content/posts/2025/opentelemetry-logs.md
user: login: gemini-code-assist[bot]
body: ![medium](https://img.shields.io/badge/priority-medium-yellow)

Consider adding a link to documentation or a more detailed explanation of how to configure the `AddOpenTelemetryExporters` method to send logs to multiple destinations. This would provide readers with a more concrete path to follow.
created_at: 2025-04-14T21:16:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-14T21:20:11Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=funkysi1701_funkysi1701.github.io&pullRequest=1717) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=funkysi1701_funkysi1701.github.io&pullRequest=1717&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=funkysi1701_funkysi1701.github.io&pullRequest=1717&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=funkysi1701_funkysi1701.github.io&pullRequest=1717&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=funkysi1701_funkysi1701.github.io&pullRequest=1717&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=funkysi1701_funkysi1701.github.io&pullRequest=1717&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=funkysi1701_funkysi1701.github.io&pullRequest=1717)


author_association: NONE