ifm3d
log_writer_console_colored.h
1 // -*- c++ -*-
2 /*
3  * Copyright 2023-present ifm electronic, gmbh
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef IFM3D_COMMON_LOGGING_LOG_WRITER_CONSOLE_COLORED_H
8 #define IFM3D_COMMON_LOGGING_LOG_WRITER_CONSOLE_COLORED_H
9 
10 #include <ifm3d/common/logging/log_level.h>
11 #include <ifm3d/common/logging/log_writer_console.h>
12 #ifdef _WIN32
13 # ifndef WIN32_LEAN_AND_MEAN
14 # define WIN32_LEAN_AND_MEAN
15 # endif
16 # define NOMINMAX
17 # include <windows.h>
18 # undef GetMessage
19 #endif
20 
21 namespace ifm3d
22 {
23  template <class FORMATTER,
24  typename std::enable_if_t<std::is_same_v<
25  decltype(FORMATTER::Format(
26  ifm3d::LogEntry("", ifm3d::LogLevel::Info, "", "", 1))),
27  std::string>>* = nullptr>
28  class LogWriterConsoleColored : public LogWriterConsole<FORMATTER>
29  {
30  public:
31  LogWriterConsoleColored(Output out = Output::StdErr)
33  {
34 #ifdef _WIN32
35  // NOLINTNEXTLINE(*-prefer-member-initializer)
36  _colored_output_available =
37  this->_is_a_tty && EnableVirtualTerminalProcessing();
38 #else
39  // NOLINTNEXTLINE(*-prefer-member-initializer)
40  _colored_output_available = this->_is_a_tty;
41 #endif
42  }
43 
44  void
45  Write(const LogEntry& entry) override
46  {
47  if (this->_colored_output_available)
48  {
49  const auto str = FORMATTER::Format(entry);
50  const std::lock_guard<std::mutex> lock(this->_mutex);
51  this->set_color(entry.GetLogLevel());
52  this->_out << str;
53  this->reset_color();
54  this->_out << std::endl;
55  }
56  else
57  {
59  }
60  }
61 
62  protected:
63  bool _colored_output_available = false;
64 #ifdef _WIN32
65  bool
66  EnableVirtualTerminalProcessing()
67  {
68  HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
69  if (hOut == INVALID_HANDLE_VALUE)
70  {
71  return false;
72  }
73 
74  DWORD dwMode = 0;
75  if (!GetConsoleMode(hOut, &dwMode))
76  {
77  return false;
78  }
79 
80  dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
81  if (!SetConsoleMode(hOut, dwMode))
82  {
83  return false;
84  }
85  return true;
86  }
87 #endif
88 
89  void
90  set_color(LogLevel log_level)
91  {
92  switch (log_level)
93  {
94  case LogLevel::Critical:
95  this->_out << "\x1B[97m\x1B[41m"; // white on red background
96  break;
97 
98  case LogLevel::Error:
99  this->_out << "\x1B[91m"; // red
100  break;
101 
102  case LogLevel::Warning:
103  this->_out << "\x1B[93m"; // yellow
104  break;
105 
106  case LogLevel::Debug:
107  case LogLevel::Verbose:
108  this->_out << "\x1B[96m"; // cyan
109  break;
110  default:
111  break;
112  }
113  }
114 
115  void
116  reset_color()
117  {
118  this->_out << "\x1B[0m\x1B[0K";
119  }
120  };
121 }
122 #endif // IFM3D_COMMON_LOGGING_LOG_WRITER_CONSOLE_COLORED_H
ifm3d::LogEntry
Definition: log_entry.h:19
ifm3d::LogWriterConsole
Definition: log_writer_console.h:40
ifm3d::LogWriterConsoleColored
Definition: log_writer_console_colored.h:28