top of page

INTRODUCTION

I created a logger system that is thread safe and determines the color by the subsystem the log is emitted from. For example: the engine prints white, the MaterialSystem prints pink, while the PakLoadAPI prints green, etc... This allows us to easily read the console and look for logs from a specific subsystem without filtering or using external tools.

​

In case the system does not support color logging (e.g., if the game is ran on a Windows 8 system), the user could still determine the origin of the log by reading out the context prefix (Native(M):, Script(S):, Native(C), etc...).

​

The system also prefixes any log with a timestamp, in square brackets. This timestamp represents the uptime of the process. We could determine exactly when a log was emitted. The files on the disk also contain dates, I removed these from the console as its was extraneous and not relevant while the game is still running.

​

The system features the open-source SpdLog library and is pretty fast! By default, we only log to a rotated file on the disk, and to the in-game console. Script prints are disabled as they are verbose. However, the user could launch the SDK in development mode and use the external console, and/or script prints.

​

To give an idea of how fast it is: we could log the raw traffic between 2 established client connections on the server without hitching the server or the game clients (file only logging, console logging disabled).

​

  • The SDK DLL containing the system has been downloaded over 150K times, without a single bug report caused by the logging system! The logging system is always active.

​

​

  • The SpdLog  initialization code could be found in this GitHub link.

  • The external console initialization code could be found in this GitHub link.

  • The Tier0 logger system could be found in this GitHub link (Contains DevMsg(..), Warning(..) and Error(..)).

  • The script logger system could be found in this GitHub Link (contains SQVM_PrintFunc(..) and SQVM_WarningFunc(..)). I had to accommodate the internal function by using the same prototype, in which I had to use pointer-to-enum casting in certain situations to yield desired results, for example, when emitting a script log over the remote console. We cannot send SquirrelVM pointers over the wire, so instead we send the enum in which the logger determines which context the log is originating from.

The above code mounts a Valve PAK file for use within the engine's filesystem. If we succeed, we log a message indicating the PAK file has been mounted successfully. If we fail, we log a warning indicating the mounting request had failed. The first argument (eDLL_T::FS) determines the context, since the Valve PAK system is handled by the filesystem DLL of the engine, we log the messages in the context of the filesystem (FS).

PROGRAMMING

Every context is enumerated:

The result of the above code :

Here I attempted to mount the VPK for 'server_mp_common.bsp', which has been successful, but I also tried to mount 'server_mp_rr_box.bsp', which has failed as the VPK for mp_rr_box was missing in this case. The Warning logger logged a message indicating the failure, this allows the developer or user to trouble shoot the problem more easily. The yellow log also stands out in the console due to its distinctive bright yellow color. We can retrieve the source of the log by the color of the log line, or the context prefix in case the terminal doesn't support colors.

​

  • ​Warnings, errors and dev logs are logged to a separate file on the disk. This is useful for when we run a dedicated server for a few hours, and someone managed to crash it. We could retrieve all errors/warnings and the crash call stack (scripts and code) without having to skim through any irrelevant dev logs.

  • We could easily merge the separated logs of warnings, errors and dev by using the process uptime stamps.

​

For errors, we can do something similar. Here I took an example from our RPak loading code:

Which results in:

logger_rpak_loadasync.png

Here I ran a command which loads the pak file "common_mp.rpak" from our mod and base paths. This has succeeded. I ran the same for "common_sdk.rpak", this has failed and thus has been logged as a distinctive red in the console. The reason this is a non-fatal error instead of a warning, is because missing RPak files could lead to segmentation faults or other unpredictable behavior. The RPak file is part of the asset streaming system and is deeply integrated into the engine with most error handling removed from retail executables.

​

However, when a segmentation fault or other fatal outcome is unavoidable, we terminate the process using the same error function, but instead of passing 'NO_ERROR' to the second parameter, we pass an error value:

Here I passed the 'EXIT_FAILURE' flag to the second parameter of the Error function if we couldn't create a DirectX 11 device and swap chain.

​

We can pass any value, the error will be considered fatal as long as the value is non-zero:

Here I passed the value '0xBAD0C0DE', which also results in the engine terminating immediately, leaving an error message in the console and an Engine/SDK error message box:

The error value passed to the second parameter of the Error wrapper will be used to terminate the process, it can be retrieved in the debugger:

bottom of page