OpenTTD Source 20260911-master-gee2b2ac12a
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
12#include "console_func.h"
13#include "debug.h"
14#include "string_func.h"
15#include "fileio_func.h"
16#include "settings_type.h"
17#include <mutex>
18
19#if defined(_WIN32)
20#include "os/windows/win32.h"
21#endif
22
23#include "3rdparty/fmt/chrono.h"
24
26
27#include "safeguards.h"
28
32 std::string message;
33};
34std::atomic<bool> _debug_remote_console;
36std::vector<QueuedDebugItem> _debug_remote_console_queue;
37std::vector<QueuedDebugItem> _debug_remote_console_queue_spare;
38
41
44 "driver", // Facility::Driver
45 "grf", // Facility::Grf
46 "map", // Facility::Map
47 "misc", // Facility::Misc
48 "net", // Facility::Net
49 "sprite", // Facility::Sprite
50 "oldloader", // Facility::Oldloader
51 "yapf", // Facility::Yapf
52 "fontcache", // Facility::Fontcache
53 "script", // Facility::Script
54 "sl", // Facility::Sl
55 "gamelog", // Facility::Gamelog
56 "desync", // Facility::Desync
57 "console", // Facility::Console
58 "random", // Facility::Random
59};
60
65void DumpDebugFacilityNames(std::back_insert_iterator<std::string> &output_iterator)
66{
67 bool written = false;
68 for (Facility facility : EnumRange(Facility::End)) {
69 if (!written) {
70 fmt::format_to(output_iterator, "List of debug facility names:\n");
71 } else {
72 fmt::format_to(output_iterator, ", ");
73 }
74 fmt::format_to(output_iterator, "{}", _debug_facilities[facility]);
75 written = true;
76 }
77 if (written) {
78 fmt::format_to(output_iterator, "\n\n");
79 }
80}
81
88void DebugPrint(Facility facility, Severity severity, std::string &&message)
89{
90 if (facility == Facility::Desync && severity != Severity::Critical) {
91 static auto f = FioFOpenFile("commands-out.log", "wb", Subdirectory::Autosave);
92 if (!f.has_value()) return;
93
94 fmt::print(*f, "{}{}\n", GetLogPrefix(true), message);
95 fflush(*f);
96#ifdef RANDOM_DEBUG
97 } else if (facility == Facility::Random) {
98 static auto f = FioFOpenFile("random-out.log", "wb", Subdirectory::Autosave);
99 if (!f.has_value()) return;
100
101 fmt::print(*f, "{}\n", message);
102 fflush(*f);
103#endif
104 } else {
105 fmt::print(stderr, "{}dbg: [{}:{}] {}\n", GetLogPrefix(true), _debug_facilities[facility], severity, message);
106
107 if (_debug_remote_console.load()) {
108 /* Only add to the queue when there is at least one consumer of the data. */
109 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
110 _debug_remote_console_queue.emplace_back(facility, std::move(message));
111 }
112 }
113}
114
122void SetDebugString(std::string_view s, SetDebugStringErrorFunc error_func)
123{
124 StringConsumer consumer{s};
125
126 /* Store planned changes into a temporary array during parse */
127 auto new_debug_level = _debug_level;
128
129 /* Global debugging level? */
130 auto level = consumer.TryReadIntegerBase<int>(10);
131 if (level.has_value()) {
132 new_debug_level.fill(static_cast<Severity>(*level));
133 }
134
135 static const std::string_view lowercase_letters{"abcdefghijklmnopqrstuvwxyz"};
136 static const std::string_view lowercase_letters_and_digits{"abcdefghijklmnopqrstuvwxyz0123456789"};
137
138 /* Individual levels */
139 while (consumer.AnyBytesLeft()) {
140 consumer.SkipUntilCharIn(lowercase_letters);
141 if (!consumer.AnyBytesLeft()) break;
142
143 /* Find the level by name. */
144 std::string_view key = consumer.ReadUntilCharNotIn(lowercase_letters);
145 auto it = std::ranges::find(_debug_facilities, key);
146 if (it == std::end(_debug_facilities)) {
147 error_func(fmt::format("Unknown debug level '{}'", key));
148 return;
149 }
150
151 /* Do not skip lowercase letters, so 'net misc=2' won't be resolved
152 * to setting 'net=2' and leaving misc untouched. */
153 consumer.SkipUntilCharIn(lowercase_letters_and_digits);
154 level = consumer.TryReadIntegerBase<int>(10);
155 if (!level.has_value()) {
156 error_func(fmt::format("Level for '{}' must be a valid integer.", key));
157 return;
158 }
159
160 new_debug_level[static_cast<Facility>(std::distance(_debug_facilities.begin(), it))] = static_cast<Severity>(*level);
161 }
162
163 /* Apply the changes after parse is successful */
164 _debug_level = new_debug_level;
165}
166
172std::string GetDebugString()
173{
174 std::string result;
175 for (Facility facility : EnumRange(Facility::End)) {
176 if (!result.empty()) result += ", ";
177 format_append(result, "{}={}", _debug_facilities[facility], _debug_level[facility]);
178 }
179 return result;
180}
181
191std::string GetLogPrefix(bool force)
192{
193 std::string log_prefix;
194 if (force || _settings_client.gui.show_date_in_logs) {
195 log_prefix = fmt::format("[{:%Y-%m-%d %H:%M:%S}] ", fmt::localtime(time(nullptr)));
196 }
197 return log_prefix;
198}
199
208{
209 if (!_debug_remote_console.load()) return;
210
211 {
212 std::lock_guard<std::mutex> lock(_debug_remote_console_mutex);
214 }
215
216 for (auto &item : _debug_remote_console_queue_spare) {
217 NetworkAdminConsole(_debug_facilities[item.facility], item.message);
218 if (_settings_client.gui.developer >= 2) IConsolePrint(CC_DEBUG, "dbg: [{}] {}", _debug_facilities[item.facility], item.message);
219 }
220
222}
223
232{
233 bool enable = _settings_client.gui.developer >= 2;
234
236 if (as->update_frequency[AdminUpdateType::Console].Test(AdminUpdateFrequency::Automatic)) {
237 enable = true;
238 break;
239 }
240 }
241
242 _debug_remote_console.store(enable);
243}
Iterate a range of enum values.
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.
Parse data from a string / buffer.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
std::string_view ReadUntilCharNotIn(std::string_view chars)
Read 8-bit chars, while they are in 'chars', until they are not; and advance reader.
void SkipUntilCharIn(std::string_view chars)
Skip 8-bit chars, while they are not in 'chars', until they are.
void IConsolePrint(ExtendedTextColour 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:90
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:191
std::vector< QueuedDebugItem > _debug_remote_console_queue
Queue for debug messages to be passed to NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:36
std::mutex _debug_remote_console_mutex
Mutex to guard the queue of debug messages for either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:35
void SetDebugString(std::string_view s, SetDebugStringErrorFunc error_func)
Set debugging levels by parsing the text in s.
Definition debug.cpp:122
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:231
std::atomic< bool > _debug_remote_console
Whether we need to send data to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:34
void DumpDebugFacilityNames(std::back_insert_iterator< std::string > &output_iterator)
Dump the available debug facility names in the help text.
Definition debug.cpp:65
std::vector< QueuedDebugItem > _debug_remote_console_queue_spare
Spare queue to swap with _debug_remote_console_queue.
Definition debug.cpp:37
EnumIndexArray< Severity, Facility, Facility::End > _debug_level
Severity level for each debug facility.
Definition debug.cpp:40
std::string GetDebugString()
Print out the current debug-level.
Definition debug.cpp:172
void DebugSendRemoteMessages()
Send the queued Debug messages to either NetworkAdminConsole or IConsolePrint from the GameLoop threa...
Definition debug.cpp:207
void DebugPrint(Facility facility, Severity severity, std::string &&message)
Internal function for outputting the debug line.
Definition debug.cpp:88
static EnumIndexArray< std::string_view, Facility, Facility::End > _debug_facilities
Name for each debug facility.
Definition debug.cpp:43
Functions related to debugging.
Facility
Debug facilities.
Definition debug_type.h:28
@ Desync
Desync message facility.
Definition debug_type.h:41
@ Random
Random message facility.
Definition debug_type.h:43
@ End
End marker.
Definition debug_type.h:44
Severity
Debug message severity levels.
Definition debug_type.h:14
@ Critical
Critical, user should know about this.
Definition debug_type.h:15
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
std::optional< FileHandle > FioFOpenFile(std::string_view filename, std::string_view mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition fileio.cpp:249
Functions for standard in/out file operations.
@ Autosave
Subdirectory of save for autosaves.
Definition fileio_type.h:91
void NetworkAdminConsole(std::string_view origin, 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:60
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
Parse strings.
Functions related to low-level strings.
Element in the queue of debug messages that have to be passed to either NetworkAdminConsole or IConso...
Definition debug.cpp:30
Facility facility
The facility of the message.
Definition debug.cpp:31
std::string message
The actual formatted message.
Definition debug.cpp:32
@ Console
The admin would like to have console messages.
Definition tcp_admin.h:87
@ Automatic
The admin gets information about this when it changes.
Definition tcp_admin.h:102
Declarations of functions for MS windows systems.
std::mutex lock
synchronization for playback status fields
Definition win32_m.cpp:35