source: pacpusframework/trunk/src/PacpusLib/Log.cpp@ 236

Last change on this file since 236 was 236, checked in by Marek Kurdej, 11 years ago

Experimental: using global logger object instead of trivial logger. Added: stub for colored log output on Linux.

  • Property svn:executable set to *
File size: 8.9 KB
Line 
1// %pacpus:license{
2// This file is part of the PACPUS framework distributed under the
3// CECILL-C License, Version 1.0.
4// %pacpus:license}
5/// @version $Id: Log.cpp 76 2013-01-10 17:05:10Z kurdejma $
6
7#include <Pacpus/kernel/Log.h>
8
9#ifdef PACPUS_USE_LOG
10
11#include <boost/log/detail/date_time_format_parser.hpp>
12#include <boost/log/expressions.hpp>
13#include <boost/log/expressions/formatters/if.hpp>
14#include <boost/log/sinks/text_file_backend.hpp>
15#include <boost/log/sinks/text_ostream_backend.hpp>
16#include <boost/log/sources/severity_logger.hpp>
17#include <boost/log/support/date_time.hpp>
18#include <boost/log/utility/setup/common_attributes.hpp>
19#include <boost/log/utility/setup/file.hpp>
20#include <boost/log/utility/setup/formatter_parser.hpp>
21#if BOOST_VERSION >= 105500 // header exists from 1.55
22# include <boost/utility/empty_deleter.hpp>
23#else
24# include <boost/log/utility/empty_deleter.hpp>
25#endif
26#include <ostream>
27#include <QString>
28
29// could use Boost.Predef with Boost >= 1.55
30#if defined(WIN32) || defined(_WINDOWS)
31# define PACPUS_OS_WINDOWS 1
32#elif defined(__unix) || defined(__unix__)
33# define PACPUS_OS_UNIX 1
34# if defined(__linux) || defined(__linux__)
35# define PACPUS_OS_LINUX 1
36# endif
37#elif defined(__APPLE__) || defined(__MACH__) || defined(Macintosh) || defined(macintosh)
38# define PACPUS_OS_MACOS 1
39#else
40// unknown system
41#endif
42
43#if PACPUS_LOG_COLORED_OUTPUT && PACPUS_OS_WINDOWS
44# include <Windows.h>
45#endif
46
47template< typename CharT, typename TraitsT >
48std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, QString const& s)
49{
50 strm << s.toStdString();
51 return strm;
52}
53
54// explicit instantiation
55template
56PACPUSLIB_API std::basic_ostream<char>& operator<< (std::basic_ostream<char>& strm, QString const& s);
57
58namespace pacpus
59{
60
61BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", ::pacpus::SeverityLevel)
62
63enum Color {
64 COLOR_DEFAULT,
65 COLOR_BLACK,
66 COLOR_RED,
67 COLOR_GREEN,
68 COLOR_YELLOW,
69 COLOR_BLUE,
70 COLOR_MAGENTA,
71 COLOR_CYAN,
72 COLOR_WHITE
73};
74
75//Color getColor(boost::log::trivial::severity_type const& sev)
76//{
77// using namespace boost::log::trivial;
78
79// if (sev >= error) {
80// return COLOR_RED;
81// } else if (sev == warning) {
82// return COLOR_YELLOW;
83// } else if (sev == info) {
84// return COLOR_GREEN;
85// } else {
86// return COLOR_DEFAULT;
87// }
88//}
89
90#if PACPUS_OS_WINDOWS //&& !PACPUS_OS_WINDOWS_MOBILE
91
92// Returns the character attribute for the given color.
93WORD getColorAttribute(Color color)
94{
95 switch (color) {
96 case COLOR_BLACK: return 0;
97 case COLOR_RED: return FOREGROUND_RED;
98 case COLOR_GREEN: return FOREGROUND_GREEN;
99 case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
100 case COLOR_BLUE: return FOREGROUND_BLUE;
101 case COLOR_MAGENTA: return FOREGROUND_RED | FOREGROUND_BLUE;
102 case COLOR_CYAN: return FOREGROUND_GREEN | FOREGROUND_BLUE;
103 case COLOR_WHITE: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
104 default: return 0;
105 }
106}
107
108#else
109
110/// @returns the ANSI color code for the given color. COLOR_DEFAULT is
111/// an invalid input.
112const char* getAnsiColorCode(Color color)
113{
114 const char* kEscapeSequence = "\033[";
115// const char* kBackground = "";
116 const char* kFontRegular = "0;";
117// const char* kFontBold = "1;";
118// const char* kFontWeak = "2;";
119// const char* kFontStrong = "3;";
120// const char* kFontUnderline = "4;";
121
122 std::stringstream ss;
123 ss << kEscapeSequence << kFontRegular;
124
125 switch (color) {
126 case COLOR_BLACK: ss << "30"; break;
127 case COLOR_RED: ss << "31"; break;
128 case COLOR_GREEN: ss << "32"; break;
129 case COLOR_YELLOW: ss << "33"; break;
130 case COLOR_BLUE: ss << "34"; break;
131 case COLOR_MAGENTA: ss << "35"; break;
132 case COLOR_CYAN: ss << "36"; break;
133 case COLOR_WHITE: ss << "37"; break;
134 default: return "";
135 };
136
137 const char* kPostfix = "m";
138 ss << kPostfix;
139
140 return ss.str().c_str();
141}
142
143const char* getAnsiColorCodeRestoreDefault()
144{
145 return "\033[0m";
146}
147
148#endif // PACPUS_OS_WINDOWS && !PACPUS_OS_WINDOWS_MOBILE
149
150void init_log_factories()
151{
152 boost::log::register_simple_formatter_factory< QString, char >("QString");
153}
154
155static int niftyCounter;
156
157LogConfigurator::LogConfigurator()
158{
159 if (0 == niftyCounter++) {
160 LOG_INFO("LogConfigurator constructor");
161 init_log_factories();
162 }
163}
164
165LogConfigurator::~LogConfigurator()
166{
167 if (0 == --niftyCounter) {
168 // clean up
169 LOG_INFO("LogConfigurator destructor");
170 }
171}
172
173void LogConfigurator::configureLoggerWithFile(const char* logFileName)
174{
175 using namespace boost;
176
177 namespace logging = boost::log;
178 namespace sinks = boost::log::sinks;
179 namespace src = boost::log::sources;
180 namespace expr = boost::log::expressions;
181 namespace attrs = boost::log::attributes;
182 namespace keywords = boost::log::keywords;
183
184 logging::add_common_attributes();
185 logging::core::get()->add_global_attribute(
186 "ProcessID",
187 attrs::current_process_id());
188 logging::core::get()->add_global_attribute(
189 "ThreadID",
190 attrs::current_thread_id());
191 //logging::core::get()->add_global_attribute(
192 // "Scope",
193 // attrs::named_scope());
194
195 logging::core::get()->set_filter
196 (
197#ifdef NDEBUG
198 // release
199 severity >= debug
200#else
201 // debug
202 severity >= trace
203#endif
204 );
205
206 ////////////////////////////////////////////////////////////////////////////////
207 // FILE
208 logging::add_file_log
209 (
210 keywords::file_name = logFileName,
211 keywords::rotation_size = 10 * 1024 * 1024,
212 keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
213 //keywords::format = "%LineID% [%TimeStamp%]: %Message%"
214 keywords::format =
215 (
216 expr::stream
217 << std::setfill('0') << std::setw(6) << expr::attr< unsigned int >("LineID")
218 //<< " [" << expr::format_date_time< posix_time::ptime >("TimeStamp", date_time::iso_extended_format) << "]"
219 << " [" << expr::format_date_time< posix_time::ptime >("TimeStamp", "%Y-%m-%d %T.%f") << "]"
220 //<< " [" << std::setw(20) << expr::attr<std::string>("Scope") << ">"
221 << " <" << severity << ">"
222 << " <" << expr::attr< attrs::current_process_id::value_type >("ProcessID")
223 << ":" << expr::attr< attrs::current_thread_id::value_type >("ThreadID") << ">"
224 << " " << expr::smessage
225 )
226 );
227
228 ////////////////////////////////////////////////////////////////////////////////
229 // CONSOLE
230#if PACPUS_LOG_COLORED_OUTPUT
231 Color color = COLOR_GREEN;// = getColor(expr::attr<logging::trivial::severity_level>(logging::trivial::severity.get_name()));
232#endif
233
234#if BOOST_VERSION >= 105500
235#else
236 using logging::empty_deleter;
237#endif
238
239 // Create a backend and attach a couple of streams to it
240 boost::shared_ptr< sinks::text_ostream_backend > backend =
241 make_shared< sinks::text_ostream_backend >();
242 backend->add_stream(
243 shared_ptr< std::ostream >(&std::clog, empty_deleter())
244 );
245
246 // Enable auto-flushing after each log record written
247 backend->auto_flush(true);
248
249 // Wrap it into the frontend and register in the core.
250 // The backend requires synchronization in the frontend.
251 typedef sinks::synchronous_sink< sinks::text_ostream_backend > sink_t;
252 shared_ptr< sink_t > sink(new sink_t(backend));
253 sink->set_filter
254 (
255 severity >= info
256 );
257
258 sink->set_formatter
259 (
260 expr::stream
261#if PACPUS_LOG_COLORED_OUTPUT && PACPUS_OS_LINUX
262// << getAnsiColorCode(color)
263#endif
264 << std::setfill('0') << std::setw(6) << expr::attr< unsigned int >("LineID")
265 //<< " [" << expr::format_date_time< posix_time::ptime >("TimeStamp", date_time::iso_extended_format) << "] "
266 << " [" << expr::format_date_time< posix_time::ptime >("TimeStamp", "%Y-%m-%d %T.%f") << "] "
267 //<< " [" << std::setw(20) << expr::attr<std::string>("Scope") << ">"
268 << "<" << severity << ">"
269 << " "
270 << expr::smessage
271#if PACPUS_LOG_COLORED_OUTPUT && PACPUS_OS_LINUX
272 << getAnsiColorCodeRestoreDefault() // Resets the terminal to default.
273#endif
274 );
275
276 logging::core::get()->add_sink(sink);
277
278 LOG_INFO("logger initialised");
279}
280
281} // namespace pacpus
282
283#else // PACPUS_USE_LOG
284
285namespace pacpus
286{
287
288 LogConfigurator::LogConfigurator()
289 {}
290
291 LogConfigurator::~LogConfigurator()
292 {}
293
294 void LogConfigurator::configureLoggerWithFile(const char* /*configFilename*/)
295 {}
296
297} // namespace pacpus
298
299#endif // PACPUS_USE_LOG
300
Note: See TracBrowser for help on using the repository browser.