OpenTTD Source: src/debug.cpp Source File

OpenTTD Source 14.0-beta3

debug.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10 #include "stdafx.h"
11 #include "console_func.h"
12 #include "debug.h"
13 #include "string_func.h"
14 #include "fileio_func.h"
15 #include "settings_type.h"
16 #include <mutex>
17
18 #if defined(_WIN32)
19 #include "os/windows/win32.h"
20 #endif
21
22 #include "3rdparty/fmt/chrono.h"
23
24 #include "network/network_admin.h"
25
26 #include "safeguards.h"
27
29 struct QueuedDebugItem {
30 std::string level;
31 std::string message;
32 };
33 std::atomic<bool> _debug_remote_console;
34 std::mutex _debug_remote_console_mutex;
35 std::vector<QueuedDebugItem> _debug_remote_console_queue;
36 std::vector<QueuedDebugItem> _debug_remote_console_queue_spare;
37
38 int _debug_driver_level;
39 int _debug_grf_level;
40 int _debug_map_level;
41 int _debug_misc_level;
42 int _debug_net_level;
43 int _debug_sprite_level;
44 int _debug_oldloader_level;
45 int _debug_npf_level;
46 int _debug_yapf_level;
47 int _debug_fontcache_level;
48 int _debug_script_level;
49 int _debug_sl_level;
50 int _debug_gamelog_level;
51 int _debug_desync_level;
52 int _debug_console_level;
53 #ifdef RANDOM_DEBUG
54 int _debug_random_level;
55 #endif
56
57 struct DebugLevel {
58 const char *name;
59 int *level;
60 };
61
62 #define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
63 static const DebugLevel debug_level[] = {
64 DEBUG_LEVEL(driver),
65 DEBUG_LEVEL(grf),
66 DEBUG_LEVEL(map),
67 DEBUG_LEVEL(misc),
68 DEBUG_LEVEL(net),
69 DEBUG_LEVEL(sprite),
70 DEBUG_LEVEL(oldloader),
71 DEBUG_LEVEL(npf),
72 DEBUG_LEVEL(yapf),
73 DEBUG_LEVEL(fontcache),
74 DEBUG_LEVEL(script),
75 DEBUG_LEVEL(sl),
76 DEBUG_LEVEL(gamelog),
77 DEBUG_LEVEL(desync),
78 DEBUG_LEVEL(console),
79 #ifdef RANDOM_DEBUG
80 DEBUG_LEVEL(random),
81 #endif
82 };
83 #undef DEBUG_LEVEL
84
89 void DumpDebugFacilityNames(std::back_insert_iterator<std::string> &output_iterator)
90 {
91 bool written = false;
92 for (const DebugLevel *i = debug_level; i != endof(debug_level); ++i) {
93 if (!written) {
94 fmt::format_to(output_iterator, "List of debug facility names:\n");
95 } else {
96 fmt::format_to(output_iterator, ", ");
97 }
98 fmt::format_to(output_iterator, "{}", i->name);
99 written = true;
100 }
101 if (written) {
102 fmt::format_to(output_iterator, "\n\n");
103 }
104 }
105
111 void DebugPrint(const char *category, int level, const std::string &message)
112 {
113 if (strcmp(category, "desync") == 0) {
114 static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
115 if (f == nullptr) return;
116
117 fmt::print(f, "{}{}\n", GetLogPrefix(true), message);
118 fflush(f);
119 #ifdef RANDOM_DEBUG
120 } else if (strcmp(category, "random") == 0) {
121 static FILE *f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR);
122 if (f == nullptr) return;
123
124 fmt::print(f, "{}\n", message);
125 fflush(f);
126 #endif
127 } else {
128 fmt::print(stderr, "{}dbg: [{}:{}] {}\n", GetLogPrefix(true), category, level, message);
129
130 if (_debug_remote_console.load()) {
131 /* Only add to the queue when there is at least one consumer of the data. */
132 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
133 _debug_remote_console_queue.push_back({ category, message });
134 }
135 }
136 }
137
145 void SetDebugString(const char *s, void (*error_func)(const std::string &))
146 {
147 int v;
148 char *end;
149 const char *t;
150
151 /* Store planned changes into map during parse */
152 std::map<const char *, int> new_levels;
153
154 /* Global debugging level? */
155 if (*s >= '0' && *s <= '9') {
156 const DebugLevel *i;
157
158 v = std::strtoul(s, &end, 0);
159 s = end;
160
161 for (i = debug_level; i != endof(debug_level); ++i) {
162 new_levels[i->name] = v;
163 }
164 }
165
166 /* Individual levels */
167 for (;;) {
168 /* skip delimiters */
169 while (*s == ' ' || *s == ',' || *s == '\t') s++;
170 if (*s == '\0') break;
171
172 t = s;
173 while (*s >= 'a' && *s <= 'z') s++;
174
175 /* check debugging levels */
176 const DebugLevel *found = nullptr;
177 for (const DebugLevel *i = debug_level; i != endof(debug_level); ++i) {
178 if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) {
179 found = i;
180 break;
181 }
182 }
183
184 if (*s == '=') s++;
185 v = std::strtoul(s, &end, 0);
186 s = end;
187 if (found != nullptr) {
188 new_levels[found->name] = v;
189 } else {
190 std::string error_string = fmt::format("Unknown debug level '{}'", std::string(t, s - t));
191 error_func(error_string);
192 return;
193 }
194 }
195
196 /* Apply the changes after parse is successful */
197 for (const DebugLevel *i = debug_level; i != endof(debug_level); ++i) {
198 const auto &nl = new_levels.find(i->name);
199 if (nl != new_levels.end()) {
200 *i->level = nl->second;
201 }
202 }
203 }
204
210 std::string GetDebugString()
211 {
212 std::string result;
213 for (const DebugLevel *i = debug_level; i != endof(debug_level); ++i) {
214 if (!result.empty()) result += ", ";
215 fmt::format_to(std::back_inserter(result), "{}={}", i->name, *i->level);
216 }
217 return result;
218 }
219
228 std::string GetLogPrefix(bool force)
229 {
230 std::string log_prefix;
231 if (force || _settings_client.gui.show_date_in_logs) {
232 log_prefix = fmt::format("[{:%Y-%m-%d %H:%M:%S}] ", fmt::localtime(time(nullptr)));
233 }
234 return log_prefix;
235 }
236
244 void DebugSendRemoteMessages()
245 {
246 if (!_debug_remote_console.load()) return;
247
248 {
249 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
250 std::swap(_debug_remote_console_queue, _debug_remote_console_queue_spare);
251 }
252
253 for (auto &item : _debug_remote_console_queue_spare) {
254 NetworkAdminConsole(item.level, item.message);
255 if (_settings_client.gui.developer >= 2) IConsolePrint(CC_DEBUG, "dbg: [{}] {}", item.level, item.message);
256 }
257
258 _debug_remote_console_queue_spare.clear();
259 }
260
268 void DebugReconsiderSendRemoteMessages()
269 {
270 bool enable = _settings_client.gui.developer >= 2;
271
272 for (ServerNetworkAdminSocketHandler *as : ServerNetworkAdminSocketHandler::IterateActive()) {
273 if (as->update_frequency[ADMIN_UPDATE_CONSOLE] & ADMIN_FREQUENCY_AUTOMATIC) {
274 enable = true;
275 break;
276 }
277 }
278
279 _debug_remote_console.store(enable);
280 }
_debug_remote_console
std::atomic< bool > _debug_remote_console
Whether we need to send data to either NetworkAdminConsole or IConsolePrint.
Definition: debug.cpp:33
win32.h
lock
std::mutex lock
synchronization for playback status fields
Definition: win32_m.cpp:35
ADMIN_UPDATE_CONSOLE
@ ADMIN_UPDATE_CONSOLE
The admin would like to have console messages.
Definition: tcp_admin.h:83
DumpDebugFacilityNames
void DumpDebugFacilityNames(std::back_insert_iterator< std::string > &output_iterator)
Dump the available debug facility names in the help text.
Definition: debug.cpp:89
fileio_func.h
ServerNetworkAdminSocketHandler::IterateActive
static Pool::IterateWrapperFiltered< ServerNetworkAdminSocketHandler, ServerNetworkAdminSocketHandlerFilter > IterateActive(size_t from=0)
Returns an iterable ensemble of all active admin sockets.
Definition: network_admin.h:96
AUTOSAVE_DIR
@ AUTOSAVE_DIR
Subdirectory of save for autosaves.
Definition: fileio_type.h:111
_settings_client
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:54
SetDebugString
void SetDebugString(const char *s, void(*error_func)(const std::string &))
Set debugging levels by parsing the text in s.
Definition: debug.cpp:145
NetworkAdminConsole
void NetworkAdminConsole(const std::string_view origin, const std::string_view string)
Send console to the admin network (if they did opt in for the respective update).
Definition: network_admin.cpp:935
QueuedDebugItem::level
std::string level
The used debug level.
Definition: debug.cpp:30
GUISettings::show_date_in_logs
bool show_date_in_logs
whether to show dates in console logs
Definition: settings_type.h:215
QueuedDebugItem::message
std::string message
The actual formatted message.
Definition: debug.cpp:31
GetDebugString
std::string GetDebugString()
Print out the current debug-level.
Definition: debug.cpp:210
_debug_remote_console_queue_spare
std::vector< QueuedDebugItem > _debug_remote_console_queue_spare
Spare queue to swap with _debug_remote_console_queue.
Definition: debug.cpp:36
FioFOpenFile
FILE * FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition: fileio.cpp:263
safeguards.h
CC_DEBUG
static const TextColour CC_DEBUG
Colour for debug output.
Definition: console_type.h:28
settings_type.h
stdafx.h
GetLogPrefix
std::string GetLogPrefix(bool force)
Get the prefix for logs.
Definition: debug.cpp:228
string_func.h
_debug_remote_console_queue
std::vector< QueuedDebugItem > _debug_remote_console_queue
Queue for debug messages to be passed to NetworkAdminConsole or IConsolePrint.
Definition: debug.cpp:35
endof
#define endof(x)
Get the end element of an fixed size array.
Definition: stdafx.h:308
ServerNetworkAdminSocketHandler
Class for handling the server side of the game connection.
Definition: network_admin.h:25
ADMIN_FREQUENCY_AUTOMATIC
@ ADMIN_FREQUENCY_AUTOMATIC
The admin gets information about this when it changes.
Definition: tcp_admin.h:98
DebugSendRemoteMessages
void DebugSendRemoteMessages()
Send the queued Debug messages to either NetworkAdminConsole or IConsolePrint from the GameLoop threa...
Definition: debug.cpp:244
DebugLevel
Definition: debug.cpp:57
GUISettings::developer
uint8_t developer
print non-fatal warnings in console (>= 1), copy debug output to console (== 2)
Definition: settings_type.h:214
_debug_remote_console_mutex
std::mutex _debug_remote_console_mutex
Mutex to guard the queue of debug messages for either NetworkAdminConsole or IConsolePrint.
Definition: debug.cpp:34
network_admin.h
console_func.h
DebugPrint
void DebugPrint(const char *category, int level, const std::string &message)
Internal function for outputting the debug line.
Definition: debug.cpp:111
QueuedDebugItem
Element in the queue of debug messages that have to be passed to either NetworkAdminConsole or IConso...
Definition: debug.cpp:29
DebugReconsiderSendRemoteMessages
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition: debug.cpp:268
ClientSettings::gui
GUISettings gui
settings related to the GUI
Definition: settings_type.h:636
debug.h
IConsolePrint
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition: console.cpp:91