I'm currently trying to log exceptions in Application Insights for later investigation.
However, any exception I try to log with the TrackException method does not appear in Application Insights.
The docs for Application Insights event filtering state the following:
Exception - Uncaught exceptions in the server, and those that you log by using TrackException().
I'm using the following code to log my exception:
private static readonly TelemetryClient Client = new TelemetryClient{InstrumentationKey = ApplicationInsightsSettings.InstrumentationKey};
public static void TrackException(Exception exception, string traceReference)
{
var properties = new Dictionary<string, string> {{"Trace Reference", traceReference}};
Client.TrackException(exception);
Client.TrackException(exception, properties);
Client.TrackEvent(traceReference);
}
Whenever I run this code only an event is logged but none of the exceptions are.
Related
Is there any way to track if end-point is available for Tcp Sink logging ?
For example locally on my machine I do not have FileBeat setup, while its working on Staging machine.
The way I initialize Logger
private readonly ILogger _tcpLogger;
public TcpClient(IOptions<ElasticSearchConfig> tcpClientConfig)
{
var ip = IPAddress.Parse(tcpClientConfig.Value.TcpClientConfig.IpAddress);
_tcpLogger = new LoggerConfiguration()
.WriteTo.TCPSink(ip, tcpClientConfig.Value.TcpClientConfig.Port, new TcpOutputFormatter())
.CreateLogger();
}
and simple method just to submit log
public void SubmitLog(string json)
{
_tcpLogger.Information(json);
}
And in my case when its submitting json string locally, it just goes nowhere and I would like to get an exeption/message back.
ideally on json submit, but during initialization is Ok.
Writing to a Serilog logger is meant to be a safe operation and never throw exceptions, and that's by design. Thus any exceptions that happen when sending those messages would only appear in the SelfLog - if you enable it.
e.g.
// Write Serilog errors to the Console
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));
The example above is, of course, just to illustrate the SelfLog feature... You'll choose where/how to display or store these error messages.
Now, if the operation you're logging is important enough that you'd want to guarantee it succeeds (or throws exception if it doesn't) then you should use Audit Logging, i.e. Use .AuditTo.TCPSink(...) instead of .WriteTo.TCPSink(...)
Azure Function 2.0 Does not deliver exceptions to App Insights following this guide and several others
I've written the following method to report exceptions to app insights:
public void PublishOperationResult(Exception ex, string CustomMessage, Guid invocationId)
{
var _client = new TelemetryClient
{
InstrumentationKey = "my-key"
};
_client.Context.Operation.Id = invocationId.ToString();
_client.Context.Operation.Name = "SnapshottingViewsException";
var exception = new ExceptionTelemetry(ex);
var properties = new Dictionary<string, string>
{
{"CustomMessage", CustomMessage}
};
foreach (var property in properties)
{
exception.Properties.Add(property);
}
_client.TrackException(exception);
}
When calling the method I can see the exception being logged in the Visual Studio debug output but nothing appears in App Insights, both locally and on an azure consumption plan.
Debug message:
Application Insights Telemetry: {"name":"Microsoft.ApplicationInsights.653f95d8909341b5a971eaa88c40606b.Exception","time": ...
If I disable this functionality and merely throw the exception everything works as expected.
Versions:
Microsoft.NetCoreApp 2.1.0
Microsoft.SDK.Functions 1.0.29
Microsoft.ApplicationInsights.AspNetCore 2.7.1
Solved, sort of.
The exception in question that I was testing with came from an SQL client. When thrown up this is seen as an exception by AppInsights but when reported by the TelemetryClient its seen as a Dependency Error with a different message/title which I wasn't looking for. And thus a little more difficult to spot.
I added those Nuget Packages to my WPF App:
Microsoft.ApplicationInsights.Log4NetAppender
Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel
The logger is logging in a file, that works. But no data is transferred to Azure.
I got this error:
AI: Server telemetry channel was not initialized. So persistent storage is turned off. You need to call ServerTelemetryChannel.Initialize(). Currently monitoring will continue but if telemetry cannot be sent it will be dropped.
My Question: Where (in the code) should i initialize the telemetry channel? And why do i have to do this? What's the appender for if i have to add a telemetry client (with config) anyways?
Update 0603:
my app.config:
Debug with visual studio:
Update: please follow the screenshot below, and try to find the info you send. And if you still cannot find the info, please provide you detailed code(remove the personal/important data like instrumentation key, and also provide us the nuget package and version you're using).
1.click the search button in overview page:
2.in the search screen, make the Local time and Event types are set correctly, then try to search the message:
You'd better provide the code to set log4net and app insights key.
I did a simple test with wpf project, the below code works fine:
public partial class MainWindow : Window
{
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
log.Info("wpf aaaa11111");
InitializeComponent();
}
}
You get the error "AI: Server telemetry channel was not initialized", maybe due to some incorrect configuration, like use the following code in the above working code:
//when add the code, it will cause the error you mentioned.
TelemetryConfiguration.Active.TelemetryChannel = new ServerTelemetryChannel();
If you have to add a telemetry client (with config), and with proper configuration, both log4net and telemetry client can send data to application insights. The code like below:
public partial class MainWindow : Window
{
private readonly TelemetryClient telemetryClient;
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
//configure the key here for log4net
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
var config = new TelemetryConfiguration();
//configure the key here for telemetry client
config.InstrumentationKey = "the key";
telemetryClient = new TelemetryClient(config);
log.Info("wpf aaaa333");
log.Info(TelemetryConfiguration.Active.TelemetryChannel.ToString());
telemetryClient.TrackTrace("it is going to start!");
InitializeComponent();
}
}
So, finally everything works. I offer the required steps here again:
Add NugetPackages:
log4net, Microsoft.ApplicationInsights, Microsoft.ApplicationInsights.Log4NetAppender and Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel to the Project
In MainWindow.xaml.cs:
private static readonly ILog log = LogManager.GetLogger(typeof(MainWindow));
public MainWindow()
{
TelemetryConfiguration.Active.InstrumentationKey = "the key";
log4net.Config.XmlConfigurator.Configure();
log.Info("wpf aaaa11111");
InitializeComponent();
}
}
In App.config:
Done
Big thanks to #Ivan Yang for his solution and his time helping me!
Is there anyway to capture handled exceptions when CreateErrorResponse() is used to return Error response with API methods?
I currently have registered a simple global exception loggger for any exceptions, however for some api responses including Model Filter attribute, I'm CreateErrorResponse() to return error responses but this doesn't to enter the Log() method in the Global Exception Logger.
Example usage of CreateErrorResponse in an API method :
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
Global Exception Logger:
public class GlobalExceptionLogger : ExceptionLogger
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public override void Log(ExceptionLoggerContext context)
{
log.Error(context.Exception);
}
}
The only way to get Log() method to be called is rather than use CreateErrorResponse, throw an Exception instead.
Is this correct?
You should log the error and any trace info in the same negative flow where you are constructing and returning the Error Response.
Using exceptions to control application flow is bad practice, avoid it.
The global handlers use is to handle anything that you haven't already handled and should be for Very exceptional cases, you also log there and present the user with a generic error message, while you sort out the chaos in the back of course :)
If I misunderstood your question please correct me.
ASP.NET Web API 2.1 includes a new global error handling capability. I found an example that demonstrates how to log exceptions into ELMAH. But I use NLog to log errors to a database table. Is it possible to use Web API global error handling with NLog? If so, please provide an example.
It's actually quite simple, you either implement IExceptionLogger by hand or inherit from the base class, ExceptionLogger.
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
Nlog.LogException(LogLevel.Error, RequestToString(context.Request), context.Exception);
}
private static string RequestToString(HttpRequestMessage request)
{
var message = new StringBuilder();
if (request.Method != null)
message.Append(request.Method);
if (request.RequestUri != null)
message.Append(" ").Append(request.RequestUri);
return message.ToString();
}
}
Also add it to the config:
var config = new HttpConfiguration();
config.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
You can find full sample solution here.
Other thing that might be handy WebApiContrib.Tracing.NLog package that allows you to use ITraceWriter interface to output to logs with NLog. A cool thing about ITraceWriter is that "all traces can correlate to the single request that caused that code to run (see this link)