[Parte 11] ASP.NET Core: Application Insights y Serilog
Published: 2022-04-25 18:43:30

# Introducción
Al tener aplicaciones en producción siempre es de suma importancia el poder monitorearlas. Monitorear una Web API tiene sus grandes beneficios y se ha convertido en un **MUST** al momento de yo manejar aplicaciones en ambientes de producción.

Saber como se comporta tu aplicación, que problemas de rendimiento tiene y hasta saber que errores genera es de vital importancia al operar un sistema. Siempre habrán errores y siempre habrá que arreglarlos. Hagamos que este proceso de *debugging* sea más sencillo para nosotros.

Como siempre, aquí encontrarás el [código](https://github.com/isaacOjeda/AspNetCoreMediatRExample/tree/parte-11) que aplica para este post.

# Application Insights
Application Insights es una herramienta que forma parte de la suite de [Azure Monitor](https://docs.microsoft.com/en-us/azure/azure-monitor/overview) el cual provee de un Application Performance Management y monitoreo para aplicaciones web que están en producción o corriendo en vivo en Azure o **en cualquier lado**.

Developers o profesionales de DevOps pueden usar Application Insights para:

- Automáticamente detectar anomalías de performance
- Ayuda a diagnosticar problemas utilizando las herramientas de analytics
- Ver el comportamiento de los usuarios al usar la aplicación
- Ayuda a mejorar continuamente la usabilidad y el performance de la aplicación

Funcionalidades de Application Insights:
- Soporta una gran variedad de lenguajes de programación, como .NET, node.js, java y python
- Funciona en aplicaciones hospedadas en servidores on-premises, híbrido o en cualquier nube pública
- Se puede integrar con procesos de DevOps
- Se puede conectar con muchas herramientas de desarrollo (Power BI, Alertas, Visual Studio, etc)
- Puede monitorear y analizar la telemetría de aplicaciones móviles

## ¿Cómo funciona?
Para usar Application Insights debemos de instalar un pequeño paquete (el SDK) en la aplicación, en visual studio se pude hacer incluso automáticamente, pero lo haremos manualmente más adelante.

Podemos monitorear cualquier servicio web o background service, incluso la parte de frontend con Javascript en una aplicación web. Como mencioné antes, las aplicaciones no están obligadas a estar hosteadas en Azure para que se puedan analizar.

La instrumentación ocurre en distintos `Threads` y no bloquea cualquier llamada que se hace a la aplicación, por lo que el impacto en la aplicación es pequeño.

El siguiente diagrama muestra un ejemplo de como Application Insights monitorea la aplicación y manda la telemetría a AI.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6z7t16qu69tkgtrg3smd.png)
 
## ¿Qué monitorea?
Application insights ayuda a los equipos de desarrollo a entender el uso y el performance de las aplicaciones, por lo que monitorea:

- Requests recibidos, tiempos de respuesta y fallas
  - Podríamos saber cuales son los métodos más lentos, más usados y los que más fallan
- Todas las dependencias (bases de datos, servicios externos, storage accounts, redis, etc)
- Excepciones
  - Todos los errores que ocurren en la aplicación podemos analizarlos e incluso debuggear el memory dump
- El frontend: visitas a las páginas, cuanto tardan en cargar y comportamiento de usuarios
  - También llamadas de javascript (requests realizados, tiempo de respuesta y errores)
- Cantidad de usuarios y sesiones únicas
- Indicadores de performance, como el CPU, memoria y uso de la red
- Diagnósticos del host, como docker o azure
- Trace logs de las apps, podemos hacer tracing de un request y ver como se ejecuto incluso si involucra distintos servicios
- En general custom events/logs y métricas que sirven para algún tracking que el negocio requiera

## Configurando Application Insights en ASP.NET Core
Realmente como mencioné antes, si usamos visual studio, podemos configurar application insights de una forma automática, pero me gusta hacerlo manualmente para entender bien que se configura.

> Nota 👀: Este post sigue siendo una continuación de la serie de artículos sobre distintos temas de ASP.NET Core. Si no tienes la solución, no dudes en visitar el repositorio en GitHub por que aquí omitiré mucho código.
> 

Comenzamos instalando los siguientes paquetes:

```xml
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.20.0" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="3.1.0" />
```

Estos dos paquetes son el SDK de Application Insights y un Sink de Serilog. Serilog lo hemos configurado en este [post](https://dev.to/isaacojeda/parte-9-aspnet-core-logging-con-serilog-48o4) y es bien útil combinarlos con Application Insights.

Para comenzar a recolectar telemetría de nuestra aplicación y empezar a usarla, necesitamos crear un Application Insights en Azure. Es bien sencillo y realmente no pide información que se te pueda dificultar.

Lo importante, es tener los connection strings / instrumentation keys de un application insights previamente creado:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/58kyvnowxetztog0ilw2.png)
 Y la configuración es extremadamente sencilla, nos vamos a **Program.cs** y agregamos la siguiente línea:
 
 ```csharp
// ... código omitido
builder.Host.UseSerilog();

// ... código omitido
builder.Services.AddApplicationInsightsTelemetry(); // <------ this one

var app = builder.Build();
// ... código omitido
```

Y agregamos la cadena de conexión en la configuración (appsettings.json o user secrets)
```json
{
    // Settings omitidos
    "ApplicationInsights": {
    "ConnectionString": "InstrumentationKey=<Instrumentation Key>;IngestionEndpoint=https://eastus-6.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/"
  }
}
```

Así de fácil, ya podemos empezar a monitorear nuestra aplicación. En este punto se monitorea casi lo más importante pero hay algo que nos falta, los logs y las excepciones.

Si ejecutamos así la aplicación y la empezamos a usar, vamos a poder ver tiempos de respuesta, que solicitudes se hacen, si las solicitudes fallan (mostrando únicamente el HTTP Code) y los indicadores del servidor como el CPU, memoria, etc.

Pero si recuerdan, al implementar CQRS y serilog, incluimos ya logs que nos pueden servir para el diagnostico de la aplicación si algo sale mal (los audit logs, las excepciones y entre otras cosas).

Por lo que, siempre recomendaré, es aprovechar el [Sink de Serilog](https://github.com/serilog-contrib/serilog-sinks-applicationinsights) para complementar esta herramienta.

Configurarlo, es igual de fácil. En **Program.cs** actualizamos:

```csharp
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .WriteTo.Console()
    .WriteTo.ApplicationInsights(app.Services.GetRequiredService<TelemetryConfiguration>(), TelemetryConverter.Traces) // <--- this one
    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();
```

Anteriormente ya teníamos configurado Serilog, por lo que solamente resta agregar el **Sink** a Application Insights que incluso ya instalamos al inicio de este post.

Lo que estamos diciendo aquí es, que todos los Logs que son generados por la aplicación, los guarde en Application Insights como del tipo **Traces**. Ya sean Information, Warning. Los Error / Exceptions serán del tipo Exception en Application Insights. Esto es bien super útil, por que nos permitirá ver traces de esta forma:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tn75n0l2m5hngdt9tqbx.png)
 Ya que previamente en nuestra aplicación, hemos configurado que se haga Logs de los errores, esto lo hacemos [aquí](https://dev.to/isaacojeda/parte-2-cqrs-y-mediatr-validando-con-fluentvalidation-14i0) implementando unos `ExceptionFilters`.
 
 Si exploramos un request, podemos ver todo bien detallado:
 
 ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0tu2i8qv0y79s5t6rtm.png)
 **Esto, es esencial, créanme, necesitan esto en sus aplicaciones en producción**
 
 Siempre va a salir algo mal, necesitamos las herramientas para investigar que sucede en nuestra aplicación.
 
 En mi Stack, application insights ha venido para quedarse.
 
 > Nota 👀: Existen otras herramientas para hacer esto mismo, pero dado a que yo soy Azure Based, esto me funciona al 100%. Open Telemetry y proyectos como Prometheus o Jeager ayudan bastante en esta misma tarea.
 > 

En resumen, con application insights en una Web Api podemos monitorear:

**Todas las operaciones realizadas**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/re5ife6bgqdxzpuz7kzz.png)
**Cuanto tardan las dependencias**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vf5gqjurexerfz4cxwy.png)
 
**Indicadores del servidor**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0382hn5blukkfasboj15.png)
 
**Métricas en tiempo real**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6mni8vfsg2f27wad9rvd.png)
Este es de los que son más útiles para mi, al intentar reproducir errores, podemos ver los logs **en tiempo real**.

Gracias a serilog, nos facilita la vida y manda los logs según lo configuremos.

### Message Templates
En el post de Serilog, mencioné la importancia de crear Message Templates en los logs y no "concatenar" strings en los logs. La razón de que es mejor usar message templates es por la generación de esta telemetría. Un Message Template se puede visualizar de esta forma:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ya31wnje24vm24v9mrtd.png)
El **Message** es lo que nosotros vemos en consola, pero todos esos **Custom Properties** nos ayudan incluso a buscar mejor según necesitemos. Aquí podríamos buscar por **RequestName**, **User** o algún dato en el **Request**.

### Búsqueda por Custom Properties

El beneficio real de usar los Message Templates y que Serilog los mande como Custom Properties, está al hacer búsqueda en los logs.

Application Insights nos deja hacer Queries con un lenguaje especial de Azure. Saber esto es bien útil, porque podemos automatizar muchas cosas (como generar alertas).

Si consultamos las operaciones realizadas por un usuario, podemos hacerlo:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a5ecop0uqj631afu74kv.png)
Aquí vemos que todo lo que el Message Template incluye, se agrega en el Trace de Application Insights.
 
Otro ejemplo, si queremos buscar por operación:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixotnm76e2xue23d63e8.png)
Ya con esto, incluso podríamos tener un sistema auditable (de eso hable en este [post](https://dev.to/isaacojeda/parte-7-aspnet-creando-un-sistema-auditable-31nf) utilizando Audit.NET).
 
Básicamente, lo que Serilog agrega como **Custom Properties** al mandar los logs a Application Insights son:

```json
{
  "AspNetCoreEnvironment": "Development",
  "RequestId": "0HMH6PLB0IKKE:00000015",
  "RequestPath": "/api/products",
  "ConnectionId": "0HMH6PLB0IKKE",
  "ActionName": "MediatrExample.WebApi.Controllers.ProductsController.CreateProduct (MediatrExample.WebApi)",
  "ActionId": "850584fd-aa63-4f96-a2a3-6fe791b279fe",
  "MessageTemplate": "{RequetsName}: {@User} with request {@Request}",
  "SourceContext": "MediatrExample.ApplicationCore.Common.Behaviours.AuditLogsBehavior",
  "User": "cbb809be-e383-44d0-9435-564017db0602",
  "Request": "{\"Description\":\"string\",\"Price\":0,\"_typeTag\":\"CreateProductCommand\"}",
  "RequetsName": "CreateProductCommand"
}
```
**Más** todo lo que incluyamos en el **Message Template**. En este caso, el message template incluye **RequestName**, **User** y **Request** ( y fíjate que Request, es otro objeto JSON)

# Conclusión
Aunque Application Insights no es gratis, no tiene un costo elevado para que no se considere en tu stack.

Uses o no Azure, AI puede usarse y obtener resultados muy similares (si no es que iguales).

Su integración con una aplicación de .NET es muy fácil, pero también lo es con los lenguajes soportados.

Espero te sea de utilidad y le des el uso que yo le doy.

# Referencias
- [Application Insights overview](https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview)
- [serilog-sinks-applicationinsights](https://github.com/serilog-contrib/serilog-sinks-applicationinsights)