source: launchers/macosx/Logger.h @ 1a00f73

Last change on this file since 1a00f73 was 5a0017a, checked in by meeh <meeh@…>, 23 months ago

Mac OSX Launcher: Adding a logger library I wrote a good while ago, refactored it to work with the launcher.

  • Property mode set to 100644
File size: 9.8 KB
Line 
1//
2//  Logger.h
3//  I2PLauncher
4//
5//  Created by Mikal Villa on 27/09/2018.
6//  Copyright © 2018 The I2P Project. All rights reserved.
7//  Imported/Refactored from earlier C++ project of Meeh
8//
9
10#ifndef Logger_h
11#define Logger_h
12
13#ifdef __cplusplus
14
15#include <string>
16#include <sstream>
17#include <iostream>
18#include <cstdarg>
19#include <chrono>
20#include <functional>
21#include <ctime>
22
23
24/**
25 * For details please see this
26 * REFERENCE: http://www.cppreference.com/wiki/io/c/printf_format
27 * \verbatim
28 *
29 There are different %-codes for different variable types, as well as options to
30 limit the length of the variables and whatnot.
31 Code Format
32 %[flags][width][.precision][length]specifier
33 SPECIFIERS
34 ----------
35 %c character
36 %d signed integers
37 %i signed integers
38 %e scientific notation, with a lowercase “e”
39 %E scientific notation, with a uppercase “E”
40 %f floating point
41 %g use %e or %f, whichever is shorter
42 %G use %E or %f, whichever is shorter
43 %o octal
44 %s a string of characters
45 %u unsigned integer
46 %x unsigned hexadecimal, with lowercase letters
47 %X unsigned hexadecimal, with uppercase letters
48 %p a pointer
49 %n the argument shall be a pointer to an integer into which is placed the number of characters written so far
50
51 */
52
53/*
54 Usage:
55 
56 SharedLogWorker logger(argv[0], path_to_log_file);
57 MeehLog::initializeLogging(&logger);
58 
59 MLOG(INFO) << "Test SLOG INFO";
60 MLOG(DEBUG) << "Test SLOG DEBUG";
61 
62 */
63
64
65class SharedLogWorker;
66
67#if !(defined(__PRETTY_FUNCTION__))
68#define __PRETTY_FUNCTION__   __FUNCTION__
69#endif
70
71const int ML_ANNOYING = 0;
72const int ML_DEBUG = 1;
73const int ML_INFO = 2;
74const int ML_WARN = 3;
75const int ML_ERROR = 4;
76const int ML_FATAL = 5;
77static const std::string kFatalLogExpression = "";
78
79#define MLOG_ANNOYING  MeehLog::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"ML_ANNOYING")
80#define MLOG_DEBUG     MeehLog::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"ML_DEBUG")
81#define MLOG_INFO      MeehLog::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"ML_INFO")
82#define MLOG_WARN      MeehLog::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"ML_WARN")
83#define MLOG_ERROR     MeehLog::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"ML_ERROR")
84#define MLOG_FATAL     MeehLog::internal::LogContractMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,k_fatal_log_expression)
85
86// MLOG(level) is the API for the stream log
87#define MLOG(level) MLOG_##level.messageStream()
88
89// conditional stream log
90#define LOG_IF(level, boolean_expression)  \
91  if(true == boolean_expression)           \
92    MLOG_##level.messageStream()
93
94#define MASSERT(boolean_expression)                                                    \
95  if (false == (boolean_expression))                                                   \
96    MeehLog::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__, #boolean_expression).messageStream()
97
98
99#define MLOGF_ANNOYING  MeehLog::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"ML_ANNOYING")
100#define MLOGF_INFO      MeehLog::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"ML_INFO")
101#define MLOGF_DEBUG     MeehLog::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"ML_DEBUG")
102#define MLOGF_WARN      MeehLog::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"ML_WARN")
103#define MLOGF_ERROR     MeehLog::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"ML_ERROR")
104#define MLOGF_FATAL     MeehLog::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,k_fatal_log_expression)
105
106// MLOGF(level,msg,...) is the API for the "printf" like log
107#define MLOGF(level, printf_like_message, ...)                   \
108  MLOGF_##level.messageSave(printf_like_message, ##__VA_ARGS__)
109
110// conditional log printf syntax
111#define MLOGF_IF(level,boolean_expression, printf_like_message, ...) \
112  if(true == boolean_expression)                                    \
113    MLOG_##level.messageSave(printf_like_message, ##__VA_ARGS__)
114
115// Design By Contract, printf-like API syntax with variadic input parameters. Throws std::runtime_eror if contract breaks */
116#define MASSERTF(boolean_expression, printf_like_message, ...)                                     \
117  if (false == (boolean_expression))                                                               \
118    MeehLog::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,#boolean_expression).messageSave(printf_like_message, ##__VA_ARGS__)
119
120namespace MeehLog {
121 
122 
123  // PUBLIC API:
124  /** Install signal handler that catches FATAL C-runtime or OS signals
125   SIGABRT  ABORT (ANSI), abnormal termination
126   SIGFPE   Floating point exception (ANSI): http://en.wikipedia.org/wiki/SIGFPE
127   SIGILL   ILlegal instruction (ANSI)
128   SIGSEGV  Segmentation violation i.e. illegal memory reference
129   SIGTERM  TERMINATION (ANSI) */
130  void installSignalHandler();
131 
132  namespace internal {
133   
134   
135    /** \return signal_name. Ref: signum.h and \ref installSignalHandler */
136    std::string signalName(int signal_number);
137   
138    /** Re-"throw" a fatal signal, previously caught. This will exit the application
139     * This is an internal only function. Do not use it elsewhere. It is triggered
140     * from g2log, g2LogWorker after flushing messages to file */
141    void exitWithDefaultSignalHandler(int signal_number);
142   
143    std::time_t systemtime_now();
144    bool isLoggingInitialized();
145   
146    struct LogEntry {
147      LogEntry(std::string msg, std::time_t timestamp) : mMsg(msg), mTimestamp(timestamp) {}
148      LogEntry(const LogEntry& other): mMsg(other.mMsg), mTimestamp(other.mTimestamp) {}
149      LogEntry& operator=(const LogEntry& other) {
150        mMsg = other.mMsg;
151        mTimestamp = other.mTimestamp;
152        return *this;
153      }
154     
155     
156      std::string mMsg;
157      std::time_t mTimestamp;
158    };
159   
160    /** Trigger for flushing the message queue and exiting the application
161     A thread that causes a FatalMessage will sleep forever until the
162     application has exited (after message flush) */
163    struct FatalMessage {
164      enum FatalType {kReasonFatal, kReasonOS_FATAL_SIGNAL};
165      FatalMessage(LogEntry message, FatalType type, int signal_id);
166      ~FatalMessage() {};
167      FatalMessage& operator=(const FatalMessage& fatal_message);
168     
169     
170      LogEntry mMessage;
171      FatalType mType;
172      int mSignalId;
173    };
174    // Will trigger a FatalMessage sending
175    struct FatalTrigger {
176      FatalTrigger(const FatalMessage& message);
177      ~FatalTrigger();
178      FatalMessage mMessage;
179    };
180
181    // Log message for 'printf-like' or stream logging, it's a temporary message constructions
182    class LogMessage {
183    public:
184      LogMessage(const std::string& file, const int line, const std::string& function, const std::string& level);
185      virtual ~LogMessage(); // at destruction will flush the message
186     
187      std::ostringstream& messageStream() {return mStream;}
188     
189      // To generate warn on illegal printf format
190    #ifndef __GNUC__
191    #define  __attribute__(x)
192    #endif
193      // C++ get 'this' as first arg
194      void messageSave(const char* printf_like_message, ...)
195      __attribute__((format(printf, 2, 3) ));
196     
197    protected:
198      const std::string mFile;
199      const int mLine;
200      const std::string mFunction;
201      const std::string mLevel;
202      std::ostringstream mStream;
203      std::string mLogEntry;
204      std::time_t mTimestamp;
205    };
206
207    // 'Design-by-Contract' temporary messsage construction
208    class LogContractMessage : public LogMessage {
209    public:
210      LogContractMessage(const std::string& file, const int line,
211                         const std::string& function, const std::string& boolean_expression);
212      virtual ~LogContractMessage(); // at destruction will flush the message
213     
214    protected:
215      const std::string mExpression;
216    };
217   
218    //  wrap for std::chrono::system_clock::now()
219    std::time_t systemtime_now();
220   
221  } // namespace internal
222 
223 
224 
225  /** Should be called at very first startup of the software with \ref SharedLogWorker pointer.
226   * Ownership of the \ref SharedLogWorker is the responsibilkity of the caller */
227  void initializeLogging(SharedLogWorker* logger);
228 
229  /** Shutdown the logging by making the pointer to the background logger to nullptr
230   * The \ref pointer to the SharedLogWorker is owned by the instantniater \ref initializeLogging
231   * and is not deleted.
232   */
233  void shutDownLogging();
234 
235  /** Same as the Shutdown above but called by the destructor of the LogWorker, thus ensuring that no further
236   *  LOG(...) calls can happen to  a non-existing LogWorker.
237   *  @param active MUST BE the LogWorker initialized for logging. If it is not then this call is just ignored
238   *         and the logging continues to be active.
239   * @return true if the correct worker was given,. and shutDownLogging was called
240   */
241  bool shutDownLoggingForActiveOnly(SharedLogWorker* active);
242 
243 
244  typedef std::chrono::steady_clock::time_point steady_time_point;
245  typedef std::chrono::time_point<std::chrono::system_clock>  system_time_point;
246  typedef std::chrono::milliseconds milliseconds;
247  typedef std::chrono::microseconds microseconds;
248 
249  /** return time representing POD struct (ref ctime + wchar) that is normally
250   * retrieved with std::localtime. MeehLog::localtime is threadsafe which std::localtime is not.
251   * MeehLog::localtime is probably used together with @ref MeehLog::systemtime_now */
252  tm localtime(const std::time_t& time);
253 
254  /** format string must conform to std::put_time's demands.
255   * WARNING: At time of writing there is only so-so compiler support for
256   * std::put_time. A possible fix if your c++11 library is not updated is to
257   * modify this to use std::strftime instead */
258  std::string localtime_formatted(const std::time_t& time_snapshot, const std::string& time_format) ;
259} // namespace MeehLog
260
261#endif // __cplusplus
262
263#endif /* Logger_h */
Note: See TracBrowser for help on using the repository browser.