The Gaudi Framework  v38r1p1 (ae26267b)
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/BaseSink.h"
13 #include "Gaudi/MonitoringHub.h"
14 #include "GaudiKernel/MsgStream.h"
15 
16 #include <boost/algorithm/string.hpp>
17 
18 #include <fmt/core.h>
19 #include <fmt/format.h>
20 
21 #include <map>
22 #include <sstream>
23 #include <string_view>
24 
25 #if FMT_VERSION < 80000
26 namespace fmt {
27  template <typename T>
28  const T& runtime( const T& v ) {
29  return v;
30  }
31 } // namespace fmt
32 #endif
33 
34 namespace {
35 
48  { "counter", "{0:nEntries|10d}" }, // all unknown counters, and default
49  { "histogram", "{0:nEntries|10d}" }, // all histograms
50  { "counter:AveragingCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g}" },
51  { "counter:SigmaCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g}" },
52  { "counter:StatCounter", "{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g} "
53  "|{0:min|#12.5g} |{0:max|#12.5g}" },
54  { "counter:BinomialCounter",
55  "{0:nEntries|10d} |{0:nTrueEntries|11d} |({0:efficiency|#9.7p} +- {0:efficiencyErr|-#8.7p})%" },
56  };
57 
58  // Helper to fix custom formatting of nlohmann::json version 3.10.5
59  // See https://gitlab.cern.ch/gaudi/Gaudi/-/issues/220
60  struct json_fmt_arg {
61  json_fmt_arg( const nlohmann::json& j ) : payload{ j } {}
62  const nlohmann::json& payload;
63  };
64 } // namespace
65 
75 template <>
76 class fmt::formatter<json_fmt_arg> {
77 public:
78  template <typename ParseContext>
79  constexpr auto parse( ParseContext& ctx ) {
80  auto fmt_begin = ctx.begin();
81  auto fmt_end = std::find( fmt_begin, ctx.end(), '}' );
82  if ( fmt_begin == fmt_end ) {
83  // we are dealing with {}, only make sure currentFormat is empty
84  currentFormat = "";
85  } else {
86  // non empty format, let's split name from format
87  auto fmt_colon = std::find( fmt_begin, fmt_end, '|' );
88  currentName = std::string( fmt_begin, fmt_colon - fmt_begin );
89  currentFormat = std::string( fmt_colon + 1, fmt_end - fmt_colon - 1 );
90  }
91  return fmt_end;
92  }
93  template <typename FormatContext>
94  auto format( const json_fmt_arg& json_arg, FormatContext& ctx ) {
95  const auto& j = json_arg.payload;
96  if ( currentFormat.size() == 0 ) {
97  // dealing with {} format, let's find entry for our type in registry
98  const auto type = j.at( "type" ).get<std::string>();
99  // first looking for the entry, then we drop on ":abc" suffix at a time and try again
100  std::string_view type_key{ type };
101  // look for the full entry
102  auto entry = registry.find( type_key );
103  // we check if we have type separators before entering the loop
104  auto sep = type_key.rfind( ':' );
105  while ( sep != type_key.npos && entry == registry.end() ) {
106  // not found, remove the trailing ":abc" section
107  type_key.remove_suffix( type_key.size() - sep );
108  // check if we have another chunk to strip
109  sep = type_key.rfind( ':' );
110  // see if the shorter key works
111  entry = registry.find( type_key );
112  }
113  // if still not found, we use the basic "counter"
114  if ( entry == registry.end() ) entry = registry.find( "counter" );
115  assert( entry != registry.end() );
116  // print the json string according to format found
117  // This actually will call this formatter again a number of times
118  return fmt::format_to( ctx.out(), fmt::runtime( entry->second ), json_arg );
119  } else {
120  // dealing with a {:name|fmt} format
121  auto actualFormat = "{:" + currentFormat + '}';
122  switch ( currentFormat.back() ) {
123  case 'd':
124  return fmt::format_to( ctx.out(), fmt::runtime( actualFormat ),
125  j.at( currentName ).template get<unsigned int>() );
126  case 'g':
127  return fmt::format_to( ctx.out(), fmt::runtime( actualFormat ), j.at( currentName ).template get<double>() );
128  case 'p':
129  actualFormat[actualFormat.size() - 2] = 'g';
130  return fmt::format_to( ctx.out(), fmt::runtime( actualFormat ),
131  j.at( currentName ).template get<double>() * 100 );
132  default:
133  return fmt::format_to( ctx.out(), "Unknown counter format : {}", currentFormat );
134  }
135  }
136  }
137 
138 private:
141 };
142 
143 namespace {
144 
145  void printCounter( std::ostringstream& log, std::string_view id, const nlohmann::json& j ) {
146  const auto type = j.at( "type" ).get<std::string>();
147  // for backward compatibility, we need to deal with statentity in a special way
148  // this block should be dropped when StatEntities are gone
149  if ( type == "statentity" ) {
150  using boost::algorithm::icontains;
151  bool isBinomial = icontains( id, "eff" ) || icontains( id, "acc" ) || icontains( id, "filt" ) ||
152  icontains( id, "fltr" ) || icontains( id, "pass" );
153  auto nj = j;
154  nj["type"] = isBinomial ? "counter:BinomialCounter" : "counter:StatCounter";
155  return printCounter( log, id, nj );
156  }
157  // binomial counters are slightly different ('*' character)
158  // fmt::runtime is required when compiling with GCC 11 but
159  // can be dropped when GCC 11 is no longer supported
160  log << fmt::format( fmt::runtime( " |{}{:48}|{} |" ),
161  ( std::string_view{ type }.substr( 0, 23 ) == "counter:BinomialCounter" ? '*' : ' ' ),
162  fmt::format( fmt::runtime( "\"{}\"" ), id ), json_fmt_arg{ j } );
163  }
164 
165 } // namespace
166 
167 namespace Gaudi::Monitoring {
168 
178  // only deal with counters, statentity and histograms
179  setProperty( "TypesToSave", std::vector<std::string>{ "counter:.*", "statentity", "histogram:" } )
180  .orThrow( "Unable to set typesToSaveProperty", "Histograming::Sink::Base" );
181  }
183  void flush( bool ) override;
184  };
185 
186  DECLARE_COMPONENT( MessageSvcSink )
187 } // namespace Gaudi::Monitoring
188 
190  std::string curAlgo = "";
191  std::ostringstream curLog;
192  unsigned int nbNonEmptyEntities = 0;
193  auto dumpAlgoCounters = [&]() {
194  // Yes, so print header, dump log and reset counters
195  if ( nbNonEmptyEntities > 0 ) {
196  MsgStream log{ msgSvc(), curAlgo };
197  log << MSG::INFO << "Number of counters : " << nbNonEmptyEntities << "\n"
198  << " | Counter | # | "
199  << " sum | mean/eff^* | rms/err^* | min | max |";
200  log << curLog.str() << endmsg;
201  }
202  };
203  applyToAllSortedEntities( [&]( std::string const& algo, std::string const& entity, nlohmann::json const& j ) {
204  // Did we change to new component ?
205  if ( algo != curAlgo ) {
206  dumpAlgoCounters();
207  curAlgo = algo;
208  nbNonEmptyEntities = 0;
209  curLog = std::ostringstream{};
210  }
211  // is current counter empty ?
212  if ( !j.at( "empty" ).template get<bool>() ) {
213  ++nbNonEmptyEntities;
214  curLog << "\n";
215  printCounter( curLog, entity, j );
216  }
217  } );
218  // last component
219  dumpAlgoCounters();
220 }
Gaudi::Monitoring::BaseSink
Base class for all Sinks registering to the Monitoring Hub Should be extended by actual Sinks.
Definition: BaseSink.h:40
std::string
STL class.
Gaudi.Configuration.log
log
Definition: Configuration.py:29
MSG::INFO
@ INFO
Definition: IMessageSvc.h:25
MonitoringHub.h
fmt::formatter< json_fmt_arg >::currentFormat
std::string currentFormat
Definition: MessageSvcSink.cpp:139
std::vector< std::string >
std::find
T find(T... args)
PropertyHolder< CommonMessaging< implements< IService, IProperty, IStateful > > >::setProperty
StatusCode setProperty(const Gaudi::Details::PropertyBase &p)
Set the property from a property.
Definition: IProperty.h:39
ISvcLocator
Definition: ISvcLocator.h:46
fmt::runtime
const T & runtime(const T &v)
Definition: MessageSvcSink.cpp:28
jsonFromLHCbLog.json
json
Definition: jsonFromLHCbLog.py:86
Gaudi::Monitoring::MessageSvcSink::flush
void flush(bool) override
stop method, handles the printing
Definition: MessageSvcSink.cpp:189
Gaudi::Monitoring
Definition: JSONSink.cpp:19
AvalancheSchedulerErrorTest.msgSvc
msgSvc
Definition: AvalancheSchedulerErrorTest.py:80
GaudiPluginService.cpluginsvc.registry
def registry()
Definition: cpluginsvc.py:83
Gaudi::Monitoring::MessageSvcSink
Sink dedicated to printing messages to the MessageSvc.
Definition: MessageSvcSink.cpp:176
GaudiPython.Pythonizations.ctx
ctx
Definition: Pythonizations.py:578
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:332
ProduceConsume.j
j
Definition: ProduceConsume.py:101
fmt::formatter< json_fmt_arg >::currentName
std::string currentName
Definition: MessageSvcSink.cpp:140
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
Gaudi::Monitoring::BaseSink::applyToAllSortedEntities
void applyToAllSortedEntities(Callable func) const
applies a callable to all monitoring entities ordered by component the callable will be called once p...
Definition: BaseSink.h:110
std::map
STL class.
MsgStream
Definition: MsgStream.h:34
Gaudi::Monitoring::MessageSvcSink::MessageSvcSink
MessageSvcSink(std::string name, ISvcLocator *svcloc)
Definition: MessageSvcSink.cpp:177
std::ostringstream
STL class.
gaudirun.type
type
Definition: gaudirun.py:160
fmt::formatter< json_fmt_arg >::parse
constexpr auto parse(ParseContext &ctx)
Definition: MessageSvcSink.cpp:79
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:46
fmt
Definition: MessageSvcSink.cpp:26
BaseSink.h
Properties.v
v
Definition: Properties.py:122
std::ostringstream::str
T str(T... args)
MsgStream.h
fmt::formatter< json_fmt_arg >::format
auto format(const json_fmt_arg &json_arg, FormatContext &ctx)
Definition: MessageSvcSink.cpp:94