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/>.
8 /** @file debug.cpp Handling of printing debug messages. */
12 #include "console_func.h"
14 #include "string_func.h"
15 #include "fileio_func.h"
16 #include "settings_type.h"
19 #include "os/windows/win32.h"
24 #include "network/network_admin.h"
25 SOCKET _debug_socket
= INVALID_SOCKET
;
27 #include "safeguards.h"
29 int _debug_driver_level
;
32 int _debug_misc_level
;
34 int _debug_sprite_level
;
35 int _debug_oldloader_level
;
37 int _debug_yapf_level
;
38 int _debug_freetype_level
;
39 int _debug_script_level
;
41 int _debug_gamelog_level
;
42 int _debug_desync_level
;
43 int _debug_console_level
;
45 int _debug_random_level
;
48 uint32 _realtime_tick
= 0;
55 #define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
56 static const DebugLevel debug_level
[] = {
63 DEBUG_LEVEL(oldloader
),
66 DEBUG_LEVEL(freetype
),
79 * Dump the available debug facility names in the help text.
80 * @param buf Start address for storing the output.
81 * @param last Last valid address for storing the output.
82 * @return Next free position in the output.
84 char *DumpDebugFacilityNames(char *buf
, char *last
)
87 for (const DebugLevel
*i
= debug_level
; i
!= endof(debug_level
); ++i
) {
89 buf
= strecpy(buf
, "List of debug facility names:\n", last
);
91 buf
= strecpy(buf
, ", ", last
);
94 buf
= strecpy(buf
, i
->name
, last
);
95 length
+= strlen(i
->name
);
98 buf
= strecpy(buf
, "\n\n", last
);
104 * Internal function for outputting the debug line.
105 * @param dbg Debug category.
106 * @param buf Text line to output.
108 static void debug_print(const char *dbg
, const char *buf
)
110 if (_debug_socket
!= INVALID_SOCKET
) {
111 char buf2
[1024 + 32];
113 seprintf(buf2
, lastof(buf2
), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg
, buf
);
114 /* Sending out an error when this fails would be nice, however... the error
115 * would have to be send over this failing socket which won't work. */
116 send(_debug_socket
, buf2
, (int)strlen(buf2
), 0);
119 if (strcmp(dbg
, "desync") == 0) {
120 static FILE *f
= FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR
);
121 if (f
== nullptr) return;
123 fprintf(f
, "%s%s\n", GetLogPrefix(), buf
);
126 } else if (strcmp(dbg
, "random") == 0) {
127 static FILE *f
= FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR
);
128 if (f
== nullptr) return;
130 fprintf(f
, "%s\n", buf
);
135 seprintf(buffer
, lastof(buffer
), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg
, buf
);
137 TCHAR system_buf
[512];
138 convert_to_fs(buffer
, system_buf
, lengthof(system_buf
), true);
139 _fputts(system_buf
, stderr
);
141 fputs(buffer
, stderr
);
143 NetworkAdminConsole(dbg
, buf
);
144 IConsoleDebug(dbg
, buf
);
149 * Output a debug line.
150 * @note Do not call directly, use the #DEBUG macro instead.
151 * @param dbg Debug category.
152 * @param format Text string a la printf, with optional arguments.
154 void CDECL
debug(const char *dbg
, const char *format
, ...)
159 va_start(va
, format
);
160 vseprintf(buf
, lastof(buf
), format
, va
);
163 debug_print(dbg
, buf
);
167 * Set debugging levels by parsing the text in \a s.
168 * For setting individual levels a string like \c "net=3,grf=6" should be used.
169 * If the string starts with a number, the number is used as global debugging level.
170 * @param s Text describing the wanted debugging levels.
172 void SetDebugString(const char *s
)
178 /* global debugging level? */
179 if (*s
>= '0' && *s
<= '9') {
182 v
= strtoul(s
, &end
, 0);
185 for (i
= debug_level
; i
!= endof(debug_level
); ++i
) *i
->level
= v
;
188 /* individual levels */
193 /* skip delimiters */
194 while (*s
== ' ' || *s
== ',' || *s
== '\t') s
++;
195 if (*s
== '\0') break;
198 while (*s
>= 'a' && *s
<= 'z') s
++;
200 /* check debugging levels */
202 for (i
= debug_level
; i
!= endof(debug_level
); ++i
) {
203 if (s
== t
+ strlen(i
->name
) && strncmp(t
, i
->name
, s
- t
) == 0) {
210 v
= strtoul(s
, &end
, 0);
215 ShowInfoF("Unknown debug level '%.*s'", (int)(s
- t
), t
);
222 * Print out the current debug-level.
223 * Just return a string with the values of all the debug categories.
224 * @return string with debug-levels
226 const char *GetDebugString()
229 static char dbgstr
[150];
232 memset(dbgstr
, 0, sizeof(dbgstr
));
234 seprintf(dbgstr
, lastof(dbgstr
), "%s=%d", i
->name
, *i
->level
);
236 for (i
++; i
!= endof(debug_level
); i
++) {
237 seprintf(dbgval
, lastof(dbgval
), ", %s=%d", i
->name
, *i
->level
);
238 strecat(dbgstr
, dbgval
, lastof(dbgstr
));
245 * Get the prefix for logs; if show_date_in_logs is enabled it returns
246 * the date, otherwise it returns nothing.
247 * @return the prefix for logs (do not free), never nullptr
249 const char *GetLogPrefix()
251 static char _log_prefix
[24];
252 if (_settings_client
.gui
.show_date_in_logs
) {
253 time_t cur_time
= time(nullptr);
254 strftime(_log_prefix
, sizeof(_log_prefix
), "[%Y-%m-%d %H:%M:%S] ", localtime(&cur_time
));