log_argument_format.hpp File Reference

Classes

class  kanzi::detail::LogArgumentFormat
 Represents log message argument formatting interface. More...
 

Namespaces

 kanzi
 
 kanzi::detail
 

Functions

template<typename T >
string kanzi::logArgumentToString (const T &value)
 The Logging Subsystem uses this function to Convert value to the string. More...
 

Detailed Description

Log message formating

The log message is either a scalar value or a format specification string followed by the format arguments. Example:

// Define log category.
#define MY_LOG_CATEGORY KZ_LOG_CREATE_CATEGORY(KZ_LOG_ENABLED_CATEGORY, "my category")
// Log message is integer constant here.
kzLogInfo(MY_LOG_CATEGORY, (100));
// Log integer variable.
int length = 100;
// Output: 100
kzLogInfo(MY_LOG_CATEGORY, (length));
// Log string literal.
// Output: Single log message.
kzLogInfo(MY_LOG_CATEGORY, ("Single log message."));
// Log formatted message.
// Format string: "{} plus {} equals {}.".
// Format arguments: 1, 2, 1+2.
// Output: 1 plus 2 equals 3.
kzLogInfo(MY_LOG_CATEGORY, ("{} plus {} equals {}.", 1, 2, 1+2));

Format specification string is a literal text that may contain the format argument references in figure braces:

"Text {...} text {...} ... {...} ..."

The argument references are replaced inplace with string representation of the referred argument's values when message is written by the logger. The rest of the literal text is kept unchanged. The format argument reference has the following structure:

{[argument index][:format specification]}

The format argument index and format specification are optional.

Note
Place colon ahead of the format specification part.
You must prepend '{' with two backslashes to prevent interpretation of the open brace as the format argument reference. <verbatim> \{ </verbatim> Note that if it's followed by closing brace '}', it's not removed and remains in the log message output. The sole string literal is not considered as format string and is not parsed for format argument references. Example:
// Log message consist of format string and one argument.
// Output: {} { some text }
kzLogInfo(MY_LOG_CATEGORY, ("\\{} \\{ {} } { this text is removed ", "some text"));
// Single string literals are not parsed as log message format string.
// Output: This text is string literal. Braces are kept {}, and { this text is remains.
kzLogInfo(MY_LOG_CATEGORY, ("This text is string literal. Braces are kept {}, and { this text is remains."));

The format argument index is a position of the format argument in the argument list. The first format argument has index 0 followed by the argument with index 1 and so on. The last format argument has index N-1 where N is a total number of the format arguments. So, the valid range of the values the argument index may take is 0..N-1.

The format specification part of the format argument reference describes how the referenced argument should be converted to the string when reference is substituted with the string representation of the argument. See Log message argument format specification section for details.

When the log message is written the format argument references found in message format string are replaced with string representation of the corresponding arguments.

In the simplest case the format arguments are referenced by just empty braces '{}':

// Format message arguments referenced on by one with empty braces.
// Output: 1 2 3.
kzLogInfo(MY_LOG_CATEGORY, ("{} {} {}.", 1, 2, 3));
// Output: 1 plus 2 equals 3.
kzLogInfo(MY_LOG_CATEGORY, ("{} plus {} equals {}.", 1, 2, 1+2));

The format arguments could also be referenced using the argument index explicitly:

// Log values in custom order.
// Output: 3 1 2 3 5.
kzLogInfo(MY_LOG_CATEGORY, ("{2} {0} {1} {2} {4}.", 1, 2, 3, 4, 5));
// Log values in custom order using implicit argument indexing.
// Note: The argument reference '{1}' followed by '{}'.
// Output: argument #4 = 5, argument #0 = 1, argument #2 = 3, argument #3 = 4, argument #4 = 5.
kzLogInfo(MY_LOG_CATEGORY, ("argument #4 = {4}, argument #0 = {0}, argument #2 = {2}, argument #3 = {}, argument #4 = {}.", 1, 2, 3, 4, 5));

In the last example you may note that indexed argument reference '{2}' is followed by argument reference without index '{}'. In such a case argument referenced without index is the one (#3 in this case) following the referenced with index (#2 in this case).

Log message argument format specification

As it is mentioned in Log message formating section the log message format argument reference consists of two parts: argument index and format specification. The format specification describes how the log message format argument value is converted to the string and describes the way it is positioned when the message is written to the log. The format argument value type is taken into account when converting the value to the textual representation that makes logging typesafe.

Here is a structure of the format specification:

[align][sign][#][0][width][.precision][specifier]

Where

  • align describes positioning of resulting text:
    • '<' text is left-aligned within the available space.
    • '>' text is right-aligned within the available space (this is the default behaviour).
    • '=' the padding is placed after the sign (if any) but before the digits. This is only valid for numeric types.
    • '^' text is centered within the available space.
  • sign is valid for numeric types only.
    • '+' the sign should be used for both positive and negative numbers.
    • '-' the sign should be used only for negative numbers (this is the default behavior).
    • ' ' the leading space should be used on positive numbers, and a minus sign on negative numbers.
  • '#' is valid for octal or hexidecimal specifier of integer types. If present, the output is prefixed by '0' for 'o' specifier or '0x'/'0X' for 'x'/'X' specifier.
  • '0' pads the number with zeroes to the left instead of spaces when value converted to string consumes less characters than width.
  • width is an integer number describing minimum width for the output text. If output text does not consume whole width then remaning space is padded with spaces or 0 if '0' flag is specified.
  • precision is only valid for floating point types and describes how many digits should be displayed after decimal point in output text.
  • specifier denotes notation to be used when converting format argument value to string. Acceptable specifier values depend on format argument type:
    • for character argument type:
      • 'c' outputs single character (default for signed character type).
      • 'd' outputs the number in base 10.
      • 'u' outputs unsigned number in base 10 (default for unsigned character type).
      • 'o' outputs the number in base 8.
      • 'x' outputs the number in base 16 using lowercase letters a-f.
      • 'X' outputs the number in base 16 using uppercase letters A-F.
    • for integer argument types:
      • 'd' outputs the number in base 10. (default for signed integer types).
      • 'u' outputs unsigned number in base 10 (default for unsigned integer types).
      • 'o' outputs the number in base 8.
      • 'x' outputs the number in base 16 using lower case letters a-f.
      • 'X' outputs the number in base 16 using apper case letters A-F.
    • for floating point argument types:
      • 'e' outputs the number in scientific notation. The letter 'e' denotes the exponent part.
      • 'E' outputs the number in scientific notation. The letter 'E' denotes the exponent part.
      • 'f' outputs the number in decimal floating point notation, lowercase (default for this type).
      • 'F' outputs the number in decimal floating point notation, uppercase.
      • 'g' outputs the number in shortest possible representation: 'e' or 'f'.
      • 'G' outputs the number in shortest possible representation: 'E' or 'F'.
      • 'a' outputs the number in hexadecimal floating point notation, lowercase.
      • 'A' outputs the number in hexadecimal floating point notation, uppercase.
      • 'x' same as 'a'.
      • 'X' same as 'A'.
    • for pointer argument types:
      • 'p' outputs pointer address (default for this type).
Note
If argument type does not match specifier field then default specifier for the argument type is used to convert argument value to string.

If the type of the format argument is a pointer then the Logging subsystem writes to the log the address stored in the pointed. If the type of the format argument is array (T[]) then the Logging subsystem writes to the log the address of the first element of that array. Only string literals of type const char[] or char[] are written to the log as a text.

To write to the log the string pointed to by the const char* or char* pointer you can use string_view object. You can initialize the string_view object with the pointer to the string that you want to log and then use that object as a log format argument. If you pass pointer to the string as a format argument then only the address of that string will be written to the log.

You can use objects of user defined type as log format arguments. The Logging subsystem uses kanzi::logArgumentToString template function to convert objects of user defined type to string. Only align format flag is applicable for user defined types. The Logging subsystem specializes kanzi::logArgumentToString for several user defined types. See Default logArgumentToString specializations.

Examples

To log message using various argument specifiers:

// Log value of 10 in different base systems.
// Output: decimal: 10, octal: 012, hexidecimal: 0xa.
kzLogInfo(MY_LOG_CATEGORY, ("decimal: {}, octal: {:#o}, hexidecimal: {:#x}.", 10, 10, 10));
// Using argument index could be shortened to:
// added in resulting text to octal or hexidecimal presentation.
// Output: decimal: 10, octal: 012, hexidecimal: 0xa.
kzLogInfo(MY_LOG_CATEGORY, ("decimal: {}, octal: {0:#o}, hexidecimal: {0:#x}.", 10));
// Field width is 4 characters.
// Output: decimal: 10.
kzLogInfo(MY_LOG_CATEGORY, ("decimal:{:4}.", 10));
// Field with is 4 characters, left aligned.
// Output: decimal:10 .
kzLogInfo(MY_LOG_CATEGORY, ("decimal:{:<4}.", 10));
// Field with is 4 characters, zero filled.
// Output: decimal:0010.
kzLogInfo(MY_LOG_CATEGORY, ("decimal:{:04}.", 10));
// Field with is 4 characters, with sign and left aligned.
// Output: decimal:+10 .
kzLogInfo(MY_LOG_CATEGORY, ("decimal:{:<+4}.", 10));

To use string format arguments:

const char* message = "Hello world!!!";
// Write message to the log:
// Output: Message: Hello World!!!
kzLogInfo(MY_LOG_CATEGORY, ("Message: {}", string_view(message)));
// Write string literal to the log:
// Output: Message: String literal message.
kzLogInfo(MY_LOG_CATEGORY, ("Message: {}", "String literal message."));