Can ILogger be trusted to catch / log ALL uncaught exceptions? - asp.net-core

Title asks it all.
Is there ever, and if so when, would ILogger not log an uncaught exception?
Reason I am asking is; am configuring Rollbar and it logs everything ILogger logs plus uncaught exceptions. This creates 2 logs. I am considering disabling Rollbar's log uncaught exceptions with the belief that ILogger catches them all already.
This question isn't about Rollbar tho :)

No. ILogger is an interface. It doesn't do anything. Rather, implementations of ILogger should log uncaught exceptions. It sounds like Rollbar is already doing your logging so you should continue to use that for logging your uncaught exceptions, or switch to a different library like NLog, Serilog, or log4net.
Personally, I have found that some libraries do miss messages in different cases, so it's important to test your logging library. It's not enough to just have faith that the messages are being correctly written. You can write unit tests to make sure that your code is logging exceptions correctly with Moq. Here is an example from this article.
_loggerMock.Verify
(
l => l.Log
(
//Check the severity level
LogLevel.Error,
//This may or may not be relevant to your scenario
It.IsAny<EventId>(),
//This is the magical Moq code that exposes internal log processing from the extension methods
It.Is<It.IsAnyType>((state, t) =>
//This confirms that the correct log message was sent to the logger. {OriginalFormat} should match the value passed to the logger
//Note: messages should be retrieved from a service that will probably store the strings in a resource file
CheckValue(state, LogTest.ErrorMessage, "{OriginalFormat}") &&
//This confirms that an argument with a key of "recordId" was sent with the correct value
//In Application Insights, this will turn up in Custom Dimensions
CheckValue(state, recordId, nameof(recordId))
),
//Confirm the exception type
It.IsAny<NotImplementedException>(),
//Accept any valid Func here. The Func is specified by the extension methods
(Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
//Make sure the message was logged the correct number of times
Times.Exactly(1)
);
But, even this doesn't guarantee that Rollbar or some other logger will definitely get your message to the log location. You can only confirm this by observing the output of the logger.
You should also see this section of the ILogger documentation which explains how to configure logging and potentially filter them.

Related

ExceptionFilterAttribute may not be logging exceptions in ApplicationInsights

Do exceptions that are filtered with a custom ExceptionFilterAttribute logged to Application Insights?
I want to return a custom DTO in my custom ExceptionFilterAttribute filter, but I think exceptions are no longer logged into ApplicationInsights after that. This is for .NET Core 3.0.
I added a line with:
this.telemetryClient.TrackException(context.Exception);
to make sure I can see the exception but I'm not sure if my exceptions are logged twice now.
Does anyone know if ApplicationInsights will log exception if they enter ExceptionFilterAttribute? I can't find documentation for this.
I'm calling just in case also:
base.OnException(context);
Does anyone know if ApplicationInsights will log exception if they
enter ExceptionFilterAttribute?
Yes, it will log the exceptions, so you do not need to add this line of code this.telemetryClient.TrackException(context.Exception);. Just using base.OnException(context); is ok.
You can see this GitHub issue for the similar issue, the reason is that "With new Ilogger enablement by default, exceptions are automatically reported by application insights.".
I also check it via a simple test, the test result as below:

What are the Implications of WCF TimeoutException vs CommunicationException on method execution?

I'm making a call to a WCF service that will initiate a batch of credit card charges. If an exception occurs, I want to know whether it occurred prior to the method executing and cards actually being charged. For example, with a TimeoutException, there's no way to know whether the WCF method executed so I need to make sure those charges aren't retried until the situation is investigated. But if the network was just down, or the server cert expired, or anything else happened prior to the method actually executing, I can un-lock my records to be retried later without human intervention.
try
{
var response = wcfClient.ProcessBatch(paymentBatch);
wcfClient.Close();
//...
}
catch(CommunicationException)
{
//Safe to assume ProcessBatch did not execute?
wcfClient.Abort();
}
catch(TimeoutException)
{
//Indeterminate state. Have to assume operation may have succeeded server-side
wcfClient.Abort();
}
catch(Exception)
{
//Assuming operation may have succeeded server-side
}
This is using a wsHttpBinding. Does a CommunicationException guarantee the method did not execute or could it also be thrown during the response?
According to the CommunicationException documentation on MSDN, a CommunicationException Exceptioon is a superclass of errors that fall into two subcategories, both related to to errors in the SOAP datagram.
Conversely, a TimeoutException is pretty straightforward: "The exception that is thrown when the time allotted for a process or operation has expired." The allotted time is probably set by the owner of the service, and you may or may not have a mechanism by which to override it.
For future reference, two quick Bing searches returned both of the articles cited herein.

asp.net 5 (core 1) logging confusion - wanting to only see "debug" messages

I'm trying to get started using logging in an ASP.NET Core 1.0 application - but this is my first time using any sort of logging, and the built in solution is presenting me some confusion.
In my Startup.cs, I initialize logging as I've seen in the sample applications;
log.AddConsole(Configuration.GetSection("Logging"));
log.AddDebug();
This works fine, my Logging section in the config file is defined as follows;
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Debug",
"Microsoft": "Debug"
}
}
}
This all works fine, but the problem is that I see everything output to the screen, like this;
That information is not bad, of course - but it's a bit verbose and clutters up the command line. I'd really like to only see errors and debug-level messages, such as when I call them like this;
Logger.LogDebug("debug info");
But I'm very unclear about how to go about this.
Is there any way to achieve this level of tuning?
Update
after more working with it, if I create only a console with LogLevel.Error, I can get the immediate result I want - but then I lose any information of the other levels. Can non-relevant information (LogLevel.Information and lower) be sent to another place? Like the Output console in Visual Studio?
To answer your question you can implement an ILogger and then log what you want in the "public void Log". Inside of that method you can switch statement the LogLevel and write it to the console, write it to a DB, only write certain things, etc. The round about steps would be:
Create a class that implements ILogger. If you want to manually handle every log level and do something different with it you can do it there (as long as you haven't set the LogLevel too high in the startup). Here you can write to a Db, write to the console, email, whatever you want.
Create class that implements ILoggerProvider, fill in it's methods (CreateLogger is where you'll instantiate your ILogger you created in step 1).
Create an extension method to ILoggerFactor that looks something like this:
public static ILoggerFactory AddMyLogger(this ILoggerFactory loggerFactory, IHttpContextAccessor httpContextAccessor)
{
loggerFactory.AddProvider(new AppsLoggerProvider(httpContextAccessor));
return loggerFactory;
}
In the Configure method of the Startup, add something like this (what you pass down the line is up to you):
// Create our logger and set the LogLevel
loggerFactory.AddMyLogger(httpContextAccessor);
loggerFactory.MinimumLevel = LogLevel.Verbose;
Note: The ILoggerFactor was injected into the Configure method (ILoggerFactory loggerFactory).
ASP.NET Core defines the following six levels of logging verbosity:
Trace – For the most detailed messages, containing possibly sensitive information. Should never be enabled in production.
Debug – For interactive investigation during development: Useful for debugging but without long term value.
Information – For tracking the general flow of the application.
Warning – For unnormal events in the application, including errors and exceptions, which are handled and as such do not impact the application’s execution but could be a sign of potential probelms.
Error – For actual failures which cause the current activity to fail, leaving the application in a recoverable state though, so other activities will not be impacted.
Critical – For failures on the application level which leaves the application in a unrecoverable state and impacts the further execution.
These levels are sorted by verbosity from very verbose, to very quiet but with important consequences. This also means that Information is considered less verbose than Debug.
This means that when you configure a logger to show logging of the Debug verbosity, you always include the less verbose log levels as well. So you will also see Information. The only way to get rid of those Information log entries would be to set the verbosity to Warning or higher.
The amount of logging on the Information level was chosen deliberately by the ASP.NET Core team, to make sure that important parts are visible. It might seem very verbose to you, but it’s entirely by design. In general, it’s more useful to log more than too little, so in case you actually need to access the logs, you have enough context information to make the logs actually useful.
If you want to hide that information, you could for example set the log level for Microsoft.AspNet.Hosting to Warning. Or alternatively, set the log level to Warning in general, but set it to Debug for your application’s namespaces to only see your own logging output.
You could also log to files and utilize a log file viewing utility (e.g. TailBlazer) to access the logs while using filters to focus on the parts you are interested in.

NServiceBus UnitOfWork to swallow certain exceptions and avoid message failure

I have an interesting use case where certain exception types mean "This message is no longer valid and should be ignored" but this code doesn't have any awareness of the Bus in order to call Bus.DoNotContinueDispatchingCurrentMessageToHandlers().
I loathe boilerplate code like try/catch blocks that need to be present in every single message handler. So I started implementing a UnitOfWork to handle and swallow the exception, but I can't find a way to tell the framework that "Yes, this code generated an exception, but forget about that and just complete the transaction."
Bus.DoNotContinueDispatchingCurrentMessageToHandlers() does not work. I tried having an ITransport injected and calling AbortHandlingCurrentMessage() but that caused the entire universe to blow up. Even stepping through the source code I seem to be at a loss.
Note that it very well may be that this is a horrible idea, because faking that there is no exception when there is in fact an exceptional case would cause the transaction to commit, causing who knows how many bad unknown side effects. So it would be preferable to have a method that still rolls back the transaction but discards the message. But I would be interested in a potential "Yes I know what I'm doing, commit the transaction regardless of the exception" option as well.
As of NServiceBus version 4.4 you can control this by injecting a behavior into our handler pipeline.
This let's you control which exceptions to mute.
class MyExceptionFilteringBehavior : IBehavior<HandlerInvocationContext>
{
public void Invoke(HandlerInvocationContext context, Action next)
{
try
{
//invoke the handler/rest of the pipeline
next();
}
//catch specific exceptions or
catch (Exception ex)
{
//modify this to your liking
if (ex.Message == "Lets filter on this text")
return;
throw;
}
}
There are several samples of how this works:
http://docs.particular.net/samples/pipeline/
That said I totally agree with Ramon that this trick should only be used if you can't change to design to avoid this.
A dirty solution would be having a unit of work test the exception, put the message id in a shared 'ignore' bag (concurrent dictionary in memory, db, what works for you) , let it fail so that everything is rolled back, in the retry have a generic message handler compare the message ID and let that call Bus.DoNotContinueDispatchingCurrentMessageToHandlers()
If you do not want to work with a unit of work then you could try to use the AppDomain.FirstChanceException.
I wouldn't advice any of these as good solution :-)
Why would you like to 'swallow' unhandled exceptions?
If you want to ignore an exception then you should catch these in the handler and then just return and log this.
What I'm more interested in is what about state? You maybe have already writen to a store. Shouldn't these writes be rolled back? If you swallow an exception the transaction commits.
It seems to me you are running in a kind of 'at least once delivery' environment. THen you need to store some kind of message id somewhere.
Or is it an action initiated by several actors based on a stale state? In that case you need to have first/last write wins construction that just ignores a command based on a stale item.
If you handl an event then swallowing a exception seems not correct. They usually say that you can ignore commands but that you always have to handle events.
Shouldn't this be part of validation? If you validate a command then you can decide to ignore it.

How do I redirect all errors, including uncaught exceptions, NSLog calls, and other logs, to a log file on Mac OS X?

I am attempting to find a logging framework for a Cocoa application, written in ObjC.
What I've attempted so far:
Use NSLog, but then realise that it is very hard to configure and redirect. I suppose I could hack it and write a macro that obtains the information I want, such as thread ID, current function, current line, current file, current time, the message, etcetera, and then uses NSLog, however...
NSLog ultimately uses NSLogv, which ultimately uses asl, so I thought "fantastic", I tried using asl instead, with the default client and context (If I was doing this properly, I would've had to create a new client for each thread), however, unless I create a macro, this is also very verbose, and I noticed that the logs sent via asl got broadcast system wide, whereas NSLog only logged to stderr, and I want them to both go to the same log!
I then noticed that errors, are formatted in a different way (different datestamp, etc), so there is now a third logging context.
What l logging framework setup can I use to have ALL messages logged through that framework in a convenient fashion so that if there is a problem with an application, a developer can get the log files, and figure out what went wrong?
I don't want to simply redirect stderr, I want to have a structured log output that contains all of the logs. I don't want some logs going to standard output, I don't want any logs sent to a syslogd, I just want all the logs written to a single file, that reliably identifies all the pertinent information about that log message (such as thread ID, message, the function that called the logger, etcetera), in format that is easy to view and visualise.
What I want is to redirect all current logs to the new destination.
Does anyone have any suggestions?
EDIT:
Effectively, what I want to do, in ObjC terms is:
Do "method swizzling" on the NSLog function. Is this possible? Is it possible to (re)configure the use of the Apple System Logger to override any prior configuration of the service within the same application?
Determine all the places where I have to catch unhandled exceptions. THis includes, but possibly isn't limited to: Unhandled Cocoa Exceptions. Unhandled ObjC exceptions. Unhandled C++ exceptions. Unix Signals.
Catch and log the stack for errors such as those raised by CoreGraphics. (The ones that simply log a message saying "Add a breakpoint using your debugger!!!").
You can intercept NSLog() messages (but not ASL in general) using _NSSetLogCStringFunction(). It’s documented here for WebObjects 4 for Windows, but it exists in current Mac OS and iOS releases too. However, it’s a private function that may go away at any time, so you shouldn’t rely on it in released code.
If you want to be able to safely do this for non-debug builds, I suggest duplicating this enhancement request on Radar.
You can use the Foundation function NSSetUncaughtExceptionHandler to set a callback function that will handle all uncaught exceptions:
void CustomLogger(NSString *format, ...) {
//do other awesome logging stuff here...
}
void uncaughtExceptionHandler(NSException *exception) {
//do something useful, like this:
CustomLogger(#"%#", [exception reason]);
}
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
For NSLog, you can use a macro to override it :)
#define NSLog(...) CustomLogger(__VA_ARGS__);
You can redirect standard error output to a file. Here is the method that redirects console output into a file in application’s Documents folder. This can be useful when you want to test your app outside your development studio, unplugged from your mac.
-(void) redirectNSLogToDocuments {
NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [allPaths objectAtIndex:0];
NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:#"yourFile.txt"];
freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}
After executing this method all output generated by NSLog will be forwarded to specified file. To get your saved file open Organizer, browse application’s files and save Application Data somewhere in your file system, than simply browse to Documents folder.