Recently we encountered an issue where our servers times out because of huge traffic surge, and those request telemetries were logged into AI as success with response code zero. Is there any way to configure response code zero to be termed as failure. Since request telemetries are captured automatically by AI so we dont have any handle on that
You can do it by using ITelemetryInitializer in your .NET core project.
To be termed as failure when response code is zero, you can set the Success property of request telemetry data as false. The sample code as below(using .NET core 2.2 for this test). And please make sure you're using the latest version of Microsoft.ApplicationInsights.AspNetCore 2.13.1.
Here is the custom ITelemetryInitializer:
public class MyTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
if (telemetry is RequestTelemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
//you can change the ResponseCode to "0" in your project
if (requestTelemetry.ResponseCode == "200")
{
// set Success property to false
requestTelemetry.Success = false;
}
}
}
}
then register it in the Startup.cs -> ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
//your other code
//here, register the custom ITelemetryInitializer
services.AddSingleton<ITelemetryInitializer, MyTelemetryInitializer>();
}
After executing the code, in azure portal -> your application insights -> Logs, you can see the Success property of request are made as false:
Related
I have a .Net core Web App API which accept request from front-end and then send HTTP POST request to Azure search to get search results.
I just use the build-in application insights logging log basic info in request and dependencies sources with zero logging code.
Now I want to extend the default Application Insights dependencies table to add the request body to Azure search.
What is the easiest way with minimum code?
As per your requirement, you can try the code below:
public class RequestBodyInitializer : ITelemetryInitializer
{
readonly IHttpContextAccessor httpContextAccessor;
public RequestBodyInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
if (telemetry is RequestTelemetry requestTelemetry)
{
if ((httpContextAccessor.HttpContext.Request.Method == HttpMethods.Post ||
httpContextAccessor.HttpContext.Request.Method == HttpMethods.Put) &&
httpContextAccessor.HttpContext.Request.Body.CanRead)
{
const string jsonBody = "JsonBody";
if (requestTelemetry.Properties.ContainsKey(jsonBody))
{
return;
}
//Allows re-usage of the stream
httpContextAccessor.HttpContext.Request.EnableRewind();
var stream = new StreamReader(httpContextAccessor.HttpContext.Request.Body);
var body = stream.ReadToEnd();
//Reset the stream so data is not lost
httpContextAccessor.HttpContext.Request.Body.Position = 0;
requestTelemetry.Properties.Add(jsonBody, body);
}
}
}
and add this to the Startup > ConfigureServices
services.AddSingleton<ITelemetryInitializer, RequestBodyInitializer>();
I'm trying to get some additional information about the message we received (basically its application-level outcome) into the Application Insights RequestTelemetry object for a WCF service.
Application Insights is logging request telemetry already. I created an ITelemetryInitializer that is being run, but at the time it runs I have no way that I can find to access information about the request, much less application-specific data from the request's context.
Is there somewhere I can put data that will be accessible by the ITelemetryInitializer at the time it runs?
public class WcfServiceTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
if (telemetry is RequestTelemetry rTelemetry)
{
// HttpContext.Current is populated at this point, but doesn't seem to be available within my application code.
// So is System.ServiceModel.OperationContext.Current
}
}
}
I had to face similar issue as the author described. Tried by implementing ITelemetryInitializer/ITelemetryProcessor but did not work.
Ended up writing my own MessageTraceTelemetryModule class implementing IWcfTelemetryModule and IWcfMessageTrace.
In the OnTraceResponse method, I added my custom property to the request telemetry by extracting value from OperationContext (which is accessible here!):
internal class MessageTraceTelemetryModule : IWcfTelemetryModule, IWcfMessageTrace
{
public void OnTraceResponse(IOperationContext operation, ref Message response)
{
if (OperationContext.Current.IncomingMessageProperties.TryGetValue("clientID", out object value))
{
operation.Request.Properties.Add("clientID", value.ToString());
}
}
}
New custom property visible in Application Insights telemetry - ClientID custom property Pic.
Note that the clientID property is being set in the OperationContext in Message Inspector:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if(!OperationContext.Current.IncomingMessageProperties.ContainsKey("clientID"))
OperationContext.Current.IncomingMessageProperties.Add("clientID", clientID);
}
Brief Context:
I implemented AAD Token based Authentication in a SOAP based WCF Service.
I needed to store the clientID from the token (which is validated in message inspector) and add the same as a custom property in the application insights request telemetry.
References:
Message Inspectors Documentation
Application Insights for WCF Documentation
In case it helps anyone, Application Insights automatically adds custom dimensions from data you store in System.Diagnostics.Activity.Current.AddBaggage(), or at least it does in asp.net 5. That might be available at the right place for you in WCF land.
e.g.
var currentActivity = System.Diagnostics.Activity.Current;
if (currentActivity != null)
{
currentActivity.AddBaggage("MyPropertyName", someData);
}
To log custom property, you can try like this...
public class CustomTelemetry : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
if (requestTelemetry == null) return;
requestTelemetry.Properties.Add("CustomProperty", "DummyValue");
}
}
And register CustomTelemetry at start of the application
TelemetryConfiguration.Active.TelemetryInitializers.Add(new CustomTelemetry());
Here is the Original Answer
MS Doc - Application Insights API for custom events and metrics
How to add custom dimension to Application Insights traces from .NET Core?
Any pointers are welcome.
If it's a .net core web project, you can use ITelemetryInitializer to add custom dimension.
First, add a new class named MyTelemetryInitializer to the project:
public class MyTelemetryInitializer: ITelemetryInitializer
{
public MyTelemetryInitializer()
{
}
public void Initialize(ITelemetry telemetry)
{
if (telemetry is TraceTelemetry traceTelemetry)
{
if (!traceTelemetry.Properties.ContainsKey("my_custom_1"))
{
//add the custom dimension here
traceTelemetry.Properties["my_custom_1"] = "test 12346";
}
}
}
}
Then in the Startup.cs -> ConfigureServices method, add these lines of code:
services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, MyTelemetryInitializer>();
And for testing purpose, in the HomeController, I have this Index method to send trace message:
public IActionResult Index()
{
TelemetryClient client = new TelemetryClient();
client.TrackTrace("it is a trace message from index page");
return View();
}
At last, run the project. Then nav to azure portal -> application insights, you can see the custom dimension is added.
better cast to ISupportProperties
if (telemetry is ISupportProperties traceTelemetry)
I have implemented a custom authentication scheme in a web service based on the ASP.NET Core webhost. I want to add Application Insights to this service.
When I successfully authenticate the user, I do something like this
telemetry.Context.User.Id = authenticatedUserName;
the telemetry object is the TelemetryClient I get from dependency injection.
Now, the problem is that the user ID does not show up among the requests, and I am not sure why.
This works
customEvents | where user_Id != "" and name == "MyCustomEvent"
but not this
request | where user_Id != ""
or this
dependencies | where user_Id != ""
Is there somewhere else where I should set the user ID for the request? I'd rather not create a custom event just for this.
I also tried setting the User property on the HttpContext object, but it does not seem to have any effect.
You should use ITelemetryInitializer for your purpose.
The following is my test steps(asp.net core 2.1):
Step 1:Add the Aplication Insights telemetry by right click your project -> Add -> Application Insights telemetry. The screenshot as below:
Step 2:Add a new class which implements the ITelemetryInitializer:
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
namespace WebApplication33netcore
{
public class MyTelemetryInitializer: ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var request = telemetry as RequestTelemetry;
if (request != null)
{
//set the user id here with your custom value
request.Context.User.Id = "ivan111";
}
}
}
}
Step 3:Register your telemetry initializer in ConfigureServices method in Startup.cs. For details, refer to here:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//Add the following code to register your telemetry initializer
services.AddSingleton<ITelemetryInitializer>(new MyTelemetryInitializer());
}
Step 4:Check the test result:
In visual studio Application Insights Search:
Then check it in Analytics:
Actually, the answer was surprisingly simple.
HttpContext ctx = ...
var requestTelemetry = ctx.Features.Get<RequestTelemetry>()
requestTelemetry.Context.User.Id = authenticationResult.UserName;
I wrote a custom logger for Application Insights in my app. I don't see any exceptions or ANY events when viewing App Insights in Azure Portal. Here is the logger class code, when I debug the code I do see a key assigned to the InstrumentationKey property, any ideas what I am doing wrong here? Do I need to attach other info to the client or configuration?
public class AppInsightsLogger:ILogger
{
private TelemetryClient ai;
public AppInsightsLogger()
{
ai = new TelemetryClient();
if (string.IsNullOrEmpty(ai.InstrumentationKey))
{
// attempt to load instrumentation key from app settings
var appSettingsTiKey = AppSettings.InsightsKey;
if (!string.IsNullOrEmpty(appSettingsTiKey))
{
TelemetryConfiguration.Active.InstrumentationKey = appSettingsTiKey;
ai.InstrumentationKey = appSettingsTiKey;
}
else
{
throw new Exception("Could not find instrumentation key for Application Insights");
}
}
}
public void LogException(Exception ex)
{
ai.TrackException(ex);
}
}
I created a new Console Application, installed latest stable ApplicationInsights SDK and pretty much kept your example, with minor but important difference - I either let it wait before shutting down after calling TrackException or added TelemetryClient.Flush()
namespace logtest
{
class Program
{
static void Main(string[] args)
{
AppInsightsLogger logger = new AppInsightsLogger();
logger.LogException(new InvalidOperationException("Is data showing?"));
// either wait for a couple of minutes for the batch to be sent of add ai.Flush() after ai.TrackException() to send the batch immediately
Console.ReadLine();
}
}
public class AppInsightsLogger
{
private TelemetryClient ai;
public AppInsightsLogger()
{
ai = new TelemetryClient();
if (string.IsNullOrEmpty(ai.InstrumentationKey))
{
// attempt to load instrumentation key from app settings
var appSettingsTiKey = "<ikey>";
if (!string.IsNullOrEmpty(appSettingsTiKey))
{
TelemetryConfiguration.Active.InstrumentationKey = appSettingsTiKey;
ai.InstrumentationKey = appSettingsTiKey;
}
else
{
throw new Exception("Could not find instrumentation key for Application Insights");
}
}
}
public void LogException(Exception ex)
{
ai.TrackException(ex);
// ai.Flush();
}
}
}
First I could see telemetry item sent in Visual Studio debug output window:
Then I could see telemetry leaving my machine in Fiddler, I also could see it was successfully accepted by our data collection endpoint.
And finally I could see it in the portal:
Nowadays, the question and the accepted answer are outdated. The contemporary approach is to add Microsoft.ApplicationInsights.AspNet NuGet package, which has logging out-of-the-box.
Please refer to the official docs.
The gist from the docs:
ApplicationInsightsLoggerProvider is enabled by default.
Captured log types can be configured in appsettings.json (or programmatically if you really need it)
"Logging": {
"LogLevel": {
"Default": "Warning"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Error"
}
}
}
For a version 3 webjob, I tried instantiating a TelemetryClient and calling TrackException(), as well as calling Flush() and waiting up to 180 seconds, but none of that worked. What does work is using the ILogger logger object and passing the exception into LogError().