TrinityCore
AppenderConsole.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "AppenderConsole.h"
19#include "LogMessage.h"
20#include "SmartEnum.h"
21#include "StringFormat.h"
22#include "StringConvert.h"
23#include "Util.h"
24
25#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
26 #include <Windows.h>
27#endif
28
29AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags, std::vector<std::string_view> const& args)
30 : Appender(id, name, level, flags), _colored(false)
31{
32 for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
34
35 if (3 < args.size())
36 InitColors(name, args[3]);
37}
38
39void AppenderConsole::InitColors(std::string const& name, std::string_view str)
40{
41 if (str.empty())
42 {
43 _colored = false;
44 return;
45 }
46
47 std::vector<std::string_view> colorStrs = Trinity::Tokenize(str, ' ', false);
48 if (colorStrs.size() != NUM_ENABLED_LOG_LEVELS)
49 {
50 throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid color data '{}' for console appender {} (expected {} entries, got {})",
51 str, name, NUM_ENABLED_LOG_LEVELS, colorStrs.size()));
52 }
53
54 for (uint8 i = 0; i < NUM_ENABLED_LOG_LEVELS; ++i)
55 {
56 if (Optional<uint8> color = Trinity::StringTo<uint8>(colorStrs[i]); color && EnumUtils::IsValid<ColorTypes>(*color))
57 _colors[i] = static_cast<ColorTypes>(*color);
58 else
59 {
60 throw InvalidAppenderArgsException(Trinity::StringFormat("Log::CreateAppenderFromConfig: Invalid color '{}' for log level {} on console appender {}",
61 colorStrs[i], EnumUtils::ToTitle(static_cast<LogLevel>(i)), name));
62 }
63 }
64
65 _colored = true;
66}
67
68void AppenderConsole::SetColor(bool stdout_stream, ColorTypes color)
69{
70#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
71 static WORD WinColorFG[NUM_COLOR_TYPES] =
72 {
73 0, // BLACK
74 FOREGROUND_RED, // RED
75 FOREGROUND_GREEN, // GREEN
76 FOREGROUND_RED | FOREGROUND_GREEN, // BROWN
77 FOREGROUND_BLUE, // BLUE
78 FOREGROUND_RED | FOREGROUND_BLUE, // MAGENTA
79 FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN
80 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // WHITE
81 // YELLOW
82 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
83 // RED_BOLD
84 FOREGROUND_RED | FOREGROUND_INTENSITY,
85 // GREEN_BOLD
86 FOREGROUND_GREEN | FOREGROUND_INTENSITY,
87 FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD
88 // MAGENTA_BOLD
89 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
90 // CYAN_BOLD
91 FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
92 // WHITE_BOLD
93 FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
94 };
95
96 HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
97 SetConsoleTextAttribute(hConsole, WinColorFG[color]);
98#else
99 enum ANSITextAttr
100 {
101 TA_NORMAL = 0,
102 TA_BOLD = 1,
103 TA_BLINK = 5,
104 TA_REVERSE = 7
105 };
106
107 enum ANSIFgTextAttr
108 {
109 FG_BLACK = 30,
110 FG_RED,
111 FG_GREEN,
112 FG_BROWN,
113 FG_BLUE,
114 FG_MAGENTA,
115 FG_CYAN,
116 FG_WHITE,
117 FG_YELLOW
118 };
119
120 enum ANSIBgTextAttr
121 {
122 BG_BLACK = 40,
123 BG_RED,
124 BG_GREEN,
125 BG_BROWN,
126 BG_BLUE,
127 BG_MAGENTA,
128 BG_CYAN,
129 BG_WHITE
130 };
131
132 static uint8 UnixColorFG[NUM_COLOR_TYPES] =
133 {
134 FG_BLACK, // BLACK
135 FG_RED, // RED
136 FG_GREEN, // GREEN
137 FG_BROWN, // BROWN
138 FG_BLUE, // BLUE
139 FG_MAGENTA, // MAGENTA
140 FG_CYAN, // CYAN
141 FG_WHITE, // WHITE
142 FG_YELLOW, // YELLOW
143 FG_RED, // LRED
144 FG_GREEN, // LGREEN
145 FG_BLUE, // LBLUE
146 FG_MAGENTA, // LMAGENTA
147 FG_CYAN, // LCYAN
148 FG_WHITE // LWHITE
149 };
150
151 fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < NUM_COLOR_TYPES ? ";1" : ""));
152 #endif
153}
154
155void AppenderConsole::ResetColor(bool stdout_stream)
156{
157 #if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
158 HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
159 SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
160 #else
161 fprintf((stdout_stream ? stdout : stderr), "\x1b[0m");
162 #endif
163}
164
165void AppenderConsole::Print(std::string const& str, bool error)
166{
167#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
168 WriteWinConsole(str + "\n", error);
169#else
170 utf8printf(error ? stderr : stdout, "%s\n", str.c_str());
171#endif
172}
173
175{
176 bool stdout_stream = !(message->level == LOG_LEVEL_ERROR || message->level == LOG_LEVEL_FATAL);
177
178 if (_colored)
179 {
180 uint8 index;
181 switch (message->level)
182 {
183 case LOG_LEVEL_TRACE:
184 index = 5;
185 break;
186 case LOG_LEVEL_DEBUG:
187 index = 4;
188 break;
189 case LOG_LEVEL_INFO:
190 index = 3;
191 break;
192 case LOG_LEVEL_WARN:
193 index = 2;
194 break;
195 case LOG_LEVEL_FATAL:
196 index = 0;
197 break;
198 case LOG_LEVEL_ERROR:
199 [[fallthrough]];
200 default:
201 index = 1;
202 break;
203 }
204
205 SetColor(stdout_stream, _colors[index]);
206 Print(message->prefix + message->text, !stdout_stream);
207 ResetColor(stdout_stream);
208 }
209 else
210 Print(message->prefix + message->text, !stdout_stream);
211}
ColorTypes
@ NUM_COLOR_TYPES
@ YELLOW
uint8_t uint8
Definition: Define.h:144
uint16 flags
Definition: DisableMgr.cpp:49
AppenderFlags
Definition: LogCommon.h:50
LogLevel
Definition: LogCommon.h:25
@ NUM_ENABLED_LOG_LEVELS
Definition: LogCommon.h:34
@ LOG_LEVEL_DEBUG
Definition: LogCommon.h:28
@ LOG_LEVEL_ERROR
Definition: LogCommon.h:31
@ LOG_LEVEL_FATAL
Definition: LogCommon.h:32
@ LOG_LEVEL_TRACE
Definition: LogCommon.h:27
@ LOG_LEVEL_WARN
Definition: LogCommon.h:30
@ LOG_LEVEL_INFO
Definition: LogCommon.h:29
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
bool WriteWinConsole(std::string_view str, bool error)
Definition: Util.cpp:826
void utf8printf(FILE *out, const char *str,...)
Definition: Util.cpp:766
void InitColors(std::string const &name, std::string_view init_str)
void ResetColor(bool stdout_stream)
void Print(std::string const &str, bool error)
void SetColor(bool stdout_stream, ColorTypes color)
void _write(LogMessage const *message) override
AppenderConsole(uint8 _id, std::string const &name, LogLevel level, AppenderFlags flags, std::vector< std::string_view > const &args)
ColorTypes _colors[NUM_ENABLED_LOG_LEVELS]
std::string name
Definition: Appender.h:50
static char const * ToTitle(Enum value)
Definition: SmartEnum.h:123
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:56
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
LogLevel const level
Definition: LogMessage.h:37
std::string const text
Definition: LogMessage.h:39
std::string prefix
Definition: LogMessage.h:40