source: pacpusframework/trunk/src/PacpusLib/ColorSeverityFormatter.hpp@ 243

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

Minor fixes for TERM

File size: 13.3 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/// @file
7/// @author Marek Kurdej <firstname.surname@utc.fr>
8/// @date 2013-11-28
9/// @version $Id$
10/// @copyright Copyright (c) UTC/CNRS Heudiasyc 2006 - 2013. All rights reserved.
11/// @brief Color logger output depending on severity level.
12///
13/// Detailed description.
14
15#ifndef COLORSEVERITYFORMATTER_HPP
16#define COLORSEVERITYFORMATTER_HPP
17
18#if defined(PACPUS_LOG_COLORED_OUTPUT)
19
20#include <boost/log/attributes/attribute_name.hpp>
21#include <boost/log/attributes/fallback_policy.hpp>
22#include <boost/log/attributes/value_visitation.hpp>
23#include <boost/log/expressions.hpp>
24#include <boost/log/utility/functional/bind.hpp>
25#include <cstdlib>
26#include <sstream>
27
28// could use Boost.Predef with Boost >= 1.55
29#if defined(WIN32) || defined(_WINDOWS)
30# define PACPUS_OS_WINDOWS 1
31#elif defined(__unix) || defined(__unix__)
32# define PACPUS_OS_UNIX 1
33# if defined(__linux) || defined(__linux__)
34# define PACPUS_OS_LINUX 1
35# endif
36#elif defined(__APPLE__) || defined(__MACH__) || defined(Macintosh) || defined(macintosh)
37# define PACPUS_OS_MACOS 1
38#else
39// unknown system
40#endif
41
42#if defined(PACPUS_OS_WINDOWS)
43# include <Windows.h>
44#endif
45
46namespace pacpus
47{
48
49enum Color {
50 COLOR_DEFAULT,
51 COLOR_BLACK,
52 COLOR_RED,
53 COLOR_GREEN,
54 COLOR_YELLOW,
55 COLOR_BLUE,
56 COLOR_MAGENTA,
57 COLOR_CYAN,
58 COLOR_WHITE
59};
60
61Color getColor(SeverityLevel const& sev)
62{
63 if (sev >= error) {
64 return COLOR_RED;
65 } else if (sev >= warning) {
66 return COLOR_YELLOW;
67 } else if (sev >= info) {
68 return COLOR_WHITE; //COLOR_GREEN;
69 }
70 return COLOR_DEFAULT;
71}
72
73#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
74
75// Returns the character attribute for the given color.
76WORD getColorAttribute(Color color)
77{
78 switch (color) {
79 case COLOR_BLACK: return 0;
80 case COLOR_RED: return FOREGROUND_RED;
81 case COLOR_GREEN: return FOREGROUND_GREEN;
82 case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
83 case COLOR_BLUE: return FOREGROUND_BLUE;
84 case COLOR_MAGENTA: return FOREGROUND_RED | FOREGROUND_BLUE;
85 case COLOR_CYAN: return FOREGROUND_GREEN | FOREGROUND_BLUE;
86 case COLOR_WHITE: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
87 default: return 0;
88 }
89}
90
91#else
92
93/// @returns the ANSI color code for the given color. COLOR_DEFAULT is
94/// an invalid input.
95std::string getAnsiColorCode(Color color)
96{
97 const char* kEscapeSequence = "\033[";
98// const char* kBackground = "";
99 const char* kFontRegular = "0;";
100// const char* kFontBold = "1;";
101// const char* kFontWeak = "2;";
102// const char* kFontStrong = "3;";
103// const char* kFontUnderline = "4;";
104
105 std::stringstream ss;
106 ss << kEscapeSequence << kFontRegular;
107
108 switch (color) {
109 case COLOR_BLACK: ss << "30"; break;
110 case COLOR_RED: ss << "31"; break;
111 case COLOR_GREEN: ss << "32"; break;
112 case COLOR_YELLOW: ss << "33"; break;
113 case COLOR_BLUE: ss << "34"; break;
114 case COLOR_MAGENTA: ss << "35"; break;
115 case COLOR_CYAN: ss << "36"; break;
116 case COLOR_WHITE: ss << "37"; break;
117 default: return "";
118 };
119
120 const char* kPostfix = "m";
121 ss << kPostfix;
122
123 return ss.str();
124}
125
126std::string getAnsiColorCodeRestoreDefault()
127{
128 return "\033[0m";
129}
130
131#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
132
133bool shouldUseColor(bool stdoutIsTty)
134{
135#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
136 return true;
137#else
138 // On non-Windows platforms, we rely on the TERM variable.
139 const char* const term = std::getenv("TERM");
140 const bool termSupportsColor = (term == "xterm")
141 || (term, "xterm-color")
142 || (term, "xterm-256color")
143 || (term, "screen")
144 || (term, "linux")
145 || (term, "cygwin");
146 return stdoutIsTty && termSupportsColor;
147#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
148}
149
150template < typename CharT >
151struct ColorFormatter
152{
153 ColorFormatter()
154#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
155 : mStreamHandle(GetStdHandle(STD_OUTPUT_HANDLE))
156#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
157 {
158 mShouldUseColor = shouldUseColor(/*stdoutIsTty*/ true);
159 }
160
161 void operator()(boost::log::basic_formatting_ostream<CharT>& strm, SeverityLevel const& sev)
162 {
163 if (!mShouldUseColor) {
164 return;
165 }
166#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
167 // Gets the current text color.
168 CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
169 GetConsoleScreenBufferInfo(mStreamHandle, &bufferInfo);
170 mSavedConsoleBufferInfo = bufferInfo.wAttributes;
171
172 // We need to flush the stream buffers into the console before each
173 // SetConsoleTextAttribute call lest it affect the text that is already
174 // printed but has not yet reached the console.
175 fflush(stdout);
176 SetConsoleTextAttribute(mStreamHandle, getColorAttribute(getColor(sev)) | FOREGROUND_INTENSITY);
177#else
178 strm << getAnsiColorCode(getColor(sev)).c_str();
179#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
180 }
181
182 bool mShouldUseColor;
183#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
184 const HANDLE mStreamHandle;
185 WORD mSavedConsoleBufferInfo;
186#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
187};
188
189template < typename CharT >
190struct DefaultFormatter
191{
192 DefaultFormatter()
193#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
194 //DefaultFormatter(WORD savedConsoleBufferInfo)
195 : mStreamHandle(GetStdHandle(STD_OUTPUT_HANDLE))
196 //, mSavedConsoleBufferInfo(savedConsoleBufferInfo)
197 , mSavedConsoleBufferInfo(getColorAttribute(COLOR_WHITE) | FOREGROUND_INTENSITY) // FIXME: restore old value, not just reset
198#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
199 {
200 mShouldUseColor = shouldUseColor(/*stdoutIsTty*/ true);
201 }
202
203 void operator()(boost::log::basic_formatting_ostream<CharT>& strm, SeverityLevel const& /*sev*/)
204 {
205 if (!mShouldUseColor) {
206 return;
207 }
208#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
209 fflush(stdout);
210 // Restores the text color.
211 SetConsoleTextAttribute(mStreamHandle, mSavedConsoleBufferInfo);
212#else
213 strm << getAnsiColorCodeRestoreDefault().c_str();
214#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
215 }
216
217 bool mShouldUseColor;
218#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
219 const HANDLE mStreamHandle;
220 WORD mSavedConsoleBufferInfo;
221#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
222};
223
224template< typename T, typename FallbackPolicyT, typename CharT >
225class FormatSeverityWithColorsTerminal
226{
227public:
228 //! Internal typedef for type categorization
229 typedef void _is_boost_log_terminal;
230
231 //! Attribute value type
232 typedef T value_type;
233 //! Fallback policy
234 typedef FallbackPolicyT fallback_policy;
235 //! Character type
236 typedef CharT char_type;
237 //! String type
238 typedef std::basic_string< char_type > string_type;
239 //! Formatting stream type
240 typedef boost::log::basic_formatting_ostream< char_type > stream_type;
241
242 //! Formatter function
243 typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
244
245 //! Function result type
246 typedef string_type result_type;
247
248 typedef boost::log::attribute_name attribute_name;
249
250private:
251 //! Attribute value visitor invoker
252 typedef boost::log::value_visitor_invoker< value_type, fallback_policy > visitor_invoker_type;
253
254private:
255 //! Attribute name
256 attribute_name m_name;
257 //! Formattr function
258 formatter_function_type m_formatter;
259 //! Attribute value visitor invoker
260 visitor_invoker_type m_visitor_invoker;
261
262public:
263 //! Initializing constructor
264 FormatSeverityWithColorsTerminal(attribute_name const& name, fallback_policy const& fallback, bool restoreDefault)
265 : m_name(name)
266 //, m_formatter(formatter_generator::parse(format))
267 , m_visitor_invoker(fallback)
268 {
269 if (restoreDefault) {
270//#if defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
271// m_formatter = formatter_function_type(DefaultFormatter<char_type>());
272//#else // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
273 m_formatter = formatter_function_type(DefaultFormatter<char_type>());
274//#endif // defined(PACPUS_OS_WINDOWS) && !defined(PACPUS_OS_WINDOWS_MOBILE)
275 } else {
276 m_formatter = formatter_function_type(ColorFormatter<char_type>());
277 }
278 }
279
280 //! Copy constructor
281 FormatSeverityWithColorsTerminal(FormatSeverityWithColorsTerminal const& that) :
282 m_name(that.m_name), m_formatter(that.m_formatter), m_visitor_invoker(that.m_visitor_invoker)
283 {
284 }
285
286 //! Invokation operator
287 template< typename ContextT >
288 result_type operator() (ContextT const& ctx)
289 {
290 using namespace boost;
291 using boost::log::binder1st;
292 string_type str;
293 stream_type strm(str);
294 m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type&, stream_type& >(m_formatter, strm));
295 strm.flush();
296 return boost::move(str);
297 }
298
299 //! Invokation operator
300 template< typename ContextT >
301 result_type operator() (ContextT const& ctx) const
302 {
303 using namespace boost;
304 using boost::log::binder1st;
305 string_type str;
306 stream_type strm(str);
307 m_visitor_invoker(m_name, fusion::at_c< 0 >(phoenix::env(ctx).args()), binder1st< formatter_function_type const&, stream_type& >(m_formatter, strm));
308 strm.flush();
309 return boost::move(str);
310 }
311
312 BOOST_DELETED_FUNCTION(FormatSeverityWithColorsTerminal())
313};
314
315template< typename T, typename FallbackPolicyT, typename CharT = char, template< typename > class ActorT = boost::phoenix::actor >
316class FormatSeverityWithColorsActor
317 : public ActorT< FormatSeverityWithColorsTerminal< T, FallbackPolicyT, CharT > >
318{
319public:
320 //! Attribute value type
321 typedef T value_type;
322 //! Character type
323 typedef CharT char_type;
324 //! Fallback policy
325 typedef FallbackPolicyT fallback_policy;
326 //! Base terminal type
327 typedef FormatSeverityWithColorsTerminal< value_type, fallback_policy, char_type > terminal_type;
328 //! Formatter function
329 typedef typename terminal_type::formatter_function_type formatter_function_type;
330
331 //! Base actor type
332 typedef ActorT< terminal_type > base_type;
333
334public:
335 //! Initializing constructor
336 explicit FormatSeverityWithColorsActor(base_type const& act)
337 : base_type(act)
338 {
339 }
340};
341
342template< typename AttributeValueT >
343/*BOOST_FORCEINLINE*/ FormatSeverityWithColorsActor< AttributeValueT, boost::log::fallback_to_none >
344formatSeverityWithColors(boost::log::attribute_name const& name, bool restoreDefault = false)
345{
346 using boost::log::fallback_to_none;
347 typedef FormatSeverityWithColorsActor< AttributeValueT, fallback_to_none > actor_type;
348 typedef typename actor_type::terminal_type terminal_type;
349 typename actor_type::base_type act = {{ terminal_type(name, fallback_to_none(), restoreDefault) }};
350 return actor_type(act);
351}
352
353template< typename DescriptorT, template< typename > class ActorT, typename CharT >
354/*BOOST_FORCEINLINE*/ FormatSeverityWithColorsActor< typename DescriptorT::value_type, boost::log::fallback_to_none, CharT, ActorT >
355formatSeverityWithColors(boost::log::expressions::attribute_keyword< DescriptorT, ActorT > const& keyword, bool restoreDefault = false)
356{
357 using boost::log::fallback_to_none;
358 typedef FormatSeverityWithColorsActor< typename DescriptorT::value_type, fallback_to_none, CharT, ActorT > actor_type;
359 typedef typename actor_type::terminal_type terminal_type;
360 typename actor_type::base_type act = {{ terminal_type(keyword.get_name(), fallback_to_none(), restoreDefault) }};
361 return actor_type(act);
362}
363
364template< typename T, typename FallbackPolicyT, typename TagT, template< typename > class ActorT>
365/*BOOST_FORCEINLINE*/ FormatSeverityWithColorsActor< T, FallbackPolicyT, char, ActorT >
366formatSeverityWithColors(boost::log::expressions::attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& placeholder, bool restoreDefault = false)
367{
368 typedef FormatSeverityWithColorsActor< T, FallbackPolicyT, char, ActorT > actor_type;
369 typedef typename actor_type::terminal_type terminal_type;
370 typename actor_type::base_type act = {{ terminal_type(placeholder.get_name(), placeholder.get_fallback_policy(), restoreDefault) }};
371 return actor_type(act);
372}
373
374} // namespace pacpus
375
376#endif // defined(PACPUS_LOG_COLORED_OUTPUT)
377
378#endif // COLORSEVERITYFORMATTER_HPP
Note: See TracBrowser for help on using the repository browser.