RCFProto
 All Classes Functions Typedefs
Log.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 #ifndef INCLUDE_UTIL_LOG_HPP
20 #define INCLUDE_UTIL_LOG_HPP
21 
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include <boost/config.hpp>
27 #include <boost/current_function.hpp>
28 #include <boost/enable_shared_from_this.hpp>
29 #include <boost/function.hpp>
30 #include <boost/scoped_ptr.hpp>
31 #include <boost/shared_ptr.hpp>
32 
33 #include <RCF/Export.hpp>
34 #include <RCF/MemStream.hpp>
35 #include <RCF/ThreadLibrary.hpp>
36 #include <RCF/Tools.hpp>
37 
38 #include <RCF/util/Tchar.hpp>
39 #include <RCF/util/VariableArgMacro.hpp>
40 
41 #ifdef BOOST_WINDOWS
42 #include <Windows.h>
43 #endif
44 
45 namespace RCF {
46 
47  // Trace std::vector
48  template<typename T>
49  void printToOstream(MemOstream & os, const std::vector<T> &v)
50  {
51  os << "(";
52  for (std::size_t i=0; i<v.size(); ++i)
53  {
54  os << v[i] << ", ";
55  }
56  os << ")";
57  }
58 
59  // Trace std::deque
60  template<typename T>
61  void printToOstream(MemOstream & os, const std::deque<T> &d)
62  {
63  os << "(";
64  for (std::size_t i=0; i<d.size(); ++i)
65  {
66  os << d[i] << ", ";
67  }
68  os << ")";
69  }
70 
71  class Exception;
72  class RemoteException;
73  class SerializationException;
74 
75  RCF_EXPORT void printToOstream(MemOstream & os, const std::type_info & ti);
76  RCF_EXPORT void printToOstream(MemOstream & os, const std::exception & e);
77  RCF_EXPORT void printToOstream(MemOstream & os, const Exception &e);
78  RCF_EXPORT void printToOstream(MemOstream & os, const RemoteException &e);
79  RCF_EXPORT void printToOstream(MemOstream & os, const SerializationException &e);
80 
81  class ByteBuffer;
82 
83  class LogBuffers
84  {
85  public:
86  MemOstream mTlsUserBuffer;
87  MemOstream mTlsLoggerBuffer;
88  MemOstream mTlsVarArgBuffer1;
89  MemOstream mTlsVarArgBuffer2;
90  };
91 
92  //******************************************************************************
93  // LogManager
94 
95  class LogEntry;
96  class Logger;
97 
98  typedef boost::shared_ptr<Logger> LoggerPtr;
99 
100  class RCF_EXPORT LogManager
101  {
102  private:
103  LogManager();
104  ~LogManager();
105 
106  public:
107  static void init();
108  static void deinit();
109  static LogManager & instance();
110 
111  void deactivateAllLoggers();
112  void deactivateAllLoggers(int name);
113 
114  bool isEnabled(int name, int level);
115 
116  typedef std::map< int, std::vector< LoggerPtr > > Loggers;
117  ReadWriteMutex mLoggersMutex;
118  Loggers mLoggers;
119 
120  void writeToLoggers(const LogEntry & logEntry);
121  void activateLogger(LoggerPtr loggerPtr);
122  void deactivateLogger(LoggerPtr loggerPtr);
123  bool isLoggerActive(LoggerPtr loggerPtr);
124 
125  const std::string DefaultLogFormat;
126 
127  Mutex DefaultLoggerPtrMutex;
128  LoggerPtr DefaultLoggerPtr;
129  };
130 
131  //******************************************************************************
132  // LogTarget
133 
134  class LogTarget;
135  typedef boost::shared_ptr<LogTarget> LogTargetPtr;
136 
139  class RCF_EXPORT LogTarget
140  {
141  public:
142  virtual ~LogTarget() {}
143  virtual LogTarget * clone() const = 0;
144  virtual void write(const ByteBuffer & output) = 0;
145  };
146 
148  class RCF_EXPORT LogToStdout : public LogTarget
149  {
150  public:
151  LogToStdout(bool flushAfterEachWrite = true);
152  LogTarget * clone() const;
153  void write(const ByteBuffer & output);
154 
155  static Mutex sIoMutex;
156 
157  private:
158  bool mFlush;
159  };
160 
161 #ifdef BOOST_WINDOWS
162 
164  class RCF_EXPORT LogToDebugWindow : public LogTarget
165  {
166  public:
167  LogTarget * clone() const;
168  void write(const ByteBuffer & output);
169  };
170 
172  class RCF_EXPORT LogToEventLog : public LogTarget
173  {
174  public:
175  LogToEventLog(const std::string & appName, int eventLogLevel);
176  ~LogToEventLog();
177 
178  LogTarget * clone() const;
179  void write(const ByteBuffer & output);
180 
181  private:
182  std::string mAppName;
183  int mEventLogLevel;
184  HANDLE mhEventLog;
185  };
186 
187 #endif
188 
190  class RCF_EXPORT LogToFile : public LogTarget
191  {
192  public:
193  LogToFile(const std::string & filePath, bool flushAfterEachWrite = false);
194  LogToFile(const LogToFile & rhs);
195  ~LogToFile();
196 
197  LogTarget * clone() const;
198  void write(const ByteBuffer & output);
199 
200  private:
201 
202  Mutex mMutex;
203 
204  std::string mFilePath;
205  bool mOpened;
206  FILE * mFp;
207  bool mFlush;
208  };
209 
210  typedef boost::function1<void, const ByteBuffer &> LogFunctor;
211 
212  class RCF_EXPORT LogToFunc : public LogTarget
213  {
214  public:
215  LogToFunc(LogFunctor logFunctor);
216 
217  LogTarget * clone() const;
218  void write(const ByteBuffer & output);
219 
220  private:
221  LogFunctor mLogFunctor;
222  };
223 
224  //******************************************************************************
225  // LogEntry
226 
227  class RCF_EXPORT LogEntry
228  {
229  public:
230 
231  LogEntry(int name, int level);
232  LogEntry(int name, int level, const char * szFile, int line, const char * szFunc);
233  ~LogEntry();
234 
235  // Pass everything through to mOstream.
236  template<typename T>
237  const LogEntry& operator<<(const T& t) const
238  {
239  const_cast<MemOstream&>(*mpOstream) << t;
240  return *this;
241  }
242 
243 #ifndef BOOST_NO_STD_WSTRING
244  const LogEntry& operator<<(const std::wstring& t) const
245  {
246  const_cast<MemOstream&>(*mpOstream) << wstringToString(t);
247  return *this;
248  }
249 #endif
250 
251  MemOstream & getOstream()
252  {
253  return *mpOstream;
254  }
255 
256  private:
257 
258  friend class LogManager;
259  friend class Logger;
260 
261  int mName;
262  int mLevel;
263  const char * mFile;
264  int mLine;
265  const char * mFunc;
266 
267  ThreadId mThreadId;
268  time_t mTime;
269  boost::uint32_t mTimeMs;
270 
271  MemOstream * mpOstream;
272  };
273 
274  //******************************************************************************
275  // Logger
276 
277  typedef boost::function2<void, const LogEntry &, ByteBuffer&> LogFormatFunctor;
278 
279  class RCF_EXPORT Logger : public boost::enable_shared_from_this<Logger>
280  {
281  public:
282  Logger(int name, int level, const LogTarget& logTarget, const std::string & logFormat = "");
283  Logger(int name, int level, const LogTarget& logTarget, LogFormatFunctor logFormatFunctor);
284 
285  Logger(int name, int level, LogTargetPtr logTargetPtr, const std::string & logFormat = "");
286  Logger(int name, int level, LogTargetPtr logTargetPtr, LogFormatFunctor logFormatFunctor);
287 
288  void setName(int name);
289  void setLevel(int level);
290  void setTarget(const LogTarget & logTarget);
291  void setFormat(const std::string & logFormat);
292 
293  int getName() const;
294  int getLevel() const;
295  const LogTarget& getTarget() const;
296  std::string getFormat() const;
297 
298  void write(const LogEntry & logEntry);
299 
300  void activate();
301  void deactivate();
302  bool isActive();
303 
304  private:
305 
306  int mName;
307  int mLevel;
308  LogTargetPtr mTargetPtr;
309  std::string mFormat;
310  LogFormatFunctor mFormatFunctor;
311  };
312 
313  typedef boost::shared_ptr<Logger> LoggerPtr;
314 
315  template<typename T>
316  class LogNameValue
317  {
318  public:
319  LogNameValue(const char * name, const T & value) :
320  mName(name),
321  mValue(value)
322  {
323  }
324 
325  const char * mName;
326  const T& mValue;
327 
328  friend MemOstream& operator<<(MemOstream & os, const LogNameValue& lnv)
329  {
330  os << "(" << lnv.mName << " = ";
331  printToOstream(os, lnv.mValue);
332  os << ")";
333  return os;
334  }
335  };
336 
337  template<typename T>
338  LogNameValue<T> makeNameValue(const char * name, const T & value)
339  {
340  return LogNameValue<T>(name, value);
341  }
342 
343  #define NAMEVALUE(x) RCF::makeNameValue(#x, x)
344 
345  class LogVarsFunctor : public VariableArgMacroFunctor
346  {
347  public:
348 
349  LogVarsFunctor() : mLogEntry(0, 0, NULL, 0, NULL)
350  {
351  }
352 
353  LogVarsFunctor(int name, int level, const char * file, int line, const char * szFunc) :
354  mLogEntry(name, level, file, line, szFunc)
355  {
356  }
357 
358  ~LogVarsFunctor()
359  {
360  if (mArgs->tellp() > 0)
361  {
362  mLogEntry << " [Args: ";
363  mLogEntry.getOstream().write(mArgs->str(), mArgs->tellp());
364  mLogEntry << "]";
365  }
366  }
367 
368  template<typename T>
369  const LogVarsFunctor & operator<<(const T & t) const
370  {
371  const_cast<LogEntry &>(mLogEntry) << t;
372  return *this;
373  }
374 
375  private:
376  LogEntry mLogEntry;
377  };
378 
379 #if defined(_MSC_VER)
380 #pragma warning(push)
381 #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
382 #endif
383 
384  DECLARE_VARIABLE_ARG_MACRO( UTIL_LOG, LogVarsFunctor );
385 
386 #if defined(_MSC_VER)
387 #pragma warning(pop)
388 #endif
389 
390 #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))
391 #define UTIL_LOG_GCC_33_HACK (const RCF::VariableArgMacro<RCF::LogVarsFunctor> &)
392 #else
393 #define UTIL_LOG_GCC_33_HACK
394 #endif
395 
396  #define UTIL_LOG(name, level) \
397  if (RCF::LogManager::instance().isEnabled(name, level)) \
398  UTIL_LOG_GCC_33_HACK RCF::VariableArgMacro<RCF::LogVarsFunctor>( \
399  name, level, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION) \
400  .cast( (RCF::VariableArgMacro<RCF::LogVarsFunctor> *) NULL ) \
401  .UTIL_LOG_A
402 
403  #define UTIL_LOG_A(x) UTIL_LOG_OP(x, B)
404  #define UTIL_LOG_B(x) UTIL_LOG_OP(x, A)
405  #define UTIL_LOG_OP(x, next) UTIL_LOG_A.notify_((x), #x).UTIL_LOG_ ## next
406 
407 
408 #ifdef BOOST_WINDOWS
409  typedef LogToDebugWindow DefaultLogTarget;
410 #else
411  typedef LogToStdout DefaultLogTarget;
412 #endif
413 
414  // Log format specifiers:
415  // %A: Log name
416  // %B: Log level
417  // %C: time
418  // %D: thread id
419  // %E: __FILE__
420  // %F: __LINE__
421  // %G: __FUNCTION__
422  // %H: time in ms since RCF initialization
423  // %X: output
424 
425  // Example log format:
426  // %E(%F): [Thread id: %D][Log: %A][Log level: %B]
427 
428 
433  RCF_EXPORT void enableLogging(
434  const LogTarget & logTarget = DefaultLogTarget(),
435  int logLevel = 2,
436  const std::string & logFormat = "");
437 
439  RCF_EXPORT void disableLogging();
440 
441 } // namespace RCF
442 
443 #endif // ! INCLUDE_UTIL_LOG_HPP