The Gaudi Framework  v36r1 (3e2fb5a8)
MessageSvcSink.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 
12 #include "Gaudi/MonitoringHub.h"
13 #include "GaudiKernel/MsgStream.h"
14 #include "GaudiKernel/Service.h"
15 
16 #include <boost/algorithm/string.hpp>
17 
18 #include <fmt/core.h>
19 #include <fmt/format.h>
20 
21 #include <deque>
22 #include <map>
23 #include <string_view>
24 
25 namespace {
26 
39  {"counter", "{0:nEntries|10d}"}, // all unknown counters, and default
40  {"histogram", "{0:nEntries|10d}"}, // all histograms
41  {"counter:AveragingCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g}"},
42  {"counter:SigmaCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g}"},
43  {"counter:StatCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g} "
44  "|{0:min|#12.5g} |{0:max|#12.5g}"},
45  {"counter:BinomialCounter",
46  "{0:nEntries|10d} |{0:nTrueEntries|11d} |({0:efficiency|#9.7p} +- {0:efficiencyErr|-#8.7p})%"},
47  };
48 } // namespace
49 
59 template <>
60 class fmt::formatter<nlohmann::json> {
61 public:
62  template <typename ParseContext>
63  constexpr auto parse( ParseContext& ctx ) {
64  auto fmt_begin = ctx.begin();
65  auto fmt_end = std::find( fmt_begin, ctx.end(), '}' );
66  if ( fmt_begin == fmt_end ) {
67  // we are dealing with {}, only make sure currentFormat is empty
68  currentFormat = "";
69  } else {
70  // non empty format, let's split name from format
71  auto fmt_colon = std::find( fmt_begin, fmt_end, '|' );
72  currentName = std::string( fmt_begin, fmt_colon - fmt_begin );
73  currentFormat = std::string( fmt_colon + 1, fmt_end - fmt_colon - 1 );
74  }
75  return fmt_end;
76  }
77  template <typename FormatContext>
78  auto format( const nlohmann::json& j, FormatContext& ctx ) {
79  if ( currentFormat.size() == 0 ) {
80  // dealing with {} format, let's find entry for our type in registry
81  const auto type = j.at( "type" ).get<std::string>();
82  // first looking for the entry, then we drop on ":abc" suffix at a time and try again
83  std::string_view type_key{type};
84  // look for the full entry
85  auto entry = registry.find( type_key );
86  // we check if we have type separators before entering the loop
87  auto sep = type_key.rfind( ':' );
88  while ( sep != type_key.npos && entry == registry.end() ) {
89  // not found, remove the trailing ":abc" section
90  type_key.remove_suffix( type_key.size() - sep );
91  // check if we have another chunk to strip
92  sep = type_key.rfind( ':' );
93  // see if the shorter key works
94  entry = registry.find( type_key );
95  }
96  // if still not found, we use the basic "counter"
97  if ( entry == registry.end() ) entry = registry.find( "counter" );
98  assert( entry != registry.end() );
99  // print the json string according to format found
100  // This actually will call this formatter again a number of times
101  return fmt::format_to( ctx.out(), entry->second, j );
102  } else {
103  // dealing with a {:name|fmt} format
104  auto actualFormat = fmt::format( "{{:{}", currentFormat ) + "}";
105  switch ( currentFormat.back() ) {
106  case 'd':
107  return fmt::format_to( ctx.out(), actualFormat, j.at( currentName ).template get<unsigned int>() );
108  case 'g':
109  return fmt::format_to( ctx.out(), actualFormat, j.at( currentName ).template get<double>() );
110  case 'p':
111  actualFormat[actualFormat.size() - 2] = 'g';
112  return fmt::format_to( ctx.out(), actualFormat, j.at( currentName ).template get<double>() * 100 );
113  default:
114  return fmt::format_to( ctx.out(), "Unknown counter format : {}", currentFormat );
115  }
116  }
117  }
118 
119 private:
122 };
123 
124 namespace {
125 
126  template <typename stream>
127  stream printCounter( stream& log, const std::string& id, const nlohmann::json& j ) {
128  const auto type = j.at( "type" ).get<std::string>();
129  // for backward compatibility, we need to deal with statentity in a special way
130  // this block should be dropped when StatEntities are gone
131  if ( type == "statentity" ) {
132  using boost::algorithm::icontains;
133  bool isBinomial = icontains( id, "eff" ) || icontains( id, "acc" ) || icontains( id, "filt" ) ||
134  icontains( id, "fltr" ) || icontains( id, "pass" );
135  auto nj = j;
136  nj["type"] = isBinomial ? "counter:BinomialCounter" : "counter:StatCounter";
137  return printCounter( log, id, nj );
138  }
139  // binomial counters are slightly different ('*' character)
140  return log << fmt::format( " |{}{:48}|{} |",
141  ( std::string_view{type}.substr( 0, 23 ) == "counter:BinomialCounter" ? '*' : ' ' ),
142  fmt::format( "\"{}\"", id ), j );
143  }
144 
145 } // namespace
146 
147 namespace Gaudi::Monitoring {
148 
149  class MessageSvcSink : public Service, public Hub::Sink {
150 
151  public:
152  using Service::Service;
153 
155  StatusCode initialize() override {
156  return Service::initialize().andThen( [&] {
157  // declare ourself as a monitoding sink
158  serviceLocator()->monitoringHub().addSink( this );
159  } );
160  }
161 
163  StatusCode stop() override;
164 
165  // Gaudi::Monitoring::Hub::Sink implementation
166  void registerEntity( Hub::Entity ent ) override {
167  if ( std::string_view( ent.type ).substr( 0, 8 ) == "counter:" || ent.type == "statentity" ||
168  ent.type == "histogram" ) {
169  m_monitoringEntities.emplace_back( std::move( ent ) );
170  }
171  }
172 
173  // Gaudi::Monitoring::Hub::Sink implementation
174  void removeEntity( Hub::Entity const& ent ) override {
176  if ( it != m_monitoringEntities.end() ) { m_monitoringEntities.erase( it ); }
177  }
178 
179  private:
181  };
182 
184 } // namespace Gaudi::Monitoring
185 
187  // We will try to mimic the old monitoring of counters, so we need to split
188  // them per Algo. The algo name can be extracted form the id of the entity
189  // as its format is "algoName/counterName"
190  // This map groups entities per algoName. For each name, the submap gives
191  // the counter name of each subentity and the associated json
193  // fill the sorted map
194  for ( auto& entity : m_monitoringEntities ) { sortedEntities[entity.component][entity.name] = entity.toJSON(); }
195  // dump all counters
196  for ( auto& [algoName, entityMap] : sortedEntities ) {
197  // check first whether there is any counter to log
198  unsigned int nbCounters =
199  std::accumulate( begin( entityMap ), end( entityMap ), 0, []( const unsigned int& a, const auto& j ) {
200  return a + ( j.second.at( "empty" ).template get<bool>() ? 0 : 1 );
201  } );
202  if ( 0 == nbCounters ) continue;
203  MsgStream log{msgSvc(), algoName};
204  log << MSG::INFO << "Number of counters : " << nbCounters << "\n"
205  << " | Counter | # | "
206  << " sum | mean/eff^* | rms/err^* | min | max |";
207  std::for_each( begin( entityMap ), end( entityMap ), [&log]( auto& p ) {
208  // Do not print empty counters
209  if ( !p.second.at( "empty" ).template get<bool>() ) {
210  log << "\n";
211  printCounter( log, p.first, p.second );
212  }
213  } );
214  log << endmsg;
215  }
216  return Service::stop();
217 }
Gaudi::Monitoring::MessageSvcSink::initialize
StatusCode initialize() override
initialization, registers to Monitoring::Hub
Definition: MessageSvcSink.cpp:155
Gaudi::Monitoring::Hub::Sink
Interface reporting services must implement.
Definition: MonitoringHub.h:78
std::for_each
T for_each(T... args)
Write.stream
stream
Definition: Write.py:31
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
std::string
STL class.
Gaudi::Monitoring::MessageSvcSink
Definition: MessageSvcSink.cpp:149
Gaudi.Configuration.log
log
Definition: Configuration.py:24
Gaudi::Monitoring::MessageSvcSink::stop
StatusCode stop() override
stop method, handles the printing
Definition: MessageSvcSink.cpp:186
StatusCode::andThen
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition: StatusCode.h:180
std::move
T move(T... args)
MSG::INFO
@ INFO
Definition: IMessageSvc.h:25
MonitoringHub.h
std::find
T find(T... args)
nlohmann
Definition: Accumulators.h:224
Gaudi::Monitoring
Definition: MessageSvcSink.cpp:147
jsonFromLHCbLog.json
dictionary json
Definition: jsonFromLHCbLog.py:86
fmt::formatter< nlohmann::json >::currentFormat
std::string currentFormat
Definition: MessageSvcSink.cpp:120
Service
Definition: Service.h:46
GaudiPluginService.cpluginsvc.registry
def registry()
Definition: cpluginsvc.py:82
fmt::formatter< nlohmann::json >::parse
constexpr auto parse(ParseContext &ctx)
Definition: MessageSvcSink.cpp:63
GaudiPython.Pythonizations.ctx
ctx
Definition: Pythonizations.py:566
StatusCode
Definition: StatusCode.h:65
CLHEP::begin
double * begin(CLHEP::HepVector &v)
Definition: TupleAlg.cpp:45
fmt::formatter< nlohmann::json >::format
auto format(const nlohmann::json &j, FormatContext &ctx)
Definition: MessageSvcSink.cpp:78
Gaudi::Monitoring::MessageSvcSink::removeEntity
void removeEntity(Hub::Entity const &ent) override
Definition: MessageSvcSink.cpp:174
std::accumulate
T accumulate(T... args)
std::deque
STL class.
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:203
std::map
STL class.
Gaudi::Monitoring::MessageSvcSink::registerEntity
void registerEntity(Hub::Entity ent) override
Definition: MessageSvcSink.cpp:166
MsgStream
Definition: MsgStream.h:34
fmt::formatter< nlohmann::json >::currentName
std::string currentName
Definition: MessageSvcSink.cpp:121
Gaudi::Monitoring::MessageSvcSink::m_monitoringEntities
std::deque< Hub::Entity > m_monitoringEntities
Definition: MessageSvcSink.cpp:180
Service.h
gaudirun.type
type
Definition: gaudirun.py:154
Service::stop
StatusCode stop() override
Definition: Service.cpp:181
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
Service::Service
Service(std::string name, ISvcLocator *svcloc)
Standard Constructor
Definition: Service.cpp:339
AsyncIncidents.msgSvc
msgSvc
Definition: AsyncIncidents.py:23
IOTest.end
end
Definition: IOTest.py:123
Gaudi::Monitoring::Hub::Entity
Wrapper class for arbitrary monitoring objects.
Definition: MonitoringHub.h:40
MsgStream.h
Service::serviceLocator
SmartIF< ISvcLocator > & serviceLocator() const override
Retrieve pointer to service locator
Definition: Service.cpp:335
Gaudi::Monitoring::Hub::Entity::type
std::string type
type of the entity, see comment above concerning its format and usage
Definition: MonitoringHub.h:55