LCOV - code coverage report
Current view: top level - ers/src - StreamManager.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 53.6 % 151 81
Test Date: 2026-10-11 15:05:20 Functions: 44.8 % 29 13

            Line data    Source code
       1              : /*
       2              :  * DUNE DAQ modification notice:
       3              :  * This file has been modified from the original ATLAS ers source for the DUNE DAQ project.
       4              :  * Fork baseline commit: 8267df82a4f6fe6bf02c4014923eba19eddc4614 (2020-04-14).
       5              :  * Renamed since fork: yes (from src/StreamManager.cxx to src/StreamManager.cpp).
       6              :  *
       7              :  * Original copyright:
       8              :  * Copyright (C) 2001-2020 CERN for the benefit of the ATLAS collaboration.
       9              :  * Licensed under the Apache License, Version 2.0.
      10              :  */
      11              : 
      12              : /*
      13              :  *  StreamManager.cxx
      14              :  *  ERS
      15              :  *
      16              :  *  Created by Matthias Wiesmann on 21.01.05.
      17              :  *  Modified by Serguei Kolos on 12.09.06.
      18              :  *  Copyright 2005 CERN. All rights reserved.
      19              :  *
      20              :  */
      21              : 
      22              : #include <assert.h>
      23              : #include <iostream>
      24              : 
      25              : #include <ers/Configuration.hpp>
      26              : #include <ers/InputStream.hpp>
      27              : #include <ers/Issue.hpp>
      28              : #include <ers/OutputStream.hpp>
      29              : #include <ers/Severity.hpp>
      30              : #include <ers/StreamFactory.hpp>
      31              : #include <ers/StreamManager.hpp>
      32              : #include <ers/ers.hpp>
      33              : #include <ers/internal/NullStream.hpp>
      34              : #include <ers/internal/PluginManager.hpp>
      35              : #include <ers/internal/SingletonCreator.hpp>
      36              : #include <ers/internal/Util.hpp>
      37              : #include <ers/internal/macro.hpp>
      38              : 
      39           78 : ERS_DECLARE_ISSUE(ers,
      40              :                   BadConfiguration,
      41              :                   "The stream configuration string \"" << config << "\" has syntax errors.",
      42              :                   ((std::string)config))
      43              : 
      44              : namespace {
      45              : /** This variable contains the default keys for building the default streams.
      46              :  * The default is to use the default stream, in verbose mode for errors and fatals.
      47              :  */
      48              : const char SEPARATOR = ',';
      49              : 
      50              : const char* const DefaultOutputStreams[] = {
      51              :   "lstdout",          // Debug
      52              :   "lstdout",          // Log
      53              :   "throttle,lstdout", // Information
      54              :   "throttle,lstderr", // Warning
      55              :   "throttle,lstderr", // Error
      56              :   "lstderr"           // Fatal
      57              : };
      58              : 
      59              : const char*
      60           59 : get_stream_description(ers::severity severity)
      61              : {
      62           59 :   assert(ers::Debug <= severity && severity <= ers::Fatal);
      63              : 
      64           59 :   std::string env_name("DUNEDAQ_ERS_");
      65           59 :   env_name += ers::to_string(severity);
      66           59 :   const char* env = ::getenv(env_name.c_str());
      67          118 :   return env ? env : DefaultOutputStreams[severity];
      68           59 : }
      69              : 
      70              : void
      71           59 : parse_stream_definition(const std::string& text, std::vector<std::string>& result)
      72              : {
      73           59 :   std::string::size_type start_p = 0, end_p = 0;
      74           59 :   short brackets_open = 0;
      75          679 :   while (end_p < text.length()) {
      76          620 :     switch (text[end_p]) {
      77            0 :       case '(':
      78            0 :         ++brackets_open;
      79            0 :         break;
      80            0 :       case ')':
      81            0 :         --brackets_open;
      82            0 :         break;
      83           23 :       case SEPARATOR:
      84           23 :         if (!brackets_open) {
      85           23 :           result.push_back(text.substr(start_p, end_p - start_p));
      86           23 :           start_p = end_p + 1;
      87              :         }
      88              :         break;
      89              :       default:
      90              :         break;
      91              :     }
      92          620 :     end_p++;
      93              :   }
      94           59 :   if (brackets_open) {
      95            0 :     throw ers::BadConfiguration(ERS_HERE, text);
      96              :   }
      97           59 :   if (start_p != end_p) {
      98           59 :     result.push_back(text.substr(start_p, end_p - start_p));
      99              :   }
     100           59 : }
     101              : }
     102              : 
     103              : namespace ers {
     104              : // Performs lazy srteam initialization. Stream instances are created
     105              : // at the first attempt of writing to the stream
     106              : class StreamInitializer : public ers::OutputStream
     107              : {
     108              : public:
     109          258 :   StreamInitializer(StreamManager& manager)
     110          516 :     : m_manager(manager)
     111          258 :     , m_in_progress(false)
     112              :   {
     113          258 :     ;
     114          258 :   }
     115              : 
     116           59 :   void write(const Issue& issue)
     117              :   {
     118           59 :     ers::severity s = issue.severity();
     119           59 :     std::scoped_lock lock(m_mutex);
     120              : 
     121           59 :     if (!m_in_progress) {
     122           59 :       m_in_progress = true;
     123              :     } else {
     124              :       // The issue is coming from the stream constructor
     125              :       // We can't use ERS streams, so print it to std
     126            0 :       if (s < ers::Warning)
     127            0 :         std::cout << issue << std::endl;
     128              :       else
     129            0 :         std::cerr << issue << std::endl;
     130            0 :       return;
     131              :     }
     132              : 
     133           59 :     if (m_manager.m_out_streams[s].get() == this) {
     134           59 :       m_manager.m_out_streams[s] = std::shared_ptr<OutputStream>(m_manager.setup_stream(s));
     135              :     }
     136           59 :     m_manager.report_issue(s, issue);
     137           59 :     m_in_progress = false;
     138           59 :   }
     139              : 
     140              : private:
     141              :   std::recursive_mutex m_mutex;
     142              :   StreamManager& m_manager;
     143              :   bool m_in_progress;
     144              : };
     145              : 
     146              : }
     147              : 
     148              : /** This method returns the singleton instance.
     149              :  * It should be used for every operation on the factory.
     150              :  * \return a reference to the singleton instance
     151              :  */
     152              : ers::StreamManager&
     153         1083 : ers::StreamManager::instance()
     154              : {
     155              :   /**Singleton instance
     156              :    */
     157         1083 :   static ers::StreamManager* instance = ers::SingletonCreator<ers::StreamManager>::create();
     158              : 
     159         1083 :   return *instance;
     160              : } // instance
     161              : 
     162              : /** Private constructor - can not be called by user code, use the \c instance() method instead
     163              :  * \see instance()
     164              :  */
     165           43 : ers::StreamManager::StreamManager()
     166              : {
     167          301 :   for (short ss = ers::Debug; ss <= ers::Fatal; ++ss) {
     168          258 :     m_init_streams[ss] = std::make_shared<StreamInitializer>(*this);
     169          258 :     m_out_streams[ss] = m_init_streams[ss];
     170              :   }
     171           43 : }
     172              : 
     173              : /** Destructor - basic cleanup
     174              :  */
     175            0 : ers::StreamManager::~StreamManager()
     176              : {
     177            0 :   ;
     178            0 : }
     179              : 
     180              : void
     181            0 : ers::StreamManager::add_output_stream(ers::severity severity, ers::OutputStream* new_stream)
     182              : {
     183            0 :   std::shared_ptr<OutputStream> head = m_out_streams[severity];
     184            0 :   if (head && !head->isNull()) {
     185            0 :     OutputStream* parent = head.get();
     186            0 :     for (OutputStream* stream = parent; !stream->isNull(); parent = stream, stream = &parent->chained())
     187              :       ;
     188              : 
     189            0 :     parent->chained(new_stream);
     190              :   } else {
     191            0 :     m_out_streams[severity] = std::shared_ptr<OutputStream>(new_stream);
     192              :   }
     193            0 : }
     194              : 
     195              : void
     196            0 : ers::StreamManager::add_receiver(const std::string& stream, const std::string& filter, ers::IssueReceiver* receiver)
     197              : {
     198            0 :   InputStream* in = ers::StreamFactory::instance().create_in_stream(stream, filter);
     199            0 :   in->set_receiver(receiver);
     200              : 
     201            0 :   std::scoped_lock lock(m_mutex);
     202            0 :   m_in_streams.push_back(std::shared_ptr<InputStream>(in));
     203            0 : }
     204              : 
     205              : void
     206            0 : ers::StreamManager::add_receiver(const std::string& stream,
     207              :                                  const std::initializer_list<std::string>& params,
     208              :                                  ers::IssueReceiver* receiver)
     209              : {
     210            0 :   InputStream* in = ers::StreamFactory::instance().create_in_stream(stream, params);
     211            0 :   in->set_receiver(receiver);
     212              : 
     213            0 :   std::scoped_lock lock(m_mutex);
     214            0 :   m_in_streams.push_back(std::shared_ptr<InputStream>(in));
     215            0 : }
     216              : 
     217              : void
     218            0 : ers::StreamManager::remove_receiver(ers::IssueReceiver* receiver)
     219              : {
     220            0 :   std::scoped_lock lock(m_mutex);
     221            0 :   for (std::list<std::shared_ptr<InputStream>>::iterator it = m_in_streams.begin(); it != m_in_streams.end();) {
     222            0 :     if ((*it)->m_receiver == receiver)
     223            0 :       m_in_streams.erase(it++);
     224              :     else
     225            0 :       ++it;
     226              :   }
     227            0 : }
     228              : 
     229              : ers::OutputStream*
     230           59 : ers::StreamManager::setup_stream(ers::severity severity)
     231              : {
     232           59 :   std::string config = get_stream_description(severity);
     233           59 :   std::vector<std::string> streams;
     234           59 :   try {
     235           59 :     parse_stream_definition(config, streams);
     236            0 :   } catch (ers::BadConfiguration& ex) {
     237            0 :     ERS_INTERNAL_ERROR("Configuration for the \"" << severity
     238              :                                                   << "\" stream is invalid. "
     239            0 :                                                      "Default configuration will be used.");
     240            0 :   }
     241              : 
     242           59 :   ers::OutputStream* main = setup_stream(streams);
     243              : 
     244           59 :   if (!main) {
     245            0 :     std::vector<std::string> default_streams;
     246            0 :     try {
     247            0 :       parse_stream_definition(DefaultOutputStreams[severity], default_streams);
     248            0 :       main = setup_stream(default_streams);
     249            0 :     } catch (ers::BadConfiguration& ex) {
     250            0 :       ERS_INTERNAL_ERROR("Can not configure the \"" << severity << "\" stream because of the following issue {" << ex
     251            0 :                                                     << "}");
     252            0 :     }
     253            0 :   }
     254           59 :   return (main ? main : new ers::NullStream());
     255           59 : }
     256              : 
     257              : ers::OutputStream*
     258           59 : ers::StreamManager::setup_stream(const std::vector<std::string>& streams)
     259              : {
     260           59 :   size_t cnt = 0;
     261           59 :   ers::OutputStream* main = 0;
     262           59 :   for (; cnt < streams.size(); ++cnt) {
     263           59 :     main = ers::StreamFactory::instance().create_out_stream(streams[cnt]);
     264           59 :     if (main)
     265              :       break;
     266              :   }
     267              : 
     268           59 :   if (!main) {
     269              :     return 0;
     270              :   }
     271              : 
     272           59 :   ers::OutputStream* head = main;
     273           82 :   for (++cnt; cnt < streams.size(); ++cnt) {
     274           23 :     ers::OutputStream* chained = ers::StreamFactory::instance().create_out_stream(streams[cnt]);
     275              : 
     276           23 :     if (chained) {
     277           23 :       head->chained(chained);
     278           23 :       head = chained;
     279              :     }
     280              :   }
     281              : 
     282              :   return main;
     283              : }
     284              : 
     285              : /** Sends an Issue to an appropriate stream
     286              :  * \param type
     287              :  * \param issue
     288              :  */
     289              : void
     290         1141 : ers::StreamManager::report_issue(ers::severity type, const Issue& issue)
     291              : {
     292         1141 :   ers::severity old_severity = issue.set_severity(type);
     293         1141 :   m_out_streams[type]->write(issue);
     294         1141 :   issue.set_severity(old_severity);
     295         1141 : } // error
     296              : 
     297              : /** Sends an Issue to the error stream
     298              :  * \param issue
     299              :  */
     300              : void
     301            0 : ers::StreamManager::error(const Issue& issue)
     302              : {
     303            0 :   report_issue(ers::Error, issue);
     304            0 : } // error
     305              : 
     306              : /** Sends an issue to the debug stream
     307              :  * \param issue the Issue to send
     308              :  * \param level the debug level.
     309              :  */
     310              : void
     311            1 : ers::StreamManager::debug(const Issue& issue, int level)
     312              : {
     313            1 :   if (Configuration::instance().debug_level() >= level) {
     314            0 :     ers::severity old_severity = issue.set_severity(ers::Severity(ers::Debug, level));
     315            0 :     m_out_streams[ers::Debug]->write(issue);
     316            0 :     issue.set_severity(old_severity);
     317              :   }
     318            1 : }
     319              : 
     320              : /** Sends an Issue to the fatal error stream
     321              :  * \param issue
     322              :  */
     323              : void
     324            0 : ers::StreamManager::fatal(const Issue& issue)
     325              : {
     326            0 :   report_issue(ers::Fatal, issue);
     327            0 : }
     328              : 
     329              : /** Sends an Issue to the warning stream
     330              :  * \param issue the issue to send
     331              :  */
     332              : void
     333            0 : ers::StreamManager::warning(const Issue& issue)
     334              : {
     335            0 :   report_issue(ers::Warning, issue);
     336            0 : }
     337              : 
     338              : /** Sends an issue to the info stream
     339              :  * \param issue the Issue to send
     340              :  */
     341              : void
     342           19 : ers::StreamManager::information(const Issue& issue)
     343              : {
     344           19 :   report_issue(ers::Information, issue);
     345           19 : }
     346              : 
     347              : /** Sends an issue to the log stream
     348              :  * \param issue the Issue to send
     349              :  */
     350              : void
     351         1022 : ers::StreamManager::log(const Issue& issue)
     352              : {
     353         1022 :   report_issue(ers::Log, issue);
     354         1022 : }
     355              : 
     356              : std::ostream&
     357            0 : ers::operator<<(std::ostream& out, const ers::StreamManager&)
     358              : {
     359            0 :   for (short ss = ers::Debug; ss <= ers::Fatal; ++ss) {
     360            0 :     out << (ers::severity)ss << "\t\"" << get_stream_description((ers::severity)ss) << "\"" << std::endl;
     361              :   }
     362            0 :   return out;
     363              : }
        

Generated by: LCOV version 2.0-1