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

Generated by: LCOV version 2.0-1