source: rrlib_logging/tLogDomain.h @ 38:f5f67eec129d

Last change on this file since 38:f5f67eec129d was 38:f5f67eec129d, checked in by Tobias Föhst <foehst@…>, 10 years ago

Adapted to new include path

File size: 14.4 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) AG Robotersysteme TU Kaiserslautern
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21//----------------------------------------------------------------------
22/*!\file    tLogDomain.h
23 *
24 * \author  Tobias Foehst
25 * \author  Max Reichardt
26 *
27 * \date    2010-06-16
28 *
29 * \brief Contains tLogDomain
30 *
31 * \b tLogDomain
32 *
33 * The RRLib logging system is structured into hierarchical domains that
34 * can be created and configured via tLogDomainRegistry. That given,
35 * in the program implementation instances of the class tLogDomain
36 * wrap the stream that can be access either in C++ iostream style via
37 * operator << or in good old-fashioned C style using printf formatting.
38 *
39 */
40//----------------------------------------------------------------------
41#ifndef _rrlib_logging_include_guard_
42#error Invalid include directive. Try #include "rrlib/logging/definitions.h" instead.
43#endif
44
45#ifndef _rrlib_logging_tLogDomain_h_
46#define _rrlib_logging_tLogDomain_h_
47
48//----------------------------------------------------------------------
49// External includes (system with <>, local with "")
50//----------------------------------------------------------------------
51#include <string>
52#include <vector>
53#include <fstream>
54#include <iomanip>
55#include <ctime>
56#include <cstdarg>
57#include <cassert>
58#include <tr1/memory>
59
60//----------------------------------------------------------------------
61// Internal includes with ""
62//----------------------------------------------------------------------
63#include "rrlib/logging/tLogDomainConfiguration.h"
64#include "rrlib/logging/tLogStreamBuffer.h"
65#include "rrlib/logging/tLogStream.h"
66#include "rrlib/logging/tLogStreamContext.h"
67
68//----------------------------------------------------------------------
69// Debugging
70//----------------------------------------------------------------------
71
72//----------------------------------------------------------------------
73// Namespace declaration
74//----------------------------------------------------------------------
75namespace rrlib
76{
77namespace logging
78{
79
80//----------------------------------------------------------------------
81// Forward declarations / typedefs / enums
82//----------------------------------------------------------------------
83//! Shared pointer to instances of tLogDomain for user space
84class tLogDomain;
85typedef std::tr1::shared_ptr<const tLogDomain> tLogDomainSharedPointer;
86
87//----------------------------------------------------------------------
88// Class declaration
89//----------------------------------------------------------------------
90//! This class implements messaging via a specific logging domain
91/*! The RRLib logging system is structured into hierarchical domains that
92 *  can be created and configured via tLogDomainRegistry. That given,
93 *  in the program implementation instances of this class wrap the stream
94 *  that can be access either in C++ iostream style via operator << or
95 *  in the good old-fashioned C style using printf formatting.
96 *
97 */
98class tLogDomain
99{
100  friend class tLogDomainRegistry;
101
102  tLogDomain *parent;
103  std::vector<tLogDomain *> children;
104
105  tLogDomainConfigurationSharedPointer configuration;
106
107  mutable tLogStreamBuffer stream_buffer;
108  mutable std::ofstream file_stream;
109
110  std::tr1::shared_ptr<boost::recursive_mutex> mutex;
111
112  /*! The ctor of a top level domain
113   *
114   * This ctor is to be called by the registry that creates the top level
115   * domain.
116   *
117   * \param configuration   The configuration for the new domain
118   */
119  tLogDomain(tLogDomainConfigurationSharedPointer configuration);
120
121  /*! The ctor for a new sub domain
122   *
123   * This ctor is to be called by the registry to create a new subdomain
124   * with a given configuration
125   *
126   * \param configuration   The configuration for the new domain
127   * \param parent          The parent domain
128   */
129  tLogDomain(tLogDomainConfigurationSharedPointer configuration, tLogDomain &parent);
130
131  /*!
132   * \returns Shared Pointer to output mutex that is shared by all logging domains
133   */
134  static std::tr1::shared_ptr<boost::recursive_mutex> GetMutex()
135  {
136    static std::tr1::shared_ptr<boost::recursive_mutex> mutex(new boost::recursive_mutex());
137    return mutex;
138  }
139
140  /*! Recursively configure the subtree that begins in this domain
141   *
142   * If the domain is configured by its parent, the configuration is
143   * copied and propagated to this domain's children
144   */
145  void ConfigureSubTree();
146
147  /*! Open the file stream for file output
148   *
149   * This method creates a new file which name is build using a prefix
150   * and the full qualified domain name.
151   * If the file already exists, it will be truncated.
152   *
153   * \returns Whether the file stream could be opened or not
154   */
155  const bool OpenFileOutputStream() const;
156
157  /*! Setup the output stream to be used in this domain
158   *
159   * A domain can stream its input to stdout, stderr, an own file and/or its parent's file.
160   *
161   *\param mask   The bitmask that selects the output streams to use
162   */
163  void SetupOutputStream(int mask) const;
164
165  /*! Get the current time as string for internal use in messages
166   *
167   * This method formats the current time as string that can be used in
168   * messages.
169   *
170   * \returns The current time as string
171   */
172  const std::string GetTimeString() const;
173
174  /*! Get the domain's name as string for internal use in messages
175   *
176   * This method formats the name as string that can be used in
177   * messages. This string is padded with spaces to the length of the
178   * longest domain name
179   *
180   * \returns The padded name as string
181   */
182  const std::string GetNameString() const;
183
184  /*! Get the given message level as string for internal use in messages
185   *
186   * This method formats the given level as string that can be used in
187   * messages.
188   *
189   * \param level   The level that should be represented as string
190   *
191   * \returns The given level as padded string
192   */
193  const std::string GetLevelString(tLogLevel level) const;
194
195  /*! Get the given location as string for internal use in messages
196   *
197   * This method formats given location consisting of a file name and a
198   * line number as string that can be used in messages.
199   *
200   * \param file   The file name (e.g. from __FILE__)
201   * \param line   The line number (e.g. from __LINE__)
202   *
203   * \returns The given location as string
204   */
205  const std::string GetLocationString(const char *file, unsigned int line) const;
206
207  /*! Setup the underlying streambuffer to produce colored output
208   *
209   * This method sets up the underlying streambuffer for colored
210   * output according to the given level.
211   *
212   * \param level   The according log level
213   */
214  void SetupOutputStreamColor(tLogLevel level) const;
215
216//----------------------------------------------------------------------
217// Public methods
218//----------------------------------------------------------------------
219public:
220
221  /*! The dtor of tLogDomain
222   */
223  ~tLogDomain();
224
225  /*! Get the full qualified name of this domain
226   *
227   * Each domain has a full qualified name consisting of its parent's name
228   * and the local part that was given at creation time.
229   *
230   * \returns The full qualified domain name
231   */
232  inline const std::string GetName() const
233  {
234    return this->configuration->name;
235  }
236
237  /*! Get configuration status of this domain's print_time flag
238   *
239   * The current time is prepended to messages of this domain if the
240   * print_time flag is set.
241   *
242   * \returns Whether the print_time flag is set or not.
243   */
244  inline const bool GetPrintTime() const
245  {
246    return this->configuration->print_time;
247  }
248
249  /*! Get configuration status of this domain's print_name flag
250   *
251   * The name of this domain prepended to messages of this domain if its
252   * print_name flag is set.
253   *
254   * \returns Whether the print_name flag is set or not.
255   */
256  inline const bool GetPrintName() const
257  {
258    return this->configuration->print_name;
259  }
260
261  /*! Get configuration status of this domain's print_level flag
262   *
263   * The level of each message is contained in the output of this domain
264   * if the print_level flag is set.
265   *
266   * \returns Whether the print_level flag is set or not.
267   */
268  inline const bool GetPrintLevel() const
269  {
270    return this->configuration->print_level;
271  }
272
273  /*! Get configuration status of this domain's print_location flag
274   *
275   * The location given to each message is contained in the output of this
276   * domain if the print_location flag is set.
277   *
278   * \returns Whether the print_location flag is set or not.
279   */
280  inline const bool GetPrintLocation() const
281  {
282    return this->configuration->print_location;
283  }
284
285  /*! Get the maximal log level a message must have to be processed
286   *
287   * Each message has a log level that must not be above the configured limit to be processed.
288   *
289   * \returns The configured maximal log level
290   */
291  inline const tLogLevel GetMaxMessageLevel() const
292  {
293    return this->configuration->max_message_level;
294  }
295
296  /*! Get a message stream from this domain
297   *
298   * This method is the streaming interface to this logging domain.
299   * It must be used for every output using operator <<.
300   * The method then depending on the domain's configuration chooses
301   * a stream, prints the prefix that should be prepended to every
302   * message and returns the stream to process further input given as
303   * operator << cascade in the user's program.
304   * To properly specify the arguments of this method consider using
305   * the macros defined in rrlib/logging/definitions.h
306   *
307   * \param description   A string that describes the global context of the message
308   * \param function      The name of the function that contains the message (__FUNCTION__)
309   * \param file          The file that contains the message
310   * \param line          The line that contains the message
311   * \param level         The log level of the message
312   *
313   * \returns A reference to the stream that can be used for the remaining message parts
314   */
315  template <typename TDescription>
316  inline tLogStream GetMessageStream(const TDescription &description, const char *function, const char *file, unsigned int line, tLogLevel level) const
317  {
318    tLogStream stream_proxy(std::tr1::shared_ptr<tLogStreamContext>(new tLogStreamContext(this->stream_buffer, mutex.get())));
319    this->stream_buffer.Clear();
320    this->stream_buffer.InitializeMultiLinePadding();
321    if (level > this->GetMaxMessageLevel())
322    {
323      return stream_proxy;
324    }
325    this->SetupOutputStream(this->configuration->sink_mask);
326
327    if (level == eLL_USER)
328    {
329      return stream_proxy;
330    }
331
332    if (this->GetPrintTime())
333    {
334      stream_proxy << this->GetTimeString();
335    }
336    this->SetupOutputStreamColor(level);
337
338#ifndef _RRLIB_LOGGING_LESS_OUTPUT_
339    if (this->GetPrintName())
340    {
341      stream_proxy << this->GetNameString();
342    }
343    if (this->GetPrintLevel())
344    {
345      stream_proxy << this->GetLevelString(level);
346    }
347#endif
348    stream_proxy << description << "::" << function << " ";
349#ifndef _RRLIB_LOGGING_LESS_OUTPUT_
350    if (this->GetPrintLocation())
351    {
352      stream_proxy << this->GetLocationString(file, line);
353    }
354#endif
355    stream_proxy << ">> ";
356    this->stream_buffer.ResetColor();
357
358    switch (level)
359    {
360    case eLL_ERROR:
361      stream_proxy << "ERROR: ";
362      break;
363    case eLL_WARNING:
364    case eLL_DEBUG_WARNING:
365      stream_proxy << "WARNING: ";
366      break;
367    default:
368      ;
369    }
370
371    this->stream_buffer.MarkEndOfPrefixForMultiLinePadding();
372
373    return stream_proxy;
374  }
375
376  /*! A printf like variant of using logging domains for message output
377   *
378   * Instead of using operator << to output messages this method can be
379   * used. It then itself uses printf to format the given message and
380   * streams the result through the result obtained from GetMessageStream.
381   * That way the message prefix is only generated in one place and - more
382   * important - the underlying technique is the more sane one from
383   * iostreams instead of file descriptors.
384   * Apart from that: iostreams and file descriptors can not be mixed. So
385   * a decision had to be made.
386   *
387   * \param description   A string that describes the global context of the message
388   * \param function      The name of the function that contains the message (__FUNCTION__)
389   * \param file          The file that contains the message
390   * \param line          The line that contains the message
391   * \param level         The log level of the message
392   * \param fmt           The format string for printf
393   * \param ...           The remaining arguments for printf
394   */
395  template <typename TDescription>
396  inline void PrintMessage(const TDescription &description, const char *function, const char *file, int line, tLogLevel level, const char *fmt, ...) const
397  {
398    if (level > this->GetMaxMessageLevel())
399    {
400      return;
401    }
402    char formatted_string_buffer[1024];
403
404    va_list printf_args;
405    va_start(printf_args, fmt);
406    vsnprintf(formatted_string_buffer, sizeof(formatted_string_buffer), fmt, printf_args);
407    va_end(printf_args);
408
409    this->GetMessageStream(description, function, file, line, level) << formatted_string_buffer;
410  }
411
412  template <typename TDescription>
413  inline void PrintMessage(const TDescription &description, const char *function, const char *file, int line, tLogLevel level, tLogDomainSharedPointer(&)(), const char *fmt, ...) const
414  {
415    if (level > this->GetMaxMessageLevel())
416    {
417      return;
418    }
419    char formatted_string_buffer[1024];
420
421    va_list printf_args;
422    va_start(printf_args, fmt);
423    vsnprintf(formatted_string_buffer, sizeof(formatted_string_buffer), fmt, printf_args);
424    va_end(printf_args);
425
426    this->GetMessageStream(description, function, file, line, level) << formatted_string_buffer;
427  }
428
429};
430
431//----------------------------------------------------------------------
432// End of namespace declaration
433//----------------------------------------------------------------------
434}
435}
436
437#endif
Note: See TracBrowser for help on using the repository browser.