Disable log formatting exceptions

In my API, I have a small hierarchy of exceptions derived from std::exception . I have an Exception base class that contains an error code, file, line and function. Other more specific exceptions are derived from Exception . For example, one derived class adds an error code for a particular platform, as well as a field that identifies which function returned the error code. This seems like a simplified version of system_error , but I canโ€™t use the C ++ 11 functions (I was stuck with VS2005 and without Boost).

I need to log these exceptions with my logging class. I want the exceptions to be logged in a specific format. After reading various forums on the Internet and reading Recommendations for raising errors and eliminating errors , I donโ€™t think that the function of each exception or any other virtual function inside Exception is the right place to format the exception for logging. Therefore, my what functions simply return the class name.

When catching exceptions, I often want to catch very general exceptions, usually std::exception , and pass them to the logger. I donโ€™t want to catch individual exceptions very often, because I try to prevent exceptions from the API (the general part of my API is in C), and there may be several exceptions that can occur. I want to avoid code like:

 try { /* blah */ } catch {DerivedException const& ex) { logger.log(ex); } ... catch {Exception const& ex) { logger.log(ex); } 

So, in my logging class, my log function takes an argument std::exception . It then uses typeid to compare the parameter with various classes of exceptions, cast to the appropriate type, and then call the logging function specialized for that type of exception. This is essentially the same method described in this other post .

I use typeid instead of dynamic_cast because dynamic_cast can succeed for any valid downcast and for the purpose of serving code, I really don't want the order of my if in the log function to be important.

So what is a decent design? It seems to me wrong to use typeid like this, but I think I have good reasons for this. I did not see the โ€œwildโ€ exception handling because we mainly work with C, so I have not seen too many approaches to this issue. Are there other ways to separate the exceptions from their journal formatting, which I should be aware of?

EDIT: what I decided to implement
I accepted the offer to use the visitor template, but adapted it to my situation. I wanted to catch std::exception , since they can be selected just like my own, but format the log message based on the type of exception.

Each of my exception classes is derived from my base class Exception and implements a virtual accept function. I created an ExceptionLogger class that implements the ExceptionVisitor interface that provides visit functions.

The LogFile class has an ExceptionLogger instance, as well as an overload of its log function, which takes the std::exception parameter. In the log function, I am trying to use dynamic_cast for my base type Exception . If this succeeds, I call the accept function of the exception, otherwise I call the function ExceptionLogger::visit(std::exception const&) directly. Since std::exception does not implement my accept function, I need dynamic_cast so that I can determine if more detailed logging is possible.

I decided to do this instead of a series of if checking typeid , because:

  • This is a named design template that I can send to future companions to
  • If the maintainer adds a new exception from my Exception database, but forgets to implement a new visit function for this exception, I still get the log that was implemented for the Exception database โ€” file, line number, and function.

    If I implemented a series of if , I would have to go back to std::exception logging, which was supposed to print what results, or I could try a dynamic_cast before an Exception .

    Of course, I would prefer a compiler error in this situation.

+5
source share
1 answer

A simpler solution is to restore your exception in your central formatting method (see also this answer ). Then you can catch each type of exception and format it.

 class Exception : public std::exception {}; class DerivedException : public Exception {}; void LogThrownException(); void DoSomething() { try { // Do something, might throw ... } catch (...) { LogThrownException(); } } void LogThrownException() { try { throw; } // Order is important to catch all derived types. // Luckily the compiler should warn, if a type is hidden. catch (DerivedException&) { std::cout << "DerivedException"; } catch (Exception&) { std::cout << "Exception"; } catch (std::exception&) { std::cout << "std::exception"; } // ... catch (...) { std::cout << "Unknown\n"; } } 
+1
source

Source: https://habr.com/ru/post/1203004/


All Articles