ECLogger.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. // -*- Mode: c++ -*-
  18. #ifndef ECLOGGER_H
  19. #define ECLOGGER_H
  20. #include <kopano/zcdefs.h>
  21. #include <kopano/platform.h>
  22. #include <list>
  23. #include <mutex>
  24. #include <pthread.h>
  25. #include <csignal>
  26. #include <cstdarg>
  27. #include <cstdio>
  28. #include <string>
  29. #include <kopano/lockhelper.hpp>
  30. #ifndef __LIKE_PRINTF
  31. #define __LIKE_PRINTF(_fmt, _va)
  32. #endif
  33. namespace KC {
  34. class ECConfig;
  35. class ECLogger;
  36. static const unsigned int EC_LOGLEVEL_NONE = 0;
  37. static const unsigned int EC_LOGLEVEL_FATAL = 1;
  38. static const unsigned int EC_LOGLEVEL_CRIT = 1;
  39. static const unsigned int EC_LOGLEVEL_ERROR = 2;
  40. static const unsigned int EC_LOGLEVEL_WARNING = 3;
  41. static const unsigned int EC_LOGLEVEL_NOTICE = 4;
  42. static const unsigned int EC_LOGLEVEL_INFO = 5;
  43. static const unsigned int EC_LOGLEVEL_DEBUG = 6;
  44. static const unsigned int EC_LOGLEVEL_ALWAYS = 0xf;
  45. static const unsigned int EC_LOGLEVEL_MASK = 0xF;
  46. // extended log options
  47. static const unsigned int EC_LOGLEVEL_SQL = 0x00010000;
  48. static const unsigned int EC_LOGLEVEL_PLUGIN = 0x00020000;
  49. static const unsigned int EC_LOGLEVEL_CACHE = 0x00040000;
  50. static const unsigned int EC_LOGLEVEL_USERCACHE = 0x00080000;
  51. static const unsigned int EC_LOGLEVEL_SOAP = 0x00100000;
  52. static const unsigned int EC_LOGLEVEL_ICS = 0x00200000;
  53. static const unsigned int EC_LOGLEVEL_SEARCH = 0x00400000;
  54. static const unsigned int EC_LOGLEVEL_EXTENDED_MASK = 0xFFFF0000;
  55. #define _LOG_BUFSIZE 10240
  56. #define _LOG_TSSIZE 64
  57. #define ZLOG_DEBUG(_plog, ...) \
  58. do { \
  59. if ((_plog)->Log(EC_LOGLEVEL_DEBUG)) \
  60. (_plog)->Log(EC_LOGLEVEL_DEBUG, __VA_ARGS__); \
  61. } while (false)
  62. #define ZLOG_AUDIT(_plog, ...) \
  63. do { \
  64. if ((_plog) != NULL) \
  65. (_plog)->Log(EC_LOGLEVEL_FATAL, __VA_ARGS__); \
  66. } while (false)
  67. #ifdef UNICODE
  68. #define TSTRING_PRINTF "%ls"
  69. #else
  70. #define TSTRING_PRINTF "%s"
  71. #endif
  72. /**
  73. * Prefixes in log message in different process models.
  74. *
  75. * LP_NONE: No prefix in log message (default)
  76. * LP_TID: Add thread id as prefix
  77. * LP_PID: Add linux process id as prefix
  78. */
  79. enum logprefix { LP_NONE, LP_TID, LP_PID };
  80. /**
  81. * ECLogger object logs messages to a specific
  82. * destination. Destinations are created in derived classes.
  83. */
  84. class _kc_export ECLogger {
  85. private:
  86. std::mutex m_mutex;
  87. unsigned m_ulRef;
  88. protected:
  89. /**
  90. * Returns string with timestamp in current locale.
  91. */
  92. _kc_hidden std::string MakeTimestamp(void);
  93. unsigned int max_loglevel;
  94. locale_t timelocale;
  95. locale_t datalocale;
  96. logprefix prefix;
  97. /**
  98. * Constructor of ECLogger. Implementations should open the log they're writing to.
  99. *
  100. * @param[in] max_ll Max loglevel allowed to enter in the log. Messages with higher loglevel will be skipped.
  101. */
  102. ECLogger(int max_ll);
  103. /**
  104. * Destructor of ECLogger. Implementations should close the log they're writing to.
  105. */
  106. virtual ~ECLogger();
  107. public:
  108. /**
  109. * Query if a message would be logged under this loglevel
  110. *
  111. * @param[in] loglevel Loglevel you want to know if it enters the log.
  112. * @return bool
  113. * @retval true Logging with 'loglevel' will enter log
  114. * @retval false Logging with 'loglevel' will be dropped
  115. */
  116. virtual bool Log(unsigned int loglevel);
  117. /**
  118. * Set new loglevel for log object
  119. *
  120. * @param[in] max_ll The new maximum loglevel
  121. */
  122. void SetLoglevel(unsigned int max_ll);
  123. /**
  124. * Set new prefix for log
  125. *
  126. * @param[in] lp New logprefix LP_TID or LP_PID. Disable prefix with LP_NONE.
  127. */
  128. void SetLogprefix(logprefix lp);
  129. /**
  130. * Adds reference to this object
  131. */
  132. unsigned AddRef();
  133. /**
  134. * Removes a reference from this object, and deletes it if all
  135. * references are removed.
  136. */
  137. unsigned Release();
  138. /**
  139. * Like the CRT snprintf, but uses the datalocale used by the current
  140. * ECLogger instance.
  141. */
  142. int snprintf(char *str, size_t size, const char *format, ...) __LIKE_PRINTF(4, 5);
  143. /**
  144. * Used for log rotation. Implementations should prepare to log in a new log.
  145. *
  146. * @param[in] lp New logprefix LP_TID or LP_PID. Disable prefix with LP_NONE.
  147. */
  148. virtual void Reset() = 0;
  149. /**
  150. * Used to get a direct file descriptor of the log file. Returns
  151. * -1 if not available.
  152. *
  153. * @return int The file descriptor of the logfile being written to.
  154. */
  155. _kc_hidden virtual int GetFileDescriptor(void) { return -1; }
  156. /**
  157. * Log a message on a specified loglevel using std::string
  158. *
  159. * @param loglevel Loglevel to log message under
  160. * @param message std::string logmessage. Expected charset is current locale.
  161. */
  162. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) = 0;
  163. /**
  164. * Log a message on a specified loglevel using char* format
  165. *
  166. * @param loglevel Loglevel to log message under
  167. * @param format formatted string for the parameter list
  168. */
  169. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) __LIKE_PRINTF(3, 4) = 0;
  170. /**
  171. * Log a message on a specified loglevel using char* format
  172. *
  173. * @param loglevel Loglevel to log message under
  174. * @param format formatted string for the parameter list
  175. * @param va va_list converted from ... parameters
  176. */
  177. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) = 0;
  178. };
  179. /**
  180. * Dummy null logger, drops every log message.
  181. */
  182. class _kc_export ECLogger_Null _kc_final : public ECLogger {
  183. public:
  184. ECLogger_Null(void);
  185. _kc_hidden virtual void Reset(void) _kc_override;
  186. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) _kc_override;
  187. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) _kc_override __LIKE_PRINTF(3, 4);
  188. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) _kc_override;
  189. };
  190. /**
  191. * File logger. Use "-" for stderr logging. Output is in system locale set in LC_CTYPE.
  192. */
  193. class _kc_export_dycast ECLogger_File _kc_final : public ECLogger {
  194. private:
  195. typedef void* handle_type;
  196. typedef handle_type(*open_func)(const char*, const char*);
  197. typedef int(*close_func)(handle_type);
  198. typedef int(*printf_func)(handle_type, const char*, ...);
  199. typedef int(*fileno_func)(handle_type);
  200. typedef int(*flush_func)(handle_type);
  201. KC::shared_mutex handle_lock, dupfilter_lock;
  202. handle_type log;
  203. std::string logname;
  204. bool timestamp;
  205. size_t buffer_size;
  206. open_func fnOpen;
  207. close_func fnClose;
  208. printf_func fnPrintf;
  209. fileno_func fnFileno;
  210. const char *szMode;
  211. int prevcount;
  212. std::string prevmsg;
  213. unsigned int prevloglevel;
  214. _kc_hidden bool DupFilter(unsigned int level, const std::string &msg);
  215. _kc_hidden std::string DoPrefix(void);
  216. public:
  217. ECLogger_File(const unsigned int max_ll, const bool add_timestamp, const char *const filename, const bool compress);
  218. ~ECLogger_File(void);
  219. _kc_hidden std::string EmitLevel(unsigned int level);
  220. _kc_hidden void reinit_buffer(size_t size);
  221. _kc_hidden virtual void Reset(void) _kc_override;
  222. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) _kc_override;
  223. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) _kc_override __LIKE_PRINTF(3, 4);
  224. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) _kc_override;
  225. _kc_hidden int GetFileDescriptor(void) _kc_override;
  226. bool IsStdErr();
  227. private:
  228. _kc_hidden void init_for_stderr(void);
  229. _kc_hidden void init_for_file(void);
  230. _kc_hidden void init_for_gzfile(void);
  231. };
  232. /**
  233. * Linux syslog logger. Output is whatever syslog does, probably LC_CTYPE.
  234. */
  235. class _kc_export_dycast ECLogger_Syslog _kc_final : public ECLogger {
  236. private:
  237. char *m_ident;
  238. static const int levelmap[16]; /* converts to syslog levels */
  239. public:
  240. ECLogger_Syslog(unsigned int max_ll, const char *ident, int facility);
  241. ~ECLogger_Syslog(void);
  242. _kc_hidden virtual void Reset(void) _kc_override;
  243. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) _kc_override;
  244. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) _kc_override __LIKE_PRINTF(3, 4);
  245. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) _kc_override;
  246. };
  247. /**
  248. * Pipe Logger, only used by forked model processes. Redirects every
  249. * log message to an ECLogger_File object. This ECLogger_Pipe object
  250. * can be created by StartLoggerProcess function.
  251. */
  252. class _kc_export_dycast ECLogger_Pipe _kc_final : public ECLogger {
  253. private:
  254. int m_fd;
  255. pid_t m_childpid;
  256. public:
  257. ECLogger_Pipe(int fd, pid_t childpid, int loglevel);
  258. _kc_hidden ~ECLogger_Pipe(void);
  259. _kc_hidden virtual void Reset(void) _kc_override;
  260. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) _kc_override;
  261. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) _kc_override __LIKE_PRINTF(3, 4);
  262. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) _kc_override;
  263. _kc_hidden int GetFileDescriptor(void) _kc_override { return m_fd; }
  264. void Disown();
  265. };
  266. extern _kc_export ECLogger *StartLoggerProcess(ECConfig *, ECLogger *file_logger);
  267. /**
  268. * This class can be used if log messages need to go to
  269. * multiple destinations. It basically distributes
  270. * the messages to one or more attached ECLogger objects.
  271. *
  272. * Each attached logger can have its own loglevel.
  273. */
  274. class _kc_export ECLogger_Tee _kc_final : public ECLogger {
  275. private:
  276. typedef std::list<ECLogger*> LoggerList;
  277. LoggerList m_loggers;
  278. public:
  279. ECLogger_Tee();
  280. _kc_hidden ~ECLogger_Tee(void);
  281. _kc_hidden virtual void Reset(void) _kc_override;
  282. _kc_hidden virtual bool Log(unsigned int level) _kc_override;
  283. _kc_hidden virtual void Log(unsigned int level, const std::string &msg) _kc_override;
  284. _kc_hidden virtual void Log(unsigned int level, const char *fmt, ...) _kc_override __LIKE_PRINTF(3, 4);
  285. _kc_hidden virtual void LogVA(unsigned int level, const char *fmt, va_list &) _kc_override;
  286. void AddLogger(ECLogger *lpLogger);
  287. };
  288. extern _kc_export bool ec_log_has_target(void);
  289. extern _kc_export ECLogger *ec_log_get(void);
  290. extern _kc_export void ec_log_set(ECLogger *);
  291. extern _kc_export void ec_log(unsigned int level, const char *msg, ...) __LIKE_PRINTF(2, 3);
  292. extern _kc_export void ec_log(unsigned int level, const std::string &msg);
  293. #define ec_log_always(...) ec_log(EC_LOGLEVEL_ALWAYS, __VA_ARGS__)
  294. #define ec_log_fatal(...) ec_log(EC_LOGLEVEL_CRIT, __VA_ARGS__)
  295. #define ec_log_crit(...) ec_log(EC_LOGLEVEL_CRIT, __VA_ARGS__)
  296. #define ec_log_err(...) ec_log(EC_LOGLEVEL_ERROR, __VA_ARGS__)
  297. #define ec_log_warn(...) ec_log(EC_LOGLEVEL_WARNING, __VA_ARGS__)
  298. #define ec_log_notice(...) ec_log(EC_LOGLEVEL_NOTICE, __VA_ARGS__)
  299. #define ec_log_info(...) ec_log(EC_LOGLEVEL_INFO, __VA_ARGS__)
  300. #define ec_log_debug(...) ec_log(EC_LOGLEVEL_DEBUG, __VA_ARGS__)
  301. extern _kc_export ECLogger *CreateLogger(ECConfig *, const char *argv0, const char *service, bool audit = false);
  302. extern _kc_export int DeleteLogger(ECLogger *);
  303. extern _kc_export void LogConfigErrors(ECConfig *);
  304. extern _kc_export void generic_sigsegv_handler(ECLogger *, const char *app, const char *vers, int sig, const siginfo_t *, const void *uctx);
  305. void ec_log_bt(unsigned int, const char *, ...);
  306. } /* namespace */
  307. #endif /* ECLOGGER_H */