November 27, 2024

Observing Spin Apps with OpenTelemetry and the .NET Aspire Dashboard

Thorsten Hans Thorsten Hans

otel tracing metrics logs aspire spin

Observing Spin Apps with OpenTelemetry and the .NET Aspire Dashboard

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. Automatic instrumentation means that Spin 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 this link to explore all 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 could use for observing your individual applications. Given the fact that we could provide all users of Spin a full-fledged observability stack - by just spawning a single container during development time - made us update the pre-existing otel plugin and 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 configures 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 .NET Aspire Standalone 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’ve 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 need some sort of demo application that we can observe. Because implementing a Spin App is not what this article is about, we will use an existing application.

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. 

Spin App Architecture

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. As 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

Awesome!

Having the observability stack and the Spin app running on your local machine, we can 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, you can either open the address 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.

Logs in .NET Aspire Dashboard

Exploring Metrics

At the point of writing this article, 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.

Metrics in .NET Aspire Dashboard

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.

Traces in .NET Aspire Dashboard

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 .NET Aspire standalone 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

If you want to dive deeper into observing your Spin Apps using the standalone.NET Aspire Dashboard, check out our video on YouTube:


🔥 Recommended Posts


Quickstart Your Serveless Apps with Spin

Get Started