Installation
The library is designed to be statically compiled into your project. Just copy the files to your project and add them to your compilation sources and you’re done with the installation. Next add an include directive for UVKLog.h
in one of your files and you’re done
Additional Features
Compiling for a library
Compiling the logger as part of a larger library and want to export the symbols? To do that you need to define the UVK_LOG_EXPORT_FROM_LIBRARY
macro and when you’re compiling the larger library make sure the macro UVK_LIB_COMPILE
is defined. When compiling with UVK_LIB_COMPILE
you export your symbols for Windows using __declspec(dllexport)
, while if disabled it uses __declspec(dllimport)
No instant error termination
Handling errors will be explained below. In the most basic sense, if the NO_INSTANT_CRASH
is defined, instead of instantly crashing on an error, we place an std::cin.get()
call before terminating the application so that you can for example, look at the last frame of your application, check the output, etc.
Enabling the dear imgui console widget
You can enable the dear imgui console widget by including UVKLogImGui.h
, having imgui.h
in your include path and defining the UVK_LOG_IMGUI
macro. This widget has a simple console interface where every log is recorded to a buffer which you can view in dear imgui. Additionally you can also add your own commands. Using the widget is explained below
Standard Logging
There is a single class you can use for all your logging needs, this class is the Logger
class, part of the UVKLog
namespace in the UVKLog.h
header. The `logger class contains the following static functions that you can use for logging
void setCrashOnError(bool bError)
- If set to true every time you call the log function with an error as the type it will terminate the applicationvoid setCurrentLogFile(const char* file)
- Sets the current file we’re logging to, to a different one or initializes a new filevoid setLogOperation(LogOperations op)
- Sets the current log operationvoid log(const char* message, LogType type, args&&... argv)
- The log functions, given a message, a log type and an optional list of templated variadic arguments, will log a message using the current log operation
Log Operations
Log operations are set using the void setLogOperation(LogOperations op)
static member function of the Logger
class. To change the log operation pass this function an argument of type LogOperations
. This type is the following enum:
enum LogOperations
{ // This is the default operation
UVK_LOG_OPERATION_TERMINAL,
UVK_LOG_OPERATION_FILE,
UVK_LOG_OPERATION_FILE_AND_TERMINAL, };
as you can see, we have 3 log operations, TERMINAL
, FILE
and FILE_AND_TERMINAL
. By default we use the TERMINAL
operation as no resources are needed for it. Please do note that using the setCurrentLogFile
function while in the TERMINAL
operation will not change the operation to FILE
or FILE_AND_TERMINAL
. You’re responsible for changing your operation type!
Log Types
There are currently 6 types of log messages that you can pass to the log function. They’re stored in the LogType
enum, which looks like this:
enum LogType
{ 1,
UVK_LOG_TYPE_WARNING = 2,
UVK_LOG_TYPE_ERROR = 4,
UVK_LOG_TYPE_NOTE = 0,
UVK_LOG_TYPE_SUCCESS = 3
UVK_LOG_TYPE_MESSAGE = };
The types other than ERROR
don’t have any functionality other than being displayed with a different title and colour in the terminal/GUI console. By default the ERROR
type also works like the others but you can enable termination on errors, which will terminate your process when an error is logged.
The different log types are represented with different colours in the terminal/GUI console, here is a lookup table:
- SUCCESS - Green
- NOTE - Blue
- MESSAGE - White/Grey
- WARNING - Yellow/Orange
- ERROR - Red
Logging
To log a message simply use the log
function of the Logger
class by passing a message, a LogType
and an optional list of templated variadic arguments. For example, here is how you can print Hello, World
as a success:
"Hello, World!", UVK_LOG_TYPE_SUCCESS); UVKLog::Logger::log(
additionally you can provide a list of optional templated variadic arguments, so this is how you can print a mix of strings and numbers
"Hello, World!", UVK_LOG_TYPE_SUCCESS, " Here we have a regular integer: ", 5, "; And here we have a float: ", 10.5f); UVKLog::Logger::log(
Using the dear imgui console widget
To use the console widget first go back here to see how you can enable it. Now that you have it enabled you can use the UVKLog::ImGuiConsole
class.
Create an instance of the class, next in you game loop decide on how you want to display it.
If you want a separate ImGui window, you can use the void displayFull(bool& bOpen, bool* bInteractingWithTextbox)
member function but keep in mind that you need to provide a bool&
for the X
icon on the window’s header.
The other argument is a bool*
that you can use to check if the text box is currently active. If you don’t need that functionality you can leave it as nullptr
If you don’t want a full window, you can also use the void display(bool* bInteractingWithTextBox)
function, which you can use in your own window, or inside the global framebuffer. The function takes the same bool*
for checking whether you’re interacting with the textbox or not. If you’re not using this feature leave it as nullptr
Changing the colours
To change the colours you can use the void setLogColour(ImVec4 colours, LogType type)
function. Simply pass your colour as a 4D vector and a LogType
enum member
Adding Commands
By default there are 2 commands in the console, clear
and help
which are self explanatory. To add your own commands you can initialize a struct of type CommandType
, which looks like this:
struct CommandType
{std::string cmd;
std::string cmdHint;
std::function<void(const std::string&)> func;
};
the cmd
string is the name of the command, we check if the command passed in the text box starts with the contents of the cmd
string
The cmdHint
string defines the string to be shown in the help message
The func
function pointer is called when the command is found. It takes a const std::string&
which you can use to parse additional arguments
After you have your struct initialized you can pass it to the static member of the UVKLog::ImGuiConsole
class’ addCommand(const CommandType& cmd)
function. After you have added this your command is ready to be used. Here is an example:
const UVKLog::CommandType customCommand =
{"test",
.cmd = "Just a test command",
.cmdHint = const std::string&){ UVKLog::ImGuiConsole::addToMessageLog("Test", UVK_LOG_TYPE_MESSAGE); }
.func = [&](
};
UVKLog::ImGuiConsole::addCommand(customCommand);
Adding messages to the log without formatting
Instead of using standard logging you can also use the static member of UVKLog::ImGuiConsole
class’ addToMessageLog(const std::string&, LogType type)
function. This function adds a string with a log type for colour, but unlike the normal log function it doesn’t have any formatting. Here is an example:
"Test", UVK_LOG_TYPE_MESSAGE); UVKLog::ImGuiConsole::addToMessageLog(
Utility classes
The Timer class
Together with the logging library and console widget we also include a Timer
to record how much time a task takes. To use the timer instantiate the Timer
class.
Call the start
function and when you want it to end call the stop
function, then get how much time the task took using the get
function.
If you still want to record call the stop
function again without calling the start
function. When you call the start
function you restart your times
Here’s an example:
Timer timer;
timer.start();
doStuff();
timer.stop()"doStuff took ", UVK_LOG_TYPE_NOTE, timer.get(), " milliseconds!");
UVKLog::Logger::log(
doStuff2();
"doStuff and doStuff2 took ", UVK_LOG_TYPE_NOTE, timer.get(), " milliseconds!"); UVKLog::Logger::log(