OpenTTD Source 20241224-master-gf74b0cf984
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
25
26#include "safeguards.h"
27
30 std::string level;
31 std::string message;
32};
33std::atomic<bool> _debug_remote_console;
35std::vector<QueuedDebugItem> _debug_remote_console_queue;
36std::vector<QueuedDebugItem> _debug_remote_console_queue_spare;
37
38int _debug_driver_level;
39int _debug_grf_level;
40int _debug_map_level;
41int _debug_misc_level;
42int _debug_net_level;
43int _debug_sprite_level;
44int _debug_oldloader_level;
45int _debug_yapf_level;
46int _debug_fontcache_level;
47int _debug_script_level;
48int _debug_sl_level;
49int _debug_gamelog_level;
50int _debug_desync_level;
51int _debug_console_level;
52#ifdef RANDOM_DEBUG
53int _debug_random_level;
54#endif
55
56struct DebugLevel {
57 const char *name;
58 int *level;
59};
60
61#define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
62static const DebugLevel _debug_levels[] = {
63 DEBUG_LEVEL(driver),
64 DEBUG_LEVEL(grf),
65 DEBUG_LEVEL(map),
66 DEBUG_LEVEL(misc),
67 DEBUG_LEVEL(net),
68 DEBUG_LEVEL(sprite),
69 DEBUG_LEVEL(oldloader),
70 DEBUG_LEVEL(yapf),
71 DEBUG_LEVEL(fontcache),
72 DEBUG_LEVEL(script),
73 DEBUG_LEVEL(sl),
74 DEBUG_LEVEL(gamelog),
75 DEBUG_LEVEL(desync),
76 DEBUG_LEVEL(console),
77#ifdef RANDOM_DEBUG
78 DEBUG_LEVEL(random),
79#endif
80};
81#undef DEBUG_LEVEL
82
87void DumpDebugFacilityNames(std::back_insert_iterator<std::string> &output_iterator)
88{
89 bool written = false;
90 for (const auto &debug_level : _debug_levels) {
91 if (!written) {
92 fmt::format_to(output_iterator, "List of debug facility names:\n");
93 } else {
94 fmt::format_to(output_iterator, ", ");
95 }
96 fmt::format_to(output_iterator, "{}", debug_level.name);
97 written = true;
98 }
99 if (written) {
100 fmt::format_to(output_iterator, "\n\n");
101 }
102}
103
109void DebugPrint(const char *category, int level, const std::string &message)
110{
111 if (strcmp(category, "desync") == 0 && level != 0) {
112 static auto f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
113 if (!f.has_value()) return;
114
115 fmt::print(*f, "{}{}\n", GetLogPrefix(true), message);
116 fflush(*f);
117#ifdef RANDOM_DEBUG
118 } else if (strcmp(category, "random") == 0) {
119 static auto f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR);
120 if (!f.has_value()) return;
121
122 fmt::print(*f, "{}\n", message);
123 fflush(*f);
124#endif
125 } else {
126 fmt::print(stderr, "{}dbg: [{}:{}] {}\n", GetLogPrefix(true), category, level, message);
127
128 if (_debug_remote_console.load()) {
129 /* Only add to the queue when there is at least one consumer of the data. */
130 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
131 _debug_remote_console_queue.push_back({ category, message });
132 }
133 }
134}
135
143void SetDebugString(const char *s, void (*error_func)(const std::string &))
144{
145 int v;
146 char *end;
147 const char *t;
148
149 /* Store planned changes into map during parse */
150 std::map<const char *, int> new_levels;
151
152 /* Global debugging level? */
153 if (*s >= '0' && *s <= '9') {
154 v = std::strtoul(s, &end, 0);
155 s = end;
156
157 for (const auto &debug_level : _debug_levels) {
158 new_levels[debug_level.name] = v;
159 }
160 }
161
162 /* Individual levels */
163 for (;;) {
164 /* skip delimiters */
165 while (*s == ' ' || *s == ',' || *s == '\t') s++;
166 if (*s == '\0') break;
167
168 t = s;
169 while (*s >= 'a' && *s <= 'z') s++;
170
171 /* check debugging levels */
172 const DebugLevel *found = nullptr;
173 for (const auto &debug_level : _debug_levels) {
174 if (s == t + strlen(debug_level.name) && strncmp(t, debug_level.name, s - t) == 0) {
175 found = &debug_level;
176 break;
177 }
178 }
179
180 if (*s == '=') s++;
181 v = std::strtoul(s, &end, 0);
182 s = end;
183 if (found != nullptr) {
184 new_levels[found->name] = v;
185 } else {
186 std::string error_string = fmt::format("Unknown debug level '{}'", std::string(t, s - t));
187 error_func(error_string);
188 return;
189 }
190 }
191
192 /* Apply the changes after parse is successful */
193 for (const auto &debug_level : _debug_levels) {
194 const auto &nl = new_levels.find(debug_level.name);
195 if (nl != new_levels.end()) {
196 *debug_level.level = nl->second;
197 }
198 }
199}
200
206std::string GetDebugString()
207{
208 std::string result;
209 for (const auto &debug_level : _debug_levels) {
210 if (!result.empty()) result += ", ";
211 fmt::format_to(std::back_inserter(result), "{}={}", debug_level.name, *debug_level.level);
212 }
213 return result;
214}
215
224std::string GetLogPrefix(bool force)
225{
226 std::string log_prefix;
228 log_prefix = fmt::format("[{:%Y-%m-%d %H:%M:%S}] ", fmt::localtime(time(nullptr)));
229 }
230 return log_prefix;
231}
232
241{
242 if (!_debug_remote_console.load()) return;
243
244 {
245 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
247 }
248
249 for (auto &item : _debug_remote_console_queue_spare) {
250 NetworkAdminConsole(item.level, item.message);
251 if (_settings_client.gui.developer >= 2) IConsolePrint(CC_DEBUG, "dbg: [{}] {}", item.level, item.message);
252 }
253
255}
256
265{
266 bool enable = _settings_client.gui.developer >= 2;
267
269 if (as->update_frequency[ADMIN_UPDATE_CONSOLE] & ADMIN_FREQUENCY_AUTOMATIC) {
270 enable = true;
271 break;
272 }
273 }
274
275 _debug_remote_console.store(enable);
276}
Class for handling the server side of the game connection.
static Pool::IterateWrapperFiltered< ServerNetworkAdminSocketHandler, ServerNetworkAdminSocketHandlerFilter > IterateActive(size_t from=0)
Returns an iterable ensemble of all active admin sockets.
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:89
Console functions used outside of the console code.
static const TextColour CC_DEBUG
Colour for debug output.
std::string GetLogPrefix(bool force)
Get the prefix for logs.
Definition debug.cpp:224
std::vector< QueuedDebugItem > _debug_remote_console_queue
Queue for debug messages to be passed to NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:35
std::mutex _debug_remote_console_mutex
Mutex to guard the queue of debug messages for either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:34
void DebugPrint(const char *category, int level, const std::string &message)
Internal function for outputting the debug line.
Definition debug.cpp:109
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:264
std::atomic< bool > _debug_remote_console
Whether we need to send data to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:33
void SetDebugString(const char *s, void(*error_func)(const std::string &))
Set debugging levels by parsing the text in s.
Definition debug.cpp:143
void DumpDebugFacilityNames(std::back_insert_iterator< std::string > &output_iterator)
Dump the available debug facility names in the help text.
Definition debug.cpp:87
std::vector< QueuedDebugItem > _debug_remote_console_queue_spare
Spare queue to swap with _debug_remote_console_queue.
Definition debug.cpp:36
std::string GetDebugString()
Print out the current debug-level.
Definition debug.cpp:206
void DebugSendRemoteMessages()
Send the queued Debug messages to either NetworkAdminConsole or IConsolePrint from the GameLoop threa...
Definition debug.cpp:240
Functions related to debugging.
std::optional< FileHandle > 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:242
Functions for Standard In/Out file operations.
@ AUTOSAVE_DIR
Subdirectory of save for autosaves.
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).
Server part of the admin network protocol.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
GUISettings gui
settings related to the GUI
bool show_date_in_logs
whether to show dates in console logs
uint8_t developer
print non-fatal warnings in console (>= 1), copy debug output to console (== 2)
Element in the queue of debug messages that have to be passed to either NetworkAdminConsole or IConso...
Definition debug.cpp:29
std::string level
The used debug level.
Definition debug.cpp:30
std::string message
The actual formatted message.
Definition debug.cpp:31
@ ADMIN_FREQUENCY_AUTOMATIC
The admin gets information about this when it changes.
Definition tcp_admin.h:103
@ ADMIN_UPDATE_CONSOLE
The admin would like to have console messages.
Definition tcp_admin.h:88
declarations of functions for MS windows systems
std::mutex lock
synchronization for playback status fields
Definition win32_m.cpp:35