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:
ReportingLevel()43 static TLogLevel ReportingLevel() { return reportingLevel; }
44 static std::string ToString(TLogLevel level);
45 static TLogLevel FromString(const std::string& level);
setReportingLevel(TLogLevel 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>
Log()62 Log<T>::Log()
63 {
64 }
65
66 template <typename T>
Get(TLogLevel level,const std::string & sourceFile,int lineNumber)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>
~Log()78 Log<T>::~Log()
79 {
80 os << std::endl;
81 T::Output(os.str());
82 }
83
84 template <typename T>
ToString(TLogLevel level)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>
FromString(const std::string & level)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
Stream()121 inline FILE*& Output2FILE::Stream()
122 {
123 static FILE* pStream = stderr;
124 return pStream;
125 }
126
Output(const std::string & msg)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
NowTime()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
NowTime()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