Observing Spin Apps with OpenTelemetry and the .NET Aspire Dashboard

Thorsten Hans headshot

Nov 11, 2024

Thorsten Hans

Thorsten Hans headshot

Written by

Thorsten Hans

Thorsten Hans is a Senior Developer Advocate at Akamai. He guides developers and teams through understanding, adopting, and mastering emerging technologies to build reliable software and embrace the next wave of cloud computing. As Docker Captain, he continues to share his experiments and knowledge with the developer community.

Share

Gathering telemetry data is crucial for understanding how your apps behave at runtime and troubleshooting when things go sideways. In this post, we will explore how you can observe Spin apps when running locally using the .NET Aspire dashboard in standalone mode.

Automatic instrumentation done by Spin

Spin does automatic instrumentation, which means that it gathers metrics, traces, and logs at runtime without you having to do anything. To have Spin export that telemetry data to an OpenTelemetry Collector, all you need to do is set the OTEL_EXPORTER_OTLP_ENDPOINT environment variable before running your Spin apps.  Although there are many different observability stacks available for observing your Spin apps, this article illustrates how you can observe your apps using the .NET Aspire dashboard in standalone mode.

What is the .NET Aspire dashboard?

The .NET Aspire dashboard was created by the Microsoft .NET team as part of .NET Aspire. In a nutshell, .NET Aspire is a set of libraries that allows developers to orchestrate, run, and investigate distributed applications on their local machine (inner loop).  The .NET Aspire dashboard is a sophisticated dashboard for monitoring and inspecting all sorts of applications. It allows you to drill into logs, traces, metrics, and configuration data (environment variables) assigned to the individual components of your app. Check out all the features of the .NET Aspire dashboard.

The .NET Aspire dashboard is also available as a standalone variant, which is a single-container observability stack that you can use for observing your individual applications. Given the fact that we could provide all users of Spin a full-fledged observability stack just by spawning a single container during development time, we updated the pre-existing otel plugin to incorporate the standalone .NET Aspire dashboard.

Meet the otel plugin for Spin

The otel plugin for Spin is designed to assist you in developing and observing Spin applications on your local machine. Relying on Docker Compose, it can deploy and run different observability stacks within seconds and configure your Spin app(s) to send telemetry data to your observability stack of choice. As of today, the otel plugin for Spin supports two different observability stacks:

  • Default:  A multi-container observability stack based on Prometheus, Loki, Grafana, and Jaeger
  • Aspire:  A single-container observability stack using the standalone .NET Aspire dashboard

Installing the otel plugin for Spin

Before we dive into observing a Spin app, let’s install the otel plugin for Spin, which is as easy as executing the following commands:

# Update the Plugin Feed
spin plugins update

# Install the otel Plugin
spin plugins install --yes otel

Keep in mind that the otel plugin is leveraging Docker Compose under the covers, so ensure that you have Docker installed on your machine and verify that the Docker Daemon is running.

The easiest way to verify if your Docker installation works as expected is to run the official hello-world image (which will print some text to stdout) and remove it upon completion:

docker run --rm hello-world

What are we going to observe?

We will use an existing application to create a  demo application that we can observe. 

The Spin app we’re going to observe exposes data stored in a SQLite database via HTTP. Every HTTP response created by the Spin app also contains a custom x-spin-runtime header. Its value is loaded from the Spin app using its wasi-config implementation provided by the Spin SDK for JavaScript. 

The sample application is part of our Enterprise Architectures & Patterns repository on GitHub (see the http-crud-js-sqlite folder).

Setting up the observability stack and starting the Spin app

Once you have cloned the repository and navigated into the folder of the app (cd http-crud-js-sqlite), you have to set up the observability stack using spin otel setup --aspire.

Next, you can build your Spin app as you would normally do by executing a simple spin build. Because this app is built with JavaScript, you must have Node.js (version 21 or later) installed on your system.

The otel plugin also provides an up command, which you use for starting the Spin app and configuring the previously mentioned OTEL_EXPORTER_OTLP_ENDPOINT environment variable.

This will instruct Spin to send telemetry data to the OTLP endpoint exposed by the .NET Aspire dashboard:

# Setup the .NET Aspire Observability Stack
spin otel setup --aspire

# Build the Spin App
spin build

# Start the Spin App through the otel plugin
spin otel up -- --sqlite @migrations.sql

Running the observability stack and the Spin app on your local machine lets us send requests to the Spin app to generate telemetry data, which we will then inspect in the .NET Aspire dashboard:

# Read All Items
curl -iX GET localhost:3000/items

# Create a new Item
curl -iX POST -H "content-type: application/json" \
  -d '{"name": "Pet Mode", "active": true}' \
  localhost:3000/items

# Again, Read all Items
curl -iX GET localhost:3000/items

Inspecting Spin apps using the .NET Aspire dashboard

The .NET Aspire dashboard is exposed on port 18888 of your local machine, which you can either open manually in your browser or use the handy spin otel open aspire command.

Exploring logs

Logs that are either sent to stdout or stderr are automatically captured and forwarded to the OTLP endpoint by Spin. The .NET Aspire dashboard visualizes structured logs in the corresponding view of the dashboard UI.

Exploring metrics

As of this writing, the Spin runtime emits the execution count of your app as a metric. Navigate to the Metrics view of the .NET Aspire dashboard to see those metrics.

Exploring distributed traces

Distributed traces are crucial to understanding runtime behavior and dependency invocation for incoming requests handled by your Spin app(s). Spin automatically creates spans when your code interacts with external resources (e.g., interacting with a SQLite database or loading configuration data through the wasi-config implementation of Spin). Additionally, individual logs created from within your Spin app are treated as events and are embedded in the corresponding spans, which streamlines the investigation process. Navigate to the Traces view of the .NET Aspire dashboard to drill into traces and locate custom logs being represented as events of a particular span.

Removing the local observability stack

To remove the local observability stack, you can run spin otel cleanup, which will terminate and remove the .NET Aspire dashboard container on your local machine.

Conclusion

Automatic instrumentation by Spin provides essential telemetry data of your apps at runtime, allowing you to observe and inspect with ease. In conjunction with the standalone .NET Aspire dashboard, we can understand how our apps behave at runtime and drill into different telemetry data buckets with ease. The otel plugin for Spin streamlines the inner-loop experience by deploying, configuring, and integrating the observability stack with your Spin app(s).

Additional resources

Thorsten Hans headshot

Nov 11, 2024

Thorsten Hans

Thorsten Hans headshot

Written by

Thorsten Hans

Thorsten Hans is a Senior Developer Advocate at Akamai. He guides developers and teams through understanding, adopting, and mastering emerging technologies to build reliable software and embrace the next wave of cloud computing. As Docker Captain, he continues to share his experiments and knowledge with the developer community.

Tags

Share

Related Blog Posts

Developers
Building Serverless Apps with Spin and HTMX
July 09, 2025
A tutorial on building serverless applications using Fermyon Spin and htmx, demonstrating a shopping list app with a Rust back end and htmx-enhanced front end.
Developers
WebAssembly Jobs and CronJobs in Kubernetes with SpinKube & the Spin Command Trigger
May 11, 2025
Learn how to run WebAssembly workloads as Kubernetes Jobs and CronJobs using SpinKube and the Spin command trigger
Developers
Software Bill of Materials (SBOM) for your Spin Apps
January 16, 2025
Learn how to generate, scan, and distribute Software Bill of Materials (SBOM) for Spin applications using trivy and oras.