Reputation: 2824
I'm trying to get some extra information into Application insights from our .net core MVC application. I've found the following post: Adding custom properties for each request in Application Insights metrics
In the answer they use an custom telemetry initializer and that works if you want some request data or something.
Now we have an set of middleware in our application. They translate some of the headers into readable content.
Of course we could log the headers and search on all different values that those can have. But we would like to have the result from the middleware into the properties of application insights.
Anyone an idee on how to use the some of the outcome of the middleware into properties of the Application Insights request telemetry?
Upvotes: 1
Views: 4917
Reputation: 45071
Instead of putting the data within the middleware into HttpContext
and running an TelemetryInitializer
, you could directly add your desired data into the telemetry object within the middleware:
public class TelemetryMiddleware
{
private const string _BodyKey = "Body";
private readonly RequestDelegate _next;
public TelemetryMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
httpContext.Request.EnableBuffering();
if (httpContext.Request.Body.CanRead
&& (httpContext.Request.Method == HttpMethods.Put
|| httpContext.Request.Method == HttpMethods.Post
|| httpContext.Request.Method == HttpMethods.Patch))
{
// The needed method to access telemetry object within middleware
var telemetry = httpContext.Features.Get<RequestTelemetry>();
if (telemetry != null
&& !telemetry.Properties.ContainsKey(_BodyKey))
{
var oldPosition = httpContext.Request.Body.Position;
httpContext.Request.Body.Position = 0;
using (var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8, false, 4096, true))
{
var body = await reader.ReadToEndAsync();
if (!string.IsNullOrEmpty(body))
telemetry.Properties.Add(_BodyKey, body);
}
httpContext.Request.Body.Position = oldPosition;
}
}
await _next(httpContext);
}
}
Building into the pipeline is the same as for every middleware:
app.UseMiddleware<TelemetryMiddleware>();
Upvotes: 0
Reputation: 2824
Got the right idea from @svoychik. The middleware adds the output values to the HttpContext.Items. See the example:
using Microsoft.AspNetCore.Http;
using System.Text;
using System.Threading.Tasks;
namespace Test.API.Middleware
{
public class ValueMiddleware
{
private readonly RequestDelegate next;
public ApiKeyMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext httpContext)
{
if (!context.Items.ContainsKey("ApplicationData"))
{
httpContext.Items["ApplicationData"] = "Important Data";
}
}
}
}
Then when you need to get all those items into application insights you can just use the following Initializer:
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Http;
namespace Test.API.TelemetryInitializers : ITelemetryInitializer
{
public class HttpContextItemsTelemetryInitializer
{
private readonly IHttpContextAccessor httpContextAccessor;
public HttpContextItemsTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
var context = httpContextAccessor.HttpContext;
if (context == null)
{
return;
}
foreach (var item in context.Items)
{
var itemKey = item.Key.ToString();
// Remove some pollution that Microsoft and the systems adds to the HttpContext Items.
if (itemKey.Contains("Microsoft") || itemKey.Contains("System"))
{
continue;
}
if (!telemetry.Context.GlobalProperties.ContainsKey(itemKey))
{
telemetry.Context.GlobalProperties.Add(itemKey, item.Value.ToString());
}
}
}
}
}
Setup the initializer and the application insights in your Startup.cs as in the following example:
using Test.API.TelemetryInitializers;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace Test.API
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<ITelemetryInitializer, HttpContextItemsTelemetryInitializer>();
services.AddApplicationInsightsTelemetry();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ValueMiddleware>();
app.UseMvc();
}
}
}
Then it just add all the values of HttpContext.Items to your application insights.
Upvotes: 5