# Dec 19th, 2024: \[EN\] Elastic observability and search in .NET Aspire

**URL:** <https://discuss.elastic.co/t/dec-19th-2024-en-elastic-observability-and-search-in-net-aspire/369417>\
**Category:** Advent Calendar\
**Created:** [December 19, 2024, 8:00am UTC](https://discuss.elastic.co/t/dec-19th-2024-en-elastic-observability-and-search-in-net-aspire/369417 "2024-12-19T08:00:22Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rossall](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rossall/32/114172_2.png) [@Rossall](https://discuss.elastic.co/u/Rossall)\
**Post date:** [December 19, 2024, 8:00am UTC](https://discuss.elastic.co/t/dec-19th-2024-en-elastic-observability-and-search-in-net-aspire/369417/1 "2024-12-19T08:00:22Z")

</div>

### Intro

[.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire) is an opinionated, cloud ready stack for building observable, production ready, distributed applications.

In this post we'll look at working with Elasticsearch in .NET Aspire, but firstly - on the observability side - let's learn just how easy it is to instrument our app with [OpenTelemetry](https://opentelemetry.io/) and see logs, metrics and traces in Elastic.

### Observability with OpenTelemetry and Elastic

.NET Aspire integrations automatically set up Logging, Tracing, and Metrics configurations using the [.NET OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-dotnet), and the telemetry data is exported to an endpoint using the OpenTelemetry protocol (OTLP).

Where to send the data, and identifiers such as a service name, are set via environment variables that .NET Aspire projects launch with. For example:

```auto
OTEL_SERVICE_NAME = ApiService
OTEL_RESOURCE_ATTRIBUTES = service.instance.id=1a5f9c1e-e5ba-451b-95ee-ced1ee89c168
OTEL_EXPORTER_OTLP_HEADERS, "Authorization=Bearer ABC123456789"
OTEL_EXPORTER_OTLP_ENDPOINT = http://localhost:4318

```

### Elastic Observability

As Elastic APM [supports OTEL natively](https://www.elastic.co/guide/en/observability/current/apm-open-telemetry.html), we can simply set the above environment variables to our specific Elastic APM instance details, as found in the Add data walkthrough for OTEL within Elastic APM:

 ![APMAddData.png](https://us1.discourse-cdn.com/elastic/original/3X/b/0/b079448ea3540c154cb9cbbfaede6da7c8c79e8d.png)

If we wanted, we can also overwrite the environment variables in C# code within the .NET Aspire AppHost project when setting up other project reference(s):

```auto
builder.AddProject<Projects.AspireOtelDefaults_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithReference(apiService)
    .WithEnvironment("OTEL_SERVICE_NAME", "WebFrontEnd")
    .WithEnvironment("OTEL_EXPORTER_OTLP_ENDPOINT", "https://myapmserveraddress.apm.cloud.es.io:443")
    .WithEnvironment("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer ABC123456789");

```

When we start the app, we get our data in Elastic APM:

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/a/1/a1b1a948fec663671e50064a2ca100aca00d2e13.png)

...and our logs (ingested to a data stream named e.g: "_logs-apm.app.yourappname_", so are still discoverable under the "logs-\*" data view):

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/4/a/4a2c280b9b3c4f8207ebdc5a4ef969a20e7678f0.png)

The logs are also correlated automatically with our APM data, keeping everything nicely together:

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/b/3/b3d607c666338af8ab27f39ca3bfdf64dd19368e.png)

Worth noting that we could have achieved this with no code changes - we'd only need to have set the environment variables necessary for OTEL!

### .NET Aspire Elasticsearch Integrations

Moving away from observability, Microsoft provide two integrations as Nuget packages for working with Elasticsearch: [Aspire.Hosting.Elasticsearch](https://www.nuget.org/packages/Aspire.Hosting.Elasticsearch), which allows you to host your own Elasticsearch instance in a container, and [Aspire.Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Aspire.Elastic.Clients.Elasticsearch) for working with existing Elasticsearch deployments.

We'll have a brief look at the client integration. Once you've added the [Aspire.Elastic.Clients.Elasticsearch](https://www.nuget.org/packages/Aspire.Elastic.Clients.Elasticsearch) package in your client-consuming project, within Program.cs, you register the Elasticsearch client instance like this (this example is for Elastic Cloud):

```auto
builder.AddElasticsearchClient(
    "elasticsearch",
    static settings =>
    {
        settings.ApiKey = "yourKeyHere";
        settings.CloudId = "ESS:CloudId";
    });

```

We can then work with the [.NET Elasticsearch client](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/introduction.html) as per usual:

```auto
app.MapGet("/weatherforecast", async () =>
{
    // Retrieve the Elasticsearch client from the container.
    var esClient = app.Services.GetRequiredService<ElasticsearchClient>();

    // Search for documents in the Elasticsearch index.
    var response = await esClient.SearchAsync<MyDoc>(s => s
        .Index("my-student-index")
        .From(0)
        .Size(10));

```
