logog
logger optimized for games
Custom formatting of log messages

The Formatter object is responsible for rendering a particular Topic into a human-readable format. A default Formatter is created by default for you based on the flavor of the compile target. See FormatterGCC and FormatterMSVC objects for examples.

If you want log messages in your own custom format, subclass the Formatter::Format method into your own custom class, and write your own formatting function for a topic. See FormatterMSVC::Format and FormatterGCC::Format for examples.

Once you have written your own custom formatting function, assign it to the Target that should use your custom formatter, by using the Target::SetFormatter() function.

If all you want to do is enable or disable a certain type of output on your formatter – for example, to remove file and line number information from all your output lines – then there's a very simple way of doing this. The Formatter class implements a Formatter::GetTopicFlags() function that in the default case queries the topic in order to find out which fields to render. You can if you wish override this default behavior for a custom formatter in order to always or never render specific fields.

The following example overrides the standard FormatterMSVC formatter in order to never show file and line number information on the output.

class FormatterCustom : public FormatterMSVC
{
virtual TOPIC_FLAGS GetTopicFlags( const Topic &topic )
{
return ( Formatter::GetTopicFlags( topic ) &
}
};
UNITTEST( CustomFormatter )
{
{
Cout out;
FormatterCustom customFormat;
out.SetFormatter( customFormat );
INFO( _LG( "No file and line number info is provided with this output.") );
/* The following output is produced:
* info: No file and line number info is provided with this output.
*/
}
return 0;
}

If you wish, you can force a formatter to output the current date and time as part of their format. You can do this by calling the Formatter::SetShowTimeOfDay function with a value of true, as follows:

{
Cerr err;
Formatter *pFormatter = &GetDefaultFormatter();
pFormatter->SetShowTimeOfDay( true );
for ( int i = 1; i <= 20; i++ )
{
WARN(_LG("This is warning %d of 20... but with time!"), i);
int q = 27832;
for ( int j = 0; j < TEST_STRESS_LEVEL * 10000000; j++ )
q *= q;
}
}

Here's a more general example of doing radical custom changes to the formatting style of the output. In this case, the formatter adds exclamation mark boundaries to any message of LOGOG_LEVEL_WARN type or more important, and it adds three periods to the end of any message. Since this custom formatter only applies to the target set with Target::SetFormatter(), you could modify this example and the changes would only apply to the formatter you select.

class FormatterModified : public FormatterMSVC
{
/* In this example custom Formatter, we've basically rewritten the parent
* class to include !!!'s before any topic of LOGOG_LEVEL_WARN
* intensity or more important, and we append ... to the message
* in all cases. Large quantities of code are simply copied
* and modified from the parent class.
*/
virtual LOGOG_STRING &Format( const Topic &topic, const Target &target )
{
TOPIC_FLAGS flags = GetTopicFlags( topic );
m_sMessageBuffer.clear();
if ( topic.Level() <= LOGOG_LEVEL_WARN )
m_sMessageBuffer.append( _LG("!!! ") );
if ( flags & TOPIC_FILE_NAME_FLAG )
{
m_sMessageBuffer.append( topic.FileName() );
m_sMessageBuffer.append( ':' );
}
if ( flags & TOPIC_LINE_NUMBER_FLAG )
{
m_sIntBuffer.assign( topic.LineNumber() );
m_sMessageBuffer.append( m_sIntBuffer );
m_sMessageBuffer.append( LOGOG_CONST_STRING(": "));
}
RenderTimeOfDay();
if ( flags & TOPIC_LEVEL_FLAG )
{
m_sMessageBuffer.append( ErrorDescription( topic.Level()));
m_sMessageBuffer.append( LOGOG_CONST_STRING(": "));
}
if ( flags & TOPIC_GROUP_FLAG )
{
m_sMessageBuffer.append( LOGOG_CONST_STRING("{") );
m_sMessageBuffer.append( topic.Group() );
m_sMessageBuffer.append( LOGOG_CONST_STRING("} ") );
}
if ( flags & TOPIC_CATEGORY_FLAG )
{
m_sMessageBuffer.append( LOGOG_CONST_STRING("["));
m_sMessageBuffer.append( topic.Category() );
m_sMessageBuffer.append( LOGOG_CONST_STRING("] "));
}
if ( flags & TOPIC_MESSAGE_FLAG )
{
m_sMessageBuffer.append( topic.Message() );
}
/* At this point we use the String's format() function to reformat the
* old string into the new format.
*/
if ( topic.Level() <= LOGOG_LEVEL_WARN )
{
/* If this message is more important than LOGOG_LEVEL_WARN,
* add exclamation marks
*/
m_sMessageBuffer.append( _LG(" !!!") );
}
else
{
/* Otherwise add periods */
m_sMessageBuffer.append( _LG(" ...") );
}
if ( flags & TOPIC_MESSAGE_FLAG )
{
m_sMessageBuffer.append( (LOGOG_CHAR)'\n' );
}
if ( target.GetNullTerminatesStrings() )
m_sMessageBuffer.append( (LOGOG_CHAR)NULL );
/* Return m_sMessageBuffer like the parent class does */
return m_sMessageBuffer;
}
};
UNITTEST( CustomFormatterModified )
{
{
/* This test produces output resembling:
C:\logog\test\test.cpp:484: info: This info message output has trailing periods ...
!!! C:\logog\test\test.cpp:485: warning: This warning message is surrounded by exclamation marks !!!
*/
Cout out;
FormatterModified customFormat;
out.SetFormatter( customFormat );
INFO( _LG( "This info message output has trailing periods") );
WARN( _LG( "This warning message is surrounded by exclamation marks") );
}
return 0;
}