From f2f340b918d690a04ba6e6bf341ea73892428630 Mon Sep 17 00:00:00 2001 From: Nathan Brei Date: Fri, 3 May 2024 15:09:55 -0400 Subject: [PATCH] JException displays wrapped exception type Addresses issue #277. --- src/libraries/JANA/JException.h | 8 +++++- src/libraries/JANA/JFactory.cc | 7 +++++ src/libraries/JANA/Omni/JComponent.h | 3 +++ src/libraries/JANA/Utils/JAutoActivator.cc | 1 + src/libraries/JANA/Utils/JTypeInfo.h | 14 ++++++++-- .../Components/JEventProcessorTests.cc | 23 ++++++++++++++++ .../unit_tests/Components/JFactoryTests.cc | 26 +++++++++++++++++++ 7 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/libraries/JANA/JException.h b/src/libraries/JANA/JException.h index 9c013a1c5..bc4e5a9f4 100644 --- a/src/libraries/JANA/JException.h +++ b/src/libraries/JANA/JException.h @@ -46,7 +46,12 @@ struct JException : public std::exception { /// Convenience method for formatting complete error data inline friend std::ostream& operator<<(std::ostream& os, JException const& ex) { os << "JException" << std::endl; - os << " Message: " << ex.message << std::endl; + if (ex.exception_type.length() != 0) { + os << " Type: " << ex.exception_type << std::endl; + } + if (ex.message.length() != 0) { + os << " Message: " << ex.message << std::endl; + } if (ex.function_name.length() != 0) { os << " Function: " << ex.function_name << std::endl; } @@ -65,6 +70,7 @@ struct JException : public std::exception { return os; } + std::string exception_type; std::string message; std::string plugin_name; std::string type_name; diff --git a/src/libraries/JANA/JFactory.cc b/src/libraries/JANA/JFactory.cc index aa99f289a..5c14d8ab4 100644 --- a/src/libraries/JANA/JFactory.cc +++ b/src/libraries/JANA/JFactory.cc @@ -4,6 +4,7 @@ #include #include +#include void JFactory::Create(const std::shared_ptr& event) { @@ -27,6 +28,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException("Exception in JFactoryT::Init(): %s", e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Init"; ex.type_name = mFactoryName; @@ -36,6 +38,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Init"; ex.type_name = mFactoryName; @@ -76,6 +79,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; ex.type_name = mFactoryName; @@ -85,6 +89,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::BeginRun/ChangeRun/EndRun"; ex.type_name = mFactoryName; @@ -105,6 +110,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Process"; ex.type_name = mFactoryName; @@ -114,6 +120,7 @@ void JFactory::Create(const std::shared_ptr& event) { } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = "JFactory::Process"; ex.type_name = mFactoryName; diff --git a/src/libraries/JANA/Omni/JComponent.h b/src/libraries/JANA/Omni/JComponent.h index e88629a53..30891298d 100644 --- a/src/libraries/JANA/Omni/JComponent.h +++ b/src/libraries/JANA/Omni/JComponent.h @@ -6,6 +6,7 @@ #pragma once #include #include +#include namespace jana { namespace omni { @@ -126,6 +127,7 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) } catch (std::exception& e) { auto ex = JException(e.what()); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = func_name; ex.type_name = m_type_name; @@ -135,6 +137,7 @@ inline void JComponent::CallWithJExceptionWrapper(std::string func_name, F func) } catch (...) { auto ex = JException("Unknown exception"); + ex.exception_type = JTypeInfo::demangle_current_exception_type(); ex.nested_exception = std::current_exception(); ex.function_name = func_name; ex.type_name = m_type_name; diff --git a/src/libraries/JANA/Utils/JAutoActivator.cc b/src/libraries/JANA/Utils/JAutoActivator.cc index e986e8f6e..37fdd7e15 100644 --- a/src/libraries/JANA/Utils/JAutoActivator.cc +++ b/src/libraries/JANA/Utils/JAutoActivator.cc @@ -7,6 +7,7 @@ JAutoActivator::JAutoActivator() { SetTypeName("JAutoActivator"); + SetCallbackStyle(CallbackStyle::ExpertMode); } void JAutoActivator::AddAutoActivatedFactory(string factory_name, string factory_tag) { diff --git a/src/libraries/JANA/Utils/JTypeInfo.h b/src/libraries/JANA/Utils/JTypeInfo.h index 39762c401..57a0c12f1 100644 --- a/src/libraries/JANA/Utils/JTypeInfo.h +++ b/src/libraries/JANA/Utils/JTypeInfo.h @@ -27,11 +27,11 @@ struct is_serializable() << s template -std::string demangle(void) { +std::string demangle() { /// Return the demangled name (if available) for the type the template /// is based. Call it like this: - /// cout << GetDemangledName() << endl; + /// cout << demangle() << endl; int status = -1; auto cstr = abi::__cxa_demangle(typeid(T).name(), NULL, NULL, &status); std::string type(cstr); @@ -41,6 +41,16 @@ std::string demangle(void) { } +inline std::string demangle_current_exception_type() { + + int status = -1; + auto cstr = abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), NULL, NULL, &status); + std::string type(cstr); + free(cstr); + if (status != 0) type = abi::__cxa_current_exception_type()->name(); + return type; +} + /// Macro for conveniently turning a variable name into a string. This is used by JObject::Summarize /// in order to play nicely with refactoring tools. Because the symbol is picked up by the /// preprocessor and not the compiler, no demangling is necessary. diff --git a/src/programs/unit_tests/Components/JEventProcessorTests.cc b/src/programs/unit_tests/Components/JEventProcessorTests.cc index cba55e739..71d836602 100644 --- a/src/programs/unit_tests/Components/JEventProcessorTests.cc +++ b/src/programs/unit_tests/Components/JEventProcessorTests.cc @@ -60,3 +60,26 @@ TEST_CASE("JEventProcessor_ExpertMode_ProcessCount") { REQUIRE(destroy_count == 1); } +struct MyExceptingProcessor : public JEventProcessor { + void Process(const std::shared_ptr&) override { + throw std::runtime_error("Mystery!"); + } +}; + +TEST_CASE("JEventProcessor_Exception") { + JApplication app; + app.Add(new JEventSource); + app.Add(new MyExceptingProcessor); + bool found_throw = false; + try { + app.Run(); + } + catch(JException& ex) { + REQUIRE(ex.function_name == "JEventProcessor::Process"); + REQUIRE(ex.message == "Mystery!"); + REQUIRE(ex.exception_type == "std::runtime_error"); + found_throw = true; + } + REQUIRE(found_throw == true); + +} diff --git a/src/programs/unit_tests/Components/JFactoryTests.cc b/src/programs/unit_tests/Components/JFactoryTests.cc index 159ee8ae7..4c165ff04 100644 --- a/src/programs/unit_tests/Components/JFactoryTests.cc +++ b/src/programs/unit_tests/Components/JFactoryTests.cc @@ -221,3 +221,29 @@ TEST_CASE("JFactoryTests") { } } + +struct MyExceptingFactory : public JFactoryT { + void Process(const std::shared_ptr&) override { + throw std::runtime_error("Weird mystery!"); + } +}; + +TEST_CASE("JFactory_Exception") { + JApplication app; + app.Add(new JEventSource); + app.Add(new JFactoryGeneratorT()); + app.SetParameterValue("autoactivate", "JFactoryTestDummyObject"); + bool found_throw = false; + try { + app.Run(); + } + catch(JException& ex) { + LOG << ex << LOG_END; + REQUIRE(ex.function_name == "JFactory::Process"); + REQUIRE(ex.message == "Weird mystery!"); + REQUIRE(ex.exception_type == "std::runtime_error"); + found_throw = true; + } + REQUIRE(found_throw == true); +} +