DCCL v4
logger.h
1 // Copyright 2012-2023:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 // Chris Murphy <cmurphy@aphysci.com>
8 //
9 //
10 // This file is part of the Dynamic Compact Control Language Library
11 // ("DCCL").
12 //
13 // DCCL is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU Lesser General Public License as published by
15 // the Free Software Foundation, either version 2.1 of the License, or
16 // (at your option) any later version.
17 //
18 // DCCL is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public License
24 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
25 #ifndef DCCLLOGGER20121009H
26 #define DCCLLOGGER20121009H
27 
28 #include <cstdio>
29 #include <deque>
30 #include <functional>
31 #include <iomanip>
32 #include <iostream>
33 #include <sstream>
34 #include <stack>
35 #include <string>
36 #include <vector>
37 
38 #include "thread_safety.h"
39 
40 namespace dccl
41 {
42 namespace logger
43 {
45 enum Verbosity
46 {
47  WARN = 1 << 1,
48  INFO = 1 << 2,
49  DEBUG1 = 1 << 3,
50  DEBUG2 = 1 << 4,
51  DEBUG3 = 1 << 5,
52  ALL = DEBUG3 | (DEBUG3 - 1),
53  WARN_PLUS = WARN | (WARN - 1),
54  INFO_PLUS = INFO | (INFO - 1),
55  DEBUG1_PLUS = DEBUG1 | (DEBUG1 - 1),
56  DEBUG2_PLUS = DEBUG2 | (DEBUG2 - 1),
57  DEBUG3_PLUS = DEBUG3 | (DEBUG3 - 1),
58  UNKNOWN = 0
59 };
60 enum Group
61 {
62  GENERAL,
63  ENCODE,
64  DECODE,
65  SIZE
66 };
67 
68 } // namespace logger
69 
70 void to_ostream(const std::string& msg, dccl::logger::Verbosity vrb, dccl::logger::Group grp,
71  std::ostream* os, bool add_timestamp);
72 
73 class Logger;
74 
75 namespace internal
76 {
77 class LogBuffer : public std::streambuf
78 {
79  public:
80  LogBuffer() : buffer_(1) {}
81  ~LogBuffer() override = default;
82 
84  template <typename Slot> void connect(int verbosity_mask, Slot slot)
85  {
86  enabled_verbosities_ |= verbosity_mask;
87  if (verbosity_mask & logger::WARN)
88  warn_signal.emplace_back(slot);
89  if (verbosity_mask & logger::INFO)
90  info_signal.emplace_back(slot);
91  if (verbosity_mask & logger::DEBUG1)
92  debug1_signal.emplace_back(slot);
93  if (verbosity_mask & logger::DEBUG2)
94  debug2_signal.emplace_back(slot);
95  if (verbosity_mask & logger::DEBUG3)
96  debug3_signal.emplace_back(slot);
97  }
98 
99  void disconnect(int verbosity_mask)
100  {
101  enabled_verbosities_ &= ~verbosity_mask;
102  if (verbosity_mask & logger::WARN)
103  warn_signal.clear();
104  if (verbosity_mask & logger::INFO)
105  info_signal.clear();
106  if (verbosity_mask & logger::DEBUG1)
107  debug1_signal.clear();
108  if (verbosity_mask & logger::DEBUG2)
109  debug2_signal.clear();
110  if (verbosity_mask & logger::DEBUG3)
111  debug3_signal.clear();
112  }
113 
115  void set_verbosity(logger::Verbosity verbosity) { verbosity_.push(verbosity); }
116 
117  void set_group(logger::Group group) { group_.push(group); }
118 
119  bool contains(logger::Verbosity verbosity) const { return verbosity & enabled_verbosities_; }
120 
121  private:
124  int sync() override;
125 
128  int overflow(int c = EOF) override;
129 
130  void display(const std::string& s)
131  {
132  if (verbosity() & logger::WARN)
133  {
134  for (auto& slot : warn_signal) slot(s, logger::WARN, group());
135  }
136  if (verbosity() & logger::INFO)
137  {
138  for (auto& slot : info_signal) slot(s, logger::INFO, group());
139  }
140  if (verbosity() & logger::DEBUG1)
141  {
142  for (auto& slot : debug1_signal) slot(s, logger::DEBUG1, group());
143  }
144  if (verbosity() & logger::DEBUG2)
145  {
146  for (auto& slot : debug2_signal) slot(s, logger::DEBUG2, group());
147  }
148  if (verbosity() & logger::DEBUG3)
149  {
150  for (auto& slot : debug3_signal) slot(s, logger::DEBUG3, group());
151  }
152  }
153 
154  logger::Verbosity verbosity()
155  {
156  return verbosity_.empty() ? logger::UNKNOWN : verbosity_.top();
157  }
158  logger::Group group() { return group_.empty() ? logger::GENERAL : group_.top(); }
159 
160  private:
161  std::stack<logger::Verbosity> verbosity_;
162  std::stack<logger::Group> group_;
163  std::deque<std::string> buffer_;
164  int enabled_verbosities_; // mask of verbosity settings enabled
165 
166  using LogSignal = std::vector<
167  std::function<void(const std::string& msg, logger::Verbosity vrb, logger::Group grp)>>;
168 
169  LogSignal warn_signal, info_signal, debug1_signal, debug2_signal, debug3_signal;
170 };
171 } // namespace internal
172 
174 class Logger : public std::ostream
175 {
176  public:
177  Logger() : std::ostream(&buf_) {}
178  ~Logger() override = default;
179 
181  bool check(logger::Verbosity verbosity) { return buf_.contains(verbosity); }
182 
192  bool is(logger::Verbosity verbosity, logger::Group group = logger::GENERAL)
193  {
194  if (!buf_.contains(verbosity))
195  {
196  return false;
197  }
198  else
199  {
200 #if DCCL_THREAD_SUPPORT
201  g_dlog_mutex.lock();
202 #endif
203  buf_.set_verbosity(verbosity);
204  buf_.set_group(group);
205  return true;
206  }
207  }
208 
214  template <typename Slot> void connect(int verbosity_mask, Slot slot)
215  {
216  DCCL_LOCK_DLOG_MUTEX
217  buf_.connect(verbosity_mask, slot);
218  }
219 
226  template <typename Obj>
227  void connect(int verbosity_mask, Obj* obj,
228  void (Obj::*mem_func)(const std::string& msg, logger::Verbosity vrb,
229  logger::Group grp))
230  {
231  DCCL_LOCK_DLOG_MUTEX
232  connect(verbosity_mask, std::bind(mem_func, obj, std::placeholders::_1,
233  std::placeholders::_2, std::placeholders::_3));
234  }
235 
241  void connect(int verbosity_mask, std::ostream* os, bool add_timestamp = true)
242  {
243  DCCL_LOCK_DLOG_MUTEX
244  buf_.connect(verbosity_mask,
245  std::bind(to_ostream, std::placeholders::_1, std::placeholders::_2,
246  std::placeholders::_3, os, add_timestamp));
247  }
248 
250  void disconnect(int verbosity_mask)
251  {
252  DCCL_LOCK_DLOG_MUTEX
253  buf_.disconnect(verbosity_mask);
254  }
255 
256  private:
257  internal::LogBuffer buf_;
258 };
259 
260 extern Logger dlog;
261 
262 inline std::string hash_as_string(std::size_t hash)
263 {
264  std::stringstream hash_stream;
265  hash_stream << "0x" << std::setfill('0') << std::setw(sizeof(std::size_t) * 2) << std::hex
266  << hash;
267  return hash_stream.str();
268 }
269 
270 } // namespace dccl
271 
272 #endif // DCCLLOGGER20121009H
dccl::Logger::connect
void connect(int verbosity_mask, std::ostream *os, bool add_timestamp=true)
Connect the output of one or more given verbosities to a std::ostream.
Definition: logger.h:241
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:46
dccl::Logger::is
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition: logger.h:192
dccl::internal::LogBuffer::set_verbosity
void set_verbosity(logger::Verbosity verbosity)
sets the verbosity level until the next sync()
Definition: logger.h:115
dccl::Logger
The DCCL Logger class. Do not instantiate this class directly. Rather, use the dccl::dlog object.
Definition: logger.h:174
dccl::internal::LogBuffer
Definition: logger.h:77
dccl::internal::LogBuffer::connect
void connect(int verbosity_mask, Slot slot)
connect a signal to a slot (function pointer or similar)
Definition: logger.h:84
dccl::Logger::connect
void connect(int verbosity_mask, Slot slot)
Connect the output of one or more given verbosities to a slot (function pointer or similar)
Definition: logger.h:214
dccl::Logger::connect
void connect(int verbosity_mask, Obj *obj, void(Obj::*mem_func)(const std::string &msg, logger::Verbosity vrb, logger::Group grp))
Connect the output of one or more given verbosities to a member function.
Definition: logger.h:227
dccl::Logger::check
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
Definition: logger.h:181
dccl::Logger::disconnect
void disconnect(int verbosity_mask)
Disconnect all slots for one or more given verbosities.
Definition: logger.h:250