Skip to content

Commit d025e9d

Browse files
authored
QC-334 Rework the catching and rethrowing of exceptions (#397)
* QC-334 Rework the catching and rethrowing of exceptions * Better handle excpetions in CheckRunner * format * Rollback a few changes that are not needed because we know DPL driver can catch the boost exceptions now and print them. * format
1 parent 157c85f commit d025e9d

3 files changed

Lines changed: 101 additions & 104 deletions

File tree

Framework/src/CheckRunner.cxx

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ using namespace o2::monitoring;
4747
using namespace o2::quality_control::core;
4848
using namespace o2::quality_control::repository;
4949
namespace bfs = boost::filesystem;
50+
const auto current_diagnostic = boost::current_exception_diagnostic_information;
5051

5152
namespace o2::quality_control::checker
5253
{
@@ -70,7 +71,7 @@ o2::framework::Inputs CheckRunner::createInputSpec(const std::string checkName,
7071
(void)key;
7172
if (sourceConf.get<std::string>("type") == "Task") {
7273
const std::string& taskName = sourceConf.get<std::string>("name");
73-
QcInfoLogger::GetInstance() << ">>>> Check name : " << checkName << " input task name: " << taskName << " " << TaskRunner::createTaskDataDescription(taskName).as<std::string>() << AliceO2::InfoLogger::InfoLogger::endm;
74+
ILOG(Info) << ">>>> Check name : " << checkName << " input task name: " << taskName << " " << TaskRunner::createTaskDataDescription(taskName).as<std::string>() << ENDM;
7475
o2::framework::InputSpec input{ taskName, TaskRunner::createTaskDataOrigin(), TaskRunner::createTaskDataDescription(taskName) };
7576
inputs.push_back(std::move(input));
7677
}
@@ -198,10 +199,17 @@ CheckRunner::~CheckRunner()
198199

199200
void CheckRunner::init(framework::InitContext&)
200201
{
201-
initDatabase();
202-
initMonitoring();
203-
for (auto& check : mChecks) {
204-
check.init();
202+
try {
203+
initDatabase();
204+
initMonitoring();
205+
for (auto& check : mChecks) {
206+
check.init();
207+
}
208+
} catch (...) {
209+
// catch the exceptions and print it (the ultimate caller might not know how to display it)
210+
ILOG(Fatal) << "Unexpected exception during initialization:\n"
211+
<< current_diagnostic(true) << ENDM;
212+
throw;
205213
}
206214
}
207215

@@ -221,7 +229,7 @@ void CheckRunner::run(framework::ProcessingContext& ctx)
221229
mLogger << "Device " << mDeviceName
222230
<< " received " << moArray->GetEntries()
223231
<< " MonitorObjects from " << input.binding
224-
<< AliceO2::InfoLogger::InfoLogger::endm;
232+
<< ENDM;
225233

226234
// Check if this CheckRunner stores this input
227235
bool store = mInputStoreSet.count(DataSpecUtils::label(input)) > 0;
@@ -239,7 +247,7 @@ void CheckRunner::run(framework::ProcessingContext& ctx)
239247
}
240248

241249
} else {
242-
mLogger << "The mo is null" << AliceO2::InfoLogger::InfoLogger::endm;
250+
mLogger << "The mo is null" << ENDM;
243251
}
244252
}
245253
}
@@ -270,7 +278,7 @@ void CheckRunner::update(std::shared_ptr<MonitorObject> mo)
270278
std::vector<Check*> CheckRunner::check(std::map<std::string, std::shared_ptr<MonitorObject>> moMap)
271279
{
272280
mLogger << "Running " << mChecks.size() << " checks for " << moMap.size() << " monitor objects"
273-
<< AliceO2::InfoLogger::InfoLogger::endm;
281+
<< ENDM;
274282

275283
std::vector<Check*> triggeredChecks;
276284
for (auto& check : mChecks) {
@@ -284,36 +292,36 @@ std::vector<Check*> CheckRunner::check(std::map<std::string, std::shared_ptr<Mon
284292
// Was checked, update latest revision
285293
check.updateRevision(mGlobalRevision);
286294
} else {
287-
mLogger << "Monitor Objects for the check '" << check.getName() << "' are not ready, ignoring" << AliceO2::InfoLogger::InfoLogger::endm;
295+
mLogger << "Monitor Objects for the check '" << check.getName() << "' are not ready, ignoring" << ENDM;
288296
}
289297
}
290298
return triggeredChecks;
291299
}
292300

293301
void CheckRunner::store(std::vector<Check*>& checks)
294302
{
295-
mLogger << "Storing " << checks.size() << " quality objects" << AliceO2::InfoLogger::InfoLogger::endm;
303+
mLogger << "Storing " << checks.size() << " quality objects" << ENDM;
296304
try {
297305
for (auto check : checks) {
298306
mDatabase->storeQO(check->getQualityObject());
299307
}
300308
} catch (boost::exception& e) {
301-
mLogger << "Unable to " << diagnostic_information(e) << AliceO2::InfoLogger::InfoLogger::endm;
309+
mLogger << "Unable to " << diagnostic_information(e) << ENDM;
302310
}
303311

304-
mLogger << "Storing " << mMonitorObjectStoreVector.size() << " monitor objects" << AliceO2::InfoLogger::InfoLogger::endm;
312+
mLogger << "Storing " << mMonitorObjectStoreVector.size() << " monitor objects" << ENDM;
305313
try {
306314
for (auto mo : mMonitorObjectStoreVector) {
307315
mDatabase->storeMO(mo);
308316
}
309317
} catch (boost::exception& e) {
310-
mLogger << "Unable to " << diagnostic_information(e) << AliceO2::InfoLogger::InfoLogger::endm;
318+
mLogger << "Unable to " << diagnostic_information(e) << ENDM;
311319
}
312320
}
313321

314322
void CheckRunner::send(std::vector<Check*>& checks, framework::DataAllocator& allocator)
315323
{
316-
mLogger << "Send " << checks.size() << " quality objects" << AliceO2::InfoLogger::InfoLogger::endm;
324+
mLogger << "Send " << checks.size() << " quality objects" << ENDM;
317325
for (auto check : checks) {
318326
auto outputSpec = check->getOutputSpec();
319327
auto concreteOutput = framework::DataSpecUtils::asConcreteDataMatcher(outputSpec);
@@ -337,38 +345,17 @@ void CheckRunner::updateRevision()
337345

338346
void CheckRunner::initDatabase()
339347
{
340-
// configuration
341-
try {
342-
std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(mConfigurationSource);
343-
// configuration of the database
344-
mDatabase = DatabaseFactory::create(config->get<std::string>("qc.config.database.implementation"));
345-
mDatabase->connect(config->getRecursiveMap("qc.config.database"));
346-
LOG(INFO) << "Database that is going to be used : ";
347-
LOG(INFO) << ">> Implementation : " << config->get<std::string>("qc.config.database.implementation");
348-
LOG(INFO) << ">> Host : " << config->get<std::string>("qc.config.database.host");
349-
} catch (
350-
std::string const& e) { // we have to catch here to print the exception because the device will make it disappear
351-
LOG(ERROR) << "exception : " << e;
352-
throw;
353-
} catch (...) {
354-
std::string diagnostic = boost::current_exception_diagnostic_information();
355-
LOG(ERROR) << "Unexpected exception, diagnostic information follows:\n"
356-
<< diagnostic;
357-
throw;
358-
}
348+
std::unique_ptr<ConfigurationInterface> config = ConfigurationFactory::getConfiguration(mConfigurationSource);
349+
mDatabase = DatabaseFactory::create(config->get<std::string>("qc.config.database.implementation"));
350+
mDatabase->connect(config->getRecursiveMap("qc.config.database"));
351+
LOG(INFO) << "Database that is going to be used : ";
352+
LOG(INFO) << ">> Implementation : " << config->get<std::string>("qc.config.database.implementation");
353+
LOG(INFO) << ">> Host : " << config->get<std::string>("qc.config.database.host");
359354
}
360355

361356
void CheckRunner::initMonitoring()
362357
{
363-
// monitoring
364-
try {
365-
mCollector = MonitoringFactory::Get("infologger://");
366-
} catch (...) {
367-
std::string diagnostic = boost::current_exception_diagnostic_information();
368-
LOG(ERROR) << "Unexpected exception, diagnostic information follows:\n"
369-
<< diagnostic;
370-
throw;
371-
}
358+
mCollector = MonitoringFactory::Get("infologger://");
372359
startFirstObject = system_clock::time_point::min();
373360
timer.reset(1000000); // 10 s.
374361
}

Framework/src/TaskRunner.cxx

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
using namespace std;
3939

40+
const auto current_diagnostic = boost::current_exception_diagnostic_information;
41+
4042
namespace o2::quality_control::core
4143
{
4244

@@ -52,13 +54,20 @@ TaskRunner::TaskRunner(const std::string& taskName, const std::string& configura
5254
mMonitorObjectsSpec({ "mo" }, createTaskDataOrigin(), createTaskDataDescription(taskName), id)
5355
{
5456
// setup configuration
55-
mConfigFile = ConfigurationFactory::getConfiguration(configurationSource);
56-
populateConfig(taskName);
57+
try {
58+
mConfigFile = ConfigurationFactory::getConfiguration(configurationSource);
59+
populateConfig(taskName);
60+
} catch (...) {
61+
// catch the configuration exception and print it to avoid losing it
62+
ILOG(Fatal) << "Unexpected exception during configuration:\n"
63+
<< current_diagnostic(true);
64+
throw;
65+
}
5766
}
5867

5968
void TaskRunner::init(InitContext& iCtx)
6069
{
61-
QcInfoLogger::GetInstance() << "initializing TaskRunner" << AliceO2::InfoLogger::InfoLogger::endm;
70+
ILOG(Info) << "initializing TaskRunner" << ENDM;
6271

6372
// registering state machine callbacks
6473
iCtx.services().get<CallbackService>().set(CallbackService::Id::Start, [this]() { start(); });
@@ -242,61 +251,55 @@ std::tuple<bool /*data ready*/, bool /*timer ready*/> TaskRunner::validateInputs
242251

243252
void TaskRunner::populateConfig(std::string taskName)
244253
{
254+
auto tasksConfigList = mConfigFile->getRecursive("qc.tasks");
255+
auto taskConfigTree = tasksConfigList.find(taskName);
256+
if (taskConfigTree == tasksConfigList.not_found()) {
257+
std::string message = "No configuration found for task \"" + taskName + "\"";
258+
BOOST_THROW_EXCEPTION(AliceO2::Common::FatalException() << AliceO2::Common::errinfo_details(message));
259+
}
260+
261+
mTaskConfig.taskName = taskName;
262+
string test = taskConfigTree->second.get<std::string>("detectorName", "MISC");
263+
mTaskConfig.detectorName = validateDetectorName(taskConfigTree->second.get<std::string>("detectorName", "MISC"));
264+
mTaskConfig.moduleName = taskConfigTree->second.get<std::string>("moduleName");
265+
mTaskConfig.className = taskConfigTree->second.get<std::string>("className");
266+
mTaskConfig.cycleDurationSeconds = taskConfigTree->second.get<int>("cycleDurationSeconds", 10);
267+
mTaskConfig.maxNumberCycles = taskConfigTree->second.get<int>("maxNumberCycles", -1);
268+
mTaskConfig.consulUrl = mConfigFile->get<std::string>("qc.config.consul.url", "http://consul-test.cern.ch:8500");
269+
mTaskConfig.conditionUrl = mConfigFile->get<std::string>("qc.config.conditionDB.url", "http://ccdb-test.cern.ch:8080");
245270
try {
246-
auto tasksConfigList = mConfigFile->getRecursive("qc.tasks");
247-
auto taskConfigTree = tasksConfigList.find(taskName);
248-
if (taskConfigTree == tasksConfigList.not_found()) {
249-
throw;
250-
}
271+
mTaskConfig.customParameters = mConfigFile->getRecursiveMap("qc.tasks." + taskName + ".taskParameters");
272+
} catch (...) {
273+
ILOG(Info) << "No custom parameters for " << taskName << ENDM;
274+
}
251275

252-
mTaskConfig.taskName = taskName;
253-
string test = taskConfigTree->second.get<std::string>("detectorName", "MISC");
254-
mTaskConfig.detectorName = validateDetectorName(taskConfigTree->second.get<std::string>("detectorName", "MISC"));
255-
mTaskConfig.moduleName = taskConfigTree->second.get<std::string>("moduleName");
256-
mTaskConfig.className = taskConfigTree->second.get<std::string>("className");
257-
mTaskConfig.cycleDurationSeconds = taskConfigTree->second.get<int>("cycleDurationSeconds", 10);
258-
mTaskConfig.maxNumberCycles = taskConfigTree->second.get<int>("maxNumberCycles", -1);
259-
mTaskConfig.consulUrl = mConfigFile->get<std::string>("qc.config.consul.url", "http://consul-test.cern.ch:8500");
260-
mTaskConfig.conditionUrl = mConfigFile->get<std::string>("qc.config.conditionDB.url", "http://ccdb-test.cern.ch:8080");
261-
try {
262-
mTaskConfig.customParameters = mConfigFile->getRecursiveMap("qc.tasks." + taskName + ".taskParameters");
263-
} catch (...) {
264-
LOG(INFO) << "No custom parameters for " << taskName;
265-
}
276+
auto policiesFilePath = mConfigFile->get<std::string>("dataSamplingPolicyFile", "");
277+
ConfigurationInterface* config = policiesFilePath.empty() ? mConfigFile.get() : ConfigurationFactory::getConfiguration(policiesFilePath).get();
278+
auto policiesTree = config->getRecursive("dataSamplingPolicies");
279+
auto dataSourceTree = taskConfigTree->second.get_child("dataSource");
280+
std::string type = dataSourceTree.get<std::string>("type");
281+
282+
if (type == "dataSamplingPolicy") {
283+
auto policyName = dataSourceTree.get<std::string>("name");
284+
ILOG(Info) << "policyName : " << policyName << ENDM;
285+
mInputSpecs = DataSampling::InputSpecsForPolicy(config, policyName);
286+
} else if (type == "direct") {
287+
auto inputsQuery = dataSourceTree.get<std::string>("query");
288+
mInputSpecs = DataDescriptorQueryBuilder::parse(inputsQuery.c_str());
289+
} else {
290+
std::string message = std::string("Configuration error : dataSource type unknown : ") + type;
291+
BOOST_THROW_EXCEPTION(AliceO2::Common::FatalException() << AliceO2::Common::errinfo_details(message));
292+
}
266293

267-
auto policiesFilePath = mConfigFile->get<std::string>("dataSamplingPolicyFile", "");
268-
ConfigurationInterface* config = policiesFilePath.empty() ? mConfigFile.get() : ConfigurationFactory::getConfiguration(policiesFilePath).get();
269-
auto policiesTree = config->getRecursive("dataSamplingPolicies");
270-
auto dataSourceTree = taskConfigTree->second.get_child("dataSource");
271-
std::string type = dataSourceTree.get<std::string>("type");
272-
273-
if (type == "dataSamplingPolicy") {
274-
auto policyName = dataSourceTree.get<std::string>("name");
275-
LOG(INFO) << "policyName : " << policyName;
276-
mInputSpecs = DataSampling::InputSpecsForPolicy(config, policyName);
277-
} else if (type == "direct") {
278-
auto inputsQuery = dataSourceTree.get<std::string>("query");
279-
mInputSpecs = DataDescriptorQueryBuilder::parse(inputsQuery.c_str());
280-
} else {
281-
std::string message = std::string("Configuration error : dataSource type unknown : ") + type; // TODO pass this message to the exception
282-
BOOST_THROW_EXCEPTION(AliceO2::Common::FatalException() << AliceO2::Common::errinfo_details(message));
283-
}
294+
mInputSpecs.emplace_back(InputSpec{ "timer-cycle", createTaskDataOrigin(), createTaskDataDescription("TIMER-" + taskName), 0, Lifetime::Timer });
295+
mOptions.push_back({ "period-timer-cycle", framework::VariantType::Int, static_cast<int>(mTaskConfig.cycleDurationSeconds * 1000000), { "timer period" } });
284296

285-
mInputSpecs.emplace_back(InputSpec{ "timer-cycle", createTaskDataOrigin(), createTaskDataDescription("TIMER-" + taskName), 0, Lifetime::Timer });
286-
mOptions.push_back({ "period-timer-cycle", framework::VariantType::Int, static_cast<int>(mTaskConfig.cycleDurationSeconds * 1000000), { "timer period" } });
287-
} catch (...) { // catch already here the configuration exception and print it
288-
// because if we are in a constructor, the exception could be lost
289-
std::string diagnostic = boost::current_exception_diagnostic_information();
290-
LOG(ERROR) << "Unexpected exception, diagnostic information follows:\n"
291-
<< diagnostic;
292-
throw;
293-
}
294-
LOG(INFO) << "Configuration loaded : ";
295-
LOG(INFO) << ">> Task name : " << mTaskConfig.taskName;
296-
LOG(INFO) << ">> Module name : " << mTaskConfig.moduleName;
297-
LOG(INFO) << ">> Detector name : " << mTaskConfig.detectorName;
298-
LOG(INFO) << ">> Cycle duration seconds : " << mTaskConfig.cycleDurationSeconds;
299-
LOG(INFO) << ">> Max number cycles : " << mTaskConfig.maxNumberCycles;
297+
ILOG(Info) << "Configuration loaded : " << ENDM;
298+
ILOG(Info) << ">> Task name : " << mTaskConfig.taskName << ENDM;
299+
ILOG(Info) << ">> Module name : " << mTaskConfig.moduleName << ENDM;
300+
ILOG(Info) << ">> Detector name : " << mTaskConfig.detectorName << ENDM;
301+
ILOG(Info) << ">> Cycle duration seconds : " << mTaskConfig.cycleDurationSeconds << ENDM;
302+
ILOG(Info) << ">> Max number cycles : " << mTaskConfig.maxNumberCycles << ENDM;
300303
}
301304

302305
std::string TaskRunner::validateDetectorName(std::string name)
@@ -316,9 +319,9 @@ std::string TaskRunner::validateDetectorName(std::string name)
316319
std::string permittedString;
317320
for (auto i : permitted)
318321
permittedString += i + ' ';
319-
LOG(ERROR) << "Invalid detector name : " << name << "\n"
320-
<< " Placeholder 'MISC' will be used instead\n"
321-
<< " Note: list of permitted detector names :" << permittedString;
322+
ILOG(Error) << "Invalid detector name : " << name << "\n"
323+
<< " Placeholder 'MISC' will be used instead\n"
324+
<< " Note: list of permitted detector names :" << permittedString << ENDM;
322325
return "MISC";
323326
}
324327
return name;
@@ -349,7 +352,7 @@ void TaskRunner::endOfActivity()
349352

350353
void TaskRunner::startCycle()
351354
{
352-
QcInfoLogger::GetInstance() << "cycle " << mCycleNumber << " in " << mTaskConfig.taskName << AliceO2::InfoLogger::InfoLogger::endm;
355+
QcInfoLogger::GetInstance() << "cycle " << mCycleNumber << " in " << mTaskConfig.taskName << ENDM;
353356
mTask->startOfCycle();
354357
mNumberMessages = 0;
355358
mNumberObjectsPublishedInCycle = 0;
@@ -371,8 +374,8 @@ void TaskRunner::finishCycle(DataAllocator& outputs)
371374
mCycleOn = false;
372375

373376
if (mTaskConfig.maxNumberCycles == mCycleNumber) {
374-
LOG(INFO) << "The maximum number of cycles (" << mTaskConfig.maxNumberCycles << ") has been reached."
375-
<< " The task will not do anything from now on.";
377+
ILOG(Info) << "The maximum number of cycles (" << mTaskConfig.maxNumberCycles << ") has been reached."
378+
<< " The task will not do anything from now on." << ENDM;
376379
}
377380
}
378381

@@ -400,7 +403,7 @@ void TaskRunner::publishCycleStats()
400403

401404
int TaskRunner::publish(DataAllocator& outputs)
402405
{
403-
QcInfoLogger::GetInstance() << "Send data from " << mTaskConfig.taskName << " len: " << mObjectsManager->getNumberPublishedObjects() << AliceO2::InfoLogger::InfoLogger::endm;
406+
ILOG(Info) << "Send data from " << mTaskConfig.taskName << " len: " << mObjectsManager->getNumberPublishedObjects() << ENDM;
404407
AliceO2::Common::Timer publicationDurationTimer;
405408

406409
auto concreteOutput = framework::DataSpecUtils::asConcreteDataMatcher(mMonitorObjectsSpec);

Modules/Skeleton/src/SkeletonTask.cxx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ void SkeletonTask::initialize(o2::framework::InitContext& /*ctx*/)
4040

4141
mHistogram = new TH1F("example", "example", 20, 0, 30000);
4242
getObjectsManager()->startPublishing(mHistogram);
43-
getObjectsManager()->addMetadata(mHistogram->GetName(), "custom", "34");
43+
try {
44+
getObjectsManager()->addMetadata(mHistogram->GetName(), "custom", "34");
45+
} catch (...) {
46+
// some methods can throw exceptions, it is indicated in their doxygen.
47+
// In case it is recoverable, it is recommended to catch them and do something meaningful.
48+
// Here we don't care that the metadata was not added and just log the event.
49+
ILOG(Warning) << "Metadata could not be added to " << mHistogram->GetName() << ENDM;
50+
}
4451
}
4552

4653
void SkeletonTask::startOfActivity(Activity& /*activity*/)

0 commit comments

Comments
 (0)