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
RevLine 
[89]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
[143]11#include <boost/log/detail/date_time_format_parser.hpp>
12#include <boost/log/expressions.hpp>
[236]13#include <boost/log/expressions/formatters/if.hpp>
[143]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>
[236]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
[141]26#include <ostream>
[89]27#include <QString>
28
[236]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
[141]47template< typename CharT, typename TraitsT >
48std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, QString const& s)
[89]49{
[141]50 strm << s.toStdString();
51 return strm;
[89]52}
53
[141]54// explicit instantiation
55template
56PACPUSLIB_API std::basic_ostream<char>& operator<< (std::basic_ostream<char>& strm, QString const& s);
[89]57
[231]58namespace pacpus
59{
[236]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
[142]150void init_log_factories()
151{
[143]152 boost::log::register_simple_formatter_factory< QString, char >("QString");
[142]153}
[89]154
[143]155static int niftyCounter;
[89]156
157LogConfigurator::LogConfigurator()
158{
[143]159 if (0 == niftyCounter++) {
[146]160 LOG_INFO("LogConfigurator constructor");
[143]161 init_log_factories();
162 }
[89]163}
164
[143]165LogConfigurator::~LogConfigurator()
[89]166{
[143]167 if (0 == --niftyCounter) {
168 // clean up
[146]169 LOG_INFO("LogConfigurator destructor");
[143]170 }
[89]171}
172
[228]173void LogConfigurator::configureLoggerWithFile(const char* logFileName)
[143]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();
[176]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());
[236]191 //logging::core::get()->add_global_attribute(
192 // "Scope",
193 // attrs::named_scope());
[176]194
[143]195 logging::core::get()->set_filter
196 (
[146]197#ifdef NDEBUG
198 // release
[236]199 severity >= debug
[146]200#else
201 // debug
[236]202 severity >= trace
[146]203#endif
[143]204 );
205
[236]206 ////////////////////////////////////////////////////////////////////////////////
207 // FILE
[143]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")
[176]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") << "]"
[236]220 //<< " [" << std::setw(20) << expr::attr<std::string>("Scope") << ">"
221 << " <" << severity << ">"
[176]222 << " <" << expr::attr< attrs::current_process_id::value_type >("ProcessID")
223 << ":" << expr::attr< attrs::current_thread_id::value_type >("ThreadID") << ">"
224 << " " << expr::smessage
[143]225 )
226 );
[236]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
[143]233
[236]234#if BOOST_VERSION >= 105500
235#else
236 using logging::empty_deleter;
237#endif
238
[143]239 // Create a backend and attach a couple of streams to it
[236]240 boost::shared_ptr< sinks::text_ostream_backend > backend =
241 make_shared< sinks::text_ostream_backend >();
[143]242 backend->add_stream(
[225]243 shared_ptr< std::ostream >(&std::clog, empty_deleter())
[143]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 (
[236]255 severity >= info
[143]256 );
[146]257
[143]258 sink->set_formatter
259 (
260 expr::stream
[236]261#if PACPUS_LOG_COLORED_OUTPUT && PACPUS_OS_LINUX
262// << getAnsiColorCode(color)
263#endif
[143]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") << "] "
[236]267 //<< " [" << std::setw(20) << expr::attr<std::string>("Scope") << ">"
268 << "<" << severity << ">"
[143]269 << " "
270 << expr::smessage
[236]271#if PACPUS_LOG_COLORED_OUTPUT && PACPUS_OS_LINUX
272 << getAnsiColorCodeRestoreDefault() // Resets the terminal to default.
273#endif
[143]274 );
275
276 logging::core::get()->add_sink(sink);
277
[144]278 LOG_INFO("logger initialised");
[143]279}
280
[89]281} // namespace pacpus
[143]282
283#else // PACPUS_USE_LOG
284
285namespace pacpus
[231]286{
[143]287
288 LogConfigurator::LogConfigurator()
289 {}
[231]290
291 LogConfigurator::~LogConfigurator()
[143]292 {}
293
[231]294 void LogConfigurator::configureLoggerWithFile(const char* /*configFilename*/)
295 {}
296
[143]297} // namespace pacpus
298
299#endif // PACPUS_USE_LOG
[231]300
Note: See TracBrowser for help on using the repository browser.