Silfur Engine # 3: Silfur ! Talk to me !


Hello everyone :)

Welcome to this 3rd devlog on the Silfur Engine. It should be a little more interesting than the last and he gets deeper into the details of the engine.

This devlog is about the logging system of the Silfur Engine. As a reminder, the logging is to display -- Silfur Engine written on the console and a file (in a folder "Logs") -- what happens during the execution of our program. This is called logs. They allow developers but also, sometimes, the user to know what happened in case of bug (s). What gives this on the console:

I made the choice to let the user enter the name of his application in these messages (by defining a global macro for example) if he wishes of course. And therefore, the choice to leave me the rigor to write the name of the engine in its logs.

Library used

For the logging system, I used the spdlog library (accessible from Github). Then, I created a custom and configurable API to use the system in a simple way. I could have done everything from scratch but that doesn't interest me. Moreover, spdlog focuses heavily on the performance, which is a very good point.

Use

To use, it's very simple. Just call the macro (see this link) by passing in parameter the message that we want to make write. For text formatting and passing of personal values, the spdlog library provides a formatting python-like. Just write {} where you want to insert data and put the arguments after the message, in the order of {}, as shown the example below:


Configuration

The API provides what to configure the logs as you want. By default, the API uses 3 usage profiles:

  • Display all logs
  • Displays logs of level info to fatal with Development profile
  • Display logs of fatal level only with the Release profile

To use the first profile, it has nothing to do, it's by default. To use the second, just enter the _DEVELOPMENT_PROFILE preprocessor directive in the project's compilations options. And for the third, the _RELEASE_PROFILE preprocessor directive in the project compilations options.

It's possible to disable this mechanics of profiles by setting this preprocessor directive, before including Silfur.h in your project:

#define SF_LOG_PACKAGE 0 // Disable the use of profiles
#define SF_LOG_PACKAGE 1 // Enable the use of profiles -- By default

The last line is the default behavior, no need to define it. It's there for information.

The API also allows you to configure the levels of logs to display according to your needs, just define one of these preprocessor directives, before including Silfur.h in your project:

#define SF_LOG_LEVEL 0 // Disable all logs
#define SF_LOG_LEVEL 1 // Display only logs of fatal level
#define SF_LOG_LEVEL 2 // Display only logs fatal, error levels
#define SF_LOG_LEVEL 3 // Display only logs fatal, error, warning levels
#define SF_LOG_LEVEL 4 // Display only logs fatal, error, warning, info levels
#define SF_LOG_LEVEL 5 // Display only logs fatal, error, warning, info, debug levels
#define SF_LOG_LEVEL 6 // Display all logs (fatal, error, warning, info, debug, trace levels) -- By default

The last line is the default behavior, no need to define it. It's there for information.

The user has the possibility to enable or disable flushing of the file if he wishes. In the example below, it is at the time of application creation (syntactically, it is a call to a static function):

Finished the explanations for using the logging system of the Silfur Engine. Let's see how it's implemented!

API's code

First, the API is defined by only one static class: Log. Its header is defined as follows:

Why static? Because I don't want instantiate the logging system. It is a simple tool that can be used as described above.

To put it simply, it only has 5 functions:

  • One for initialisation
  • One for enable/disable the flushing of the log file (it can be a real cost on performance)
  • 3 getters : the logger, the log file's name (not its full path), and one boolean for know if the flushing is activate or not

The values of the static variables are defined in the file Log.cpp :

Initialization is to be called once and it's only the engine that does it. It's therefore completely transparent to the user. The initialization function is rather trivial (once we read the documentation on spdlog):

I also wanted to display more information than the spdlog library allowed. In particular, the display of the file, the line and the function where the log was called. So I thought about a solution leading to this:

For macro configuration, it was necessary to create macros representing different levels and enable/disable packages:

And write the preprocessor directives to manage all the different cases:


Finished this devlog for the logging system, its use as a user and its implementation.

Thank for reading!

See you soon on the next devlog ! :)

Leave a comment

Log in with itch.io to leave a comment.