xref: /glogg/src/log.h (revision 6e2e573c451ec24d720c967fab68538eaa3f3ab5)
1 /*
2  * Copyright (C) 2009, 2010 Nicolas Bonnefon and other contributors
3  *
4  * This file is part of glogg.
5  *
6  * glogg is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * glogg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef __LOG_H__
21 #define __LOG_H__
22 
23 #include <sstream>
24 #include <string>
25 #include <cstdio>
26 
27 // Modify here!
28 //#define FILELOG_MAX_LEVEL logDEBUG
29 
30 inline std::string NowTime();
31 
32 enum TLogLevel {logERROR, logWARNING, logINFO, logDEBUG, logDEBUG1, logDEBUG2, logDEBUG3, logDEBUG4};
33 
34 template <typename T>
35 class Log
36 {
37 public:
38     Log();
39     virtual ~Log();
40     std::ostringstream& Get(TLogLevel level = logINFO,
41             const std::string& sourceFile = "", int lineNumber = 0);
42 public:
43     static TLogLevel ReportingLevel() { return reportingLevel; }
44     static std::string ToString(TLogLevel level);
45     static TLogLevel FromString(const std::string& level);
46     static void setReportingLevel(TLogLevel level) { reportingLevel = level; }
47 
48     template <typename U> friend class Log;
49 
50 protected:
51     std::ostringstream os;
52 private:
53     static TLogLevel reportingLevel;
54 
55     Log(const Log&);
56     Log& operator =(const Log&);
57 };
58 
59 template <typename T> TLogLevel Log<T>::reportingLevel = logDEBUG4;
60 
61 template <typename T>
62 Log<T>::Log()
63 {
64 }
65 
66 template <typename T>
67 std::ostringstream& Log<T>::Get(TLogLevel level,
68         const std::string& sourceFile, int lineNumber)
69 {
70     os << "- " << NowTime();
71     os << " " << ToString(level);
72     os << " " << sourceFile << ":" << lineNumber << ": ";
73     os << std::string(level > logDEBUG ? level - logDEBUG : 0, '\t');
74     return os;
75 }
76 
77 template <typename T>
78 Log<T>::~Log()
79 {
80     os << std::endl;
81     T::Output(os.str());
82 }
83 
84 template <typename T>
85 std::string Log<T>::ToString(TLogLevel level)
86 {
87     static const char* const buffer[] = {"ERROR", "WARNING", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4"};
88     return buffer[level];
89 }
90 
91 template <typename T>
92 TLogLevel Log<T>::FromString(const std::string& level)
93 {
94     if (level == "DEBUG4")
95         return logDEBUG4;
96     if (level == "DEBUG3")
97         return logDEBUG3;
98     if (level == "DEBUG2")
99         return logDEBUG2;
100     if (level == "DEBUG1")
101         return logDEBUG1;
102     if (level == "DEBUG")
103         return logDEBUG;
104     if (level == "INFO")
105         return logINFO;
106     if (level == "WARNING")
107         return logWARNING;
108     if (level == "ERROR")
109         return logERROR;
110     Log<T>().Get(logWARNING) << "Unknown logging level '" << level << "'. Using INFO level as default.";
111     return logINFO;
112 }
113 
114 class Output2FILE
115 {
116 public:
117     static FILE*& Stream();
118     static void Output(const std::string& msg);
119 };
120 
121 inline FILE*& Output2FILE::Stream()
122 {
123     static FILE* pStream = stderr;
124     return pStream;
125 }
126 
127 inline void Output2FILE::Output(const std::string& msg)
128 {
129     FILE* pStream = Stream();
130     if (!pStream)
131         return;
132     fprintf(pStream, "%s", msg.c_str());
133     fflush(pStream);
134 }
135 
136 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
137 #   if defined (BUILDING_FILELOG_DLL)
138 #       define FILELOG_DECLSPEC   __declspec (dllexport)
139 #   elif defined (USING_FILELOG_DLL)
140 #       define FILELOG_DECLSPEC   __declspec (dllimport)
141 #   else
142 #       define FILELOG_DECLSPEC
143 #   endif // BUILDING_DBSIMPLE_DLL
144 #else
145 #   define FILELOG_DECLSPEC
146 #endif // _WIN32
147 
148 //class FILELOG_DECLSPEC FILELog : public Log<Output2FILE> {};
149 typedef Log<Output2FILE> FILELog;
150 
151 #ifndef FILELOG_MAX_LEVEL
152 #define FILELOG_MAX_LEVEL logDEBUG
153 #endif
154 
155 #define FILE_LOG(level) \
156     if (level > FILELOG_MAX_LEVEL) ;\
157     else if (level > FILELog::ReportingLevel() || !Output2FILE::Stream()) ; \
158     else FILELog().Get(level, __FILE__, __LINE__)
159 
160 #define LOG(level) FILE_LOG(level)
161 
162 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
163 
164 #include <windows.h>
165 
166 inline std::string NowTime()
167 {
168     const int MAX_LEN = 200;
169     char buffer[MAX_LEN];
170     if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0,
171             "HH':'mm':'ss", buffer, MAX_LEN) == 0)
172         return "Error in NowTime()";
173 
174     char result[100] = {0};
175     static DWORD first = GetTickCount();
176     std::sprintf(result, "%s.%03ld", buffer, (long)(GetTickCount() - first) % 1000);
177     return result;
178 }
179 
180 #else
181 
182 #include <sys/time.h>
183 
184 inline std::string NowTime()
185 {
186     char buffer[11];
187     time_t t;
188     time(&t);
189     tm r;
190     strftime(buffer, sizeof(buffer), "%T", localtime_r(&t, &r));
191     struct timeval tv;
192     gettimeofday(&tv, 0);
193     char result[100] = {0};
194     std::sprintf(result, "%s.%03ld", buffer, (long)tv.tv_usec / 1000);
195     return result;
196 }
197 
198 #endif //WIN32
199 
200 #endif //__LOG_H__
201