Open diehard2 opened 10 months ago
The output from diagnostic_information is not designed to be user-friendly. The intended use of the "arbitrary tags" with Boost Exception is that you'd catch and handle every possible exception type, and in each catch block access the additional info to format a user-friendly message (which in general includes localization); then follow with catch(...) that outputs the diagnostic information, which you would treat as a bug (you're missing a necessary catch statement for some exception type that formats a user-friendly message).
That said, you do have some control over the automatic conversion to string, by providing to_string overloads for error_info<Tag, t>. See https://www.boost.org/doc/libs/1_83_0/libs/exception/doc/diagnostic_information.html.
Thanks @zajo, that gets me closer.
I don't believe I'm using boost::exception in an unintended manner. I have a main program/service with libraries that call libraries, and with C++17 on, we have the ability to nest exceptions. I don't necessarily know what's in those library thrown boost exceptions, so my only recourse for printing it out for logs is to use diagnostic_information(). If I could iterate over the set of error_infos, I could handle the ones I need to with a cast to the types I know about and otherwise print out unknown ones with the generic to_string(). I will say that with the exception of getting the information out of it, this is all working amazingly well. And I can live with the diagnostic_output to my logs, but I was hoping for a more flexible option.
If you can think of any way for me to get this information out, I would really appreciate it. If not, I hope you'll consider this for a feature request. Thanks again!
Do I understand correctly that you want the diagnostic info to only include error_infos you don't know about? Otherwise I don't see a point in iterating over them, you don't need iteration in order to handle the error_infos you need.
Do you mind me asking if this is some legacy project? If not, I'd recommend Boost LEAF over Boost Exception.
@diehard2 apparently as @zajo explained this great lib wasn't designed with the idea of further extensibility and customization in mind so I also have had to find my ways to get to its internals and also implement few derived/custom classes (error_info, error_info_container etc.) to achieve what I wanted, including localizable and custom per instance error info descriptions etc.
this code
```
eh::AddErrorInfoDescription
@zlojvavan if you make a pull request with your changes I'll take a look.
@zlojvavan great minds think alike, that's at least partially what I'm doing. with only about 50 lines of code plus boost::exception plus boost stacktrace you can essentially get Java and C# style exceptions.
Do you mind me asking if this is some legacy project? If not, I'd recommend Boost LEAF over Boost Exception.
@zajo my place largely uses exceptions and its unlikely we would switch to a return code paradigm at this late stage. There's just too many millions of lines. I think what would be ideal is if I could remove error_info's. Instead of get_error_info that returns a raw pointer, maybe a unique_ptr? That way I could handle the ones I know about and let diagnostic_information print out the ones I don't. But if I could just iterate over them like diagnostic_information does that would make my life much easier. For people who use exceptions, this library is really great. Thanks for all your hard work.
@diehard2 I endorse using exceptions to handle errors. Boost LEAF works great with exceptions, you can think of it as a better Boost Exception. See https://www.boost.org/doc/libs/1_83_0/libs/leaf/doc/html/index.html#boost_exception.
@diehard2 despite not being designed to such customizations the library is still flexible enough to leave some backdoors allowing to implement required functionality through exploiting of boost::exception public methods and friend structs. in my mini-framework I replace standard boost implementation provided error info container with my own derived class providing needed methods. I believe you could do the same to achieve what you wish. so whenever my code throws new exception or rethrows caught exception thrown somewhere outside my control I install/replace my container into boost::exception instance copying already inserted error info from standard container into my one if any
@zajo I was able to implement all required functionality without modifying/patching existing boost sources (though not in the most comfortable way) so not sure what changes would be acceptable for you. I already tried to ask you to enhance library in the past (as in https://github.com/boostorg/exception/issues/25) to no avail so I've had to find my own ways to achieve what I wanted then the way resembling @apolukhin approach from https://github.com/boostorg/stacktrace/pull/147
@zlojvavan The issue you linked was about customizing throw exception, which I don't want to do. In this case it seems you have some kind of system for customizing the conversion of error_info to string, which could be useful, so I'm offering to take a look at it, since I'm not sure I understand the use case.
it seems you have some kind of system for customizing the conversion of error_info to string
well, yes I have rather primitive formatting capabilities. for example if in code above replace catch block with the following:
catch (...)
{
eh::handle_exception_params_t hep;
auto& dip = hep.diagnostic_info_params;
dip.nameFormat = "\"%s\": ";
dip.valueFormat = ">%s<";
dip.showTypeNames = false;
dip.types = V_EXCLUDE_DIAG_INFO_TYPES(eh::errinfo_file_name/*, eh::throw_chain, eh::throw_callstack, eh::errinfo_init_callstack, eh::errinfo_nested_exception*/);
/*hep.invokeCustomHandlers = true;
hep.getDiagnosticInfo = true;
hep.async = true;
auto& dup = hep.dup;
dup.handle = true;
dup.ignoreDuration = std::chrono::seconds{ 5 };
dup.useWhat = true;*/
HANDLE_EXCEPTION(hep);
}
it will change first part of produced report to
/opt/vcpkg/installed/x64-linux/include/boost/asio/ip/impl/address.ipp(112): Throw in function address boost::asio::ip::make_address(const char *)
Dynamic exception type: vavan::eh::boosted_exception<boost::system::system_error>
std::exception::what: Invalid argument [system:22]
"system" error #22
"some description": >rethrowing here<
"variant": >1352345<
"someVar": >1352345<
"custom var description": >1352345<
"API function name": >net::ip::make_address<
"custom tuple description": >/home/vavan/.vs/test_all/test_all.cpp, 69, test, 5<
"std::make_tuple("/home/vavan/.vs/test_all/test_all.cpp", 70, "test", 5)": >/home/vavan/.vs/test_all/test_all.cpp, 70, test, 5<
"another tuple": >/home/vavan/.vs/test_all/test_all.cpp, 71, test, 5<
"at line #": >72<
I'm offering to take a look at it
well, atm it doesn't exist as a patched/modified boost sources but is part of my "super header" containing lots of stuff I tend to use across different projects, so it may take indefinite time to produce PR containing only subset of available functionality in digestable form
This makes me think that what you really need is conversion to json, and then you can parse it and do whatever you want with it.
@zajo well, for me there's no need to convert anything to json, ATM I'm fine with my exception handling and reporting stuff and been using it for years. there are still some inconveniences with throw sites that do not use boost::throw_exception though but with p2370 and some tricks as in mentioned above from_exception I hope we'll finally get there sooner than later
@zlojvavan LEAF is able to deal with throw sites not using boost::throw_exception.
@zajo do you mean it is able to get callstacks of all throw expressions throughout the entire application and all used rtl and thirdparty libs that do not use LEAF?
anyway as already been explained several times switching libraries in existing codebases isn't always an option
Yes, LEAF is able to do that. Switching from Boost Exception to Boost LEAF is very straightforward, even for a large codebase, I've done it in an afternoon. It doesn't mean that it's always a good idea, but it should be considered.
I'm allowing people to add arbitrary tags, however diagnostic_information() is causing some formatting I don't love. However I don't see any good way to create my own version of that function and get the formatting I would like. The closest I've come to seeing a solution is here
https://stackoverflow.com/questions/48191012/how-to-iterate-over-all-error-infos-in-boostexception
Thanks for any help or workarounds and apologies if this isn't where I should submit something like this