I want to attach the user's "client_id" claim as a property to every request sent to Application Insights.
From what I've read, I should be implementing ITelemetryInitializer
but I need the HttpContext
for the request in order to retrieve "client_id". See my initialiser:
public class ClaimTelemetryInitializer : ITelemetryInitializer
{
public HttpContext HttpContext { get; set; }
public void Initialize(ITelemetry telemetry)
{
this.AddTelemetryContextPropertFromClaims(telemetry, "client_id");
}
private void AddTelemetryContextPropertFromClaims(ITelemetry telemetry, string claimName)
{
if (HttpContext != null)
{
var requestTelemetry = telemetry as RequestTelemetry;
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
}
I could create an action filter to set the context each time, but this feels awful:
public class TrackClaimsAttribute : ActionFilterAttribute
{
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var initialiser = TelemetryConfiguration.Active.TelemetryInitializers.OfType<ClaimTelemetryInitializer>().Single();
initialiser.HttpContext = context.HttpContext;
return base.OnActionExecutionAsync(context, next);
}
}
Is there a better way to achieve what I want to do?
Add/modify properties: ITelemetryInitializer. Use telemetry initializers to enrich telemetry with additional information or to override telemetry properties set by the standard telemetry modules. For example, Application Insights for a web package collects telemetry about HTTP requests.
AddApplicationInsightsTelemetry prioritizes configuration from appsettings. json , irrespective of the order in which providers are added. Use the services. AddApplicationInsightsTelemetry(IConfiguration) method to read configuration from IConfiguration without this preferential treatment for appsettings.
Add Application Insights automatically From within your ASP.NET web app project in Visual Studio: Select Project > Add Application Insights Telemetry > Application Insights Sdk (local) > Next > Finish > Close.
Enable monitoringSelect Application Insights in the left pane for your app service. Then select Enable. Create a new resource or select an existing Application Insights resource for this application. When you select OK to create a new resource, you're prompted to Apply monitoring settings.
You should implement the WebTelemetryInitializerBase which provides you the HttpContext.
Your code should look like:
public class ClaimTelemetryInitializer : WebTelemetryInitializerBase
{
protected override void OnInitializeTelemetry(
HttpContext platformContext,
RequestTelemetry rootRequestTelemetry,
ITelemetry telemetry) {
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
I would suggest to inject an HttpContextAccessor instance in the ClaimTelemetryInitializer class's constructor, and then you could use it to extract values from the HttpContext. Or, even better, create a base class for your TelemetryInitializer, and use it's constructor to inject the HttpContextAccessor instance.
For example:
protected ClaimTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
var context = this.httpContextAccessor.HttpContext;
if (context == null)
{
return;
}
var claim = context.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
//Do logic here...
}
I wish this were designed into AppInsights but you can directly use the static HttpContext.Current
. You can use it's per-request Items
dictionary as a short term (near stateless) storage space to deliver your custom values to the custom telemetry handler.
So try
class AppInsightCustomProps : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
// Is this a TrackRequest() ?
if (requestTelemetry == null) return;
var httpCtx = HttpContext.Current;
if (httpCtx != null)
{
var customPropVal = (string)httpCtx.Items["PerRequestMyCustomProp"];
if (!string.IsNullOrWhiteSpace(customPropVal))
{
requestTelemetry.Properties["MyCustomProp"] = customPropVal;
}
}
}
}
And to program the desired custom property, anywhere in your request pipeline have something like
if (HttpContext.Current != null)
{
HttpContext.Current.Items["PerRequestMyCustomProp"] = myCustomPropValue;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With