logog
logger optimized for games
Quick start

The logog system is a set of C++ header files and C++ source files. To use them, compile all the C++ source files into a single library. The compiler will need to reference the files in the include directory when compiling the logog library.

Build the logog library

To make this easier, logog has been set up to compile using CMake, available at http://www.cmake.org/ . CMake is a free cross-platform build system, and executables are available for most major platforms and development environments. Download and install CMake in order to generate a build for your platform.

For example, to build the project and libraries on Visual Studio 2017, find and launch the Visual Studio 2017 Command Prompt at Microsoft Visual Studio 2017 / Visual Studio Tools / Visual Studio 2017 Command Prompt.

Then, to create the appropriate project files, create an empty directory, make that directory the current directory, and run the CMake command with the logog directory as a parameter:

mkdir logog-build
cd logog-build
cmake [path-to-logog-top-directory]

At this point, your directory will contain appropriate project and solution files for your platform. Once the solution is building, the CMake program is no longer needed. Compile and link the library for your own platform using the makefile or project files generated for your platform.

Your Hello, Logog! program

Here is a working logog example that initializes logog, outputs some sample messages and then terminates.

/* The LOGOG_INITIALIZE() function must be called before we call
* any other logog functions.
*/
{
/* In order to see any output, we have to instance a Target object,
* such as a Cerr or a Cout. Additionally, we have to destroy
* this object before calling LOGOG_SHUTDOWN(). This
* is why we have this object within these enclosing brackets.
*/
Cout out;
/* Send some debugging information to any targets that have
* been instanced.
*/
/* If you're just getting started, and you haven't defined
* LOGOG_UNICODE, then ASCII logging is easy and works
* out of the box.
*/
#ifndef LOGOG_UNICODE
INFO("Hello, logog!");
WARN("This is a warning");
#endif // !LOGOG_UNICODE
/* The _LG() macro around static text permits the given text to
* display correctly in both Unicode and ASCII builds of the
* logog library.
*/
ERR( _LG( "This is an error") );
DBUG( _LG( "This is debugging info") );
/* The Cout object is destroyed here because it falls out of
* scope. */
}
/* Call LOGOG_SHUTDOWN() at the termination of your program to free
* all memory allocated by logog. Make sure no logog objects exist
* when you call LOGOG_SHUTDOWN().
*/
/* Depending on your compiler, the output of the preceding code is
* something like:
*
* test.cpp(373) : info: Hello, logog!
* test.cpp(374) : warning: This is a warning
* test.cpp(375) : error: This is an error
* test.cpp(376) : debug: This is debugging info
*/

The most common mistake when getting started with logog is creating a Cerr or Cout object and not destroying the object before LOGOG_SHUTDOWN(). This is a usage error and will be detected as heap corruption by most debuggers.

Integrate logog into your own project

To use the logging library in your own project, put the following line at the top of your source file(s):

#include "logog.hpp"

Additionally, make sure to add logog's /include path into the directories your build process searches.

At the beginning of your program, initialize logog exactly once, with this macro:

Choose one or more output types

To tell logog what type of output should be logged, you must first create a logog::Cerr, a logog::Cout, or a logog::LogFile object. Once this object is instantiated, all messages will be routed to that target. For example:

logog::Cerr errOutput;

Or:

logog::LogFile errFile("log.txt");

It's only necessary to create one target per process, immediately after initializing logog; you don't need to instance a different Cout, Cerr or LogFile for each class or each file.

Start logging events

To log a message in your code, use one of the following macros, in order of severity. Arguments are assumed to be sprintf-style varargs:

#define DBUG(...) LOGOG_DEBUG( __VA_ARGS__ )
#define INFO(...) LOGOG_INFO( __VA_ARGS__ )
#define WARN3(...) LOGOG_WARN3( __VA_ARGS__ )
#define WARN2(...) LOGOG_WARN2( __VA_ARGS__ )
#define WARN1(...) LOGOG_WARN1( __VA_ARGS__ )
#define WARN(...) LOGOG_WARN( __VA_ARGS__ )
#define ERR(...) LOGOG_ERROR( __VA_ARGS__ )
#define ALERT(...) LOGOG_ALERT( __VA_ARGS__ )
#define CRITICAL(...) LOGOG_CRITICAL( __VA_ARGS__ )
#define EMERGENCY(...) LOGOG_EMERGENCY( __VA_ARGS__ )

Note the funny spellings on DBUG and ERR to avoid conflicting with existing macros on Windows platforms.

If it turns out that the names of these macros conflict with your existing code, then before including the logog.hpp file, define the following constant:

#define LOGOG_USE_PREFIX 1

If you enable that prefix, you may log with the following macros instead:

LOGOG_DEBUG( __VA_ARGS__ )
LOGOG_INFO( __VA_ARGS__ )
LOGOG_WARN3( __VA_ARGS__ )
LOGOG_WARN2( __VA_ARGS__ )
LOGOG_WARN1( __VA_ARGS__ )
LOGOG_WARN( __VA_ARGS__ )
LOGOG_ERROR( __VA_ARGS__ )
LOGOG_ALERT( __VA_ARGS__ )
LOGOG_CRITICAL( __VA_ARGS__ )
LOGOG_EMERGENCY( __VA_ARGS__ )

An example usage follows:

int foo = 9001;
int maxfoo = 9000;
if ( foo > maxfoo )
{
WARN("Foo is over %d! Current value is %d.", maxfoo, foo );
WARN("Since this is a warning, by default all builds will log this message!");
}
const char *pMessage = "message"
INFO( "This is an informational %s.", pMessage );

At this point, your Target object (in this case, the errOutput object) should be destroyed. Falling out of scope is the easiest way to achieve this.

Then, terminate your program and logging with the following message:

Lastly, compile and link with the logog library you created earlier.