std.log

Implements an application level logging mechanism.

The std.log module defines a set of functions useful for many common logging tasks. Five logging severity levels are defined. In the order of severity they are info, warning, error, critical and fatal. Verbose messages are logged using the vlog template.

By default std.log will configure itself using the command line arguments passed to the process and using the process's environment variables. For a list of the default command line options, environment variables and their meaning, see Configuration and FileLogger.Configuration.

Example:
import std.log;

void main(string[] args)
{
    info("You passed %s argument(s)", args.length - 1);
    info.when(args.length > 1).write("Arguments: ", args[1 .. $]);

    warning("This is a warning message.");
    error("This is an error message!");
    dfatal("This is a debug fatal message");

    vlog(1)("Verbosity 1 message");
    vlog(2)("Verbosity 2 message");

    foreach (i; 0 .. 10)
    {
        info.when(every(9))("Every nine");

        if(info.willLog)
        {
            auto message = "Cool message";
            // perform some complex operation
            // ...
            info(message);
        }
    }

    try critical("Critical message");
    catch(CriticalException e)
    {
        // shutdown application...
    }

    fatal("This is a fatal message!!!");
    assert(false, "Never reached");
}

License:
Boost License 1.0.

Authors:
Jose Armando Garcia Sancio

Source:
std/log.d

template log(Severity severity)
alias fatal;
alias dfatal;
alias critical;
alias error;
alias warning;
alias info;
Maps to the LogFilter for the specified severity.

Example:
info("Info severity message");
warning("Warning severity message");
error("Error severity message");
critical("Critical severity message");
dfatal("Fatal message in debug mode and critical message in release mode");
fatal("Fatal severity message");
Description of supported severities.
Severity Description
fatal Logs a fatal severity message. Fatal log messages terminate the application after the message is persisted. Fatal log message cannot be disable at compile time or at run time.
dfatal Logs a debug fatal message. Debug fatal log messages log at fatal severity in debug mode and log at critical severity in release mode. See fatal and critical severity levels for a description of their behavior.
critical Logs a critical severity message. Critical log messages throw a CriticalException exception after the message is persisted. Critical log messages cannot be disable at compile time or at run time.
error Logs an error severity message. Error log messages are disable at compiled time by setting the version to strip_log_error. Error log messages are disable at run time by setting the minimun severity to Severity.fatal or Severity.critical in Configuration. Disabling error log messages at compile time or at run time also disables lower severity messages, e.g. warning and info.
warning Logs a warning severity message. Warning log messages are disable at compiled time by setting the version to strip_log_warning. Warning log messages are disable at run time by setting the minimum severity to Severity.error in Configuration. Disabling warning log messages at compile time or at run time also disables lower severity messages, e.g. info.
info Logs a info severity message. Info log messages are disable at compiled time by setting the version to strip_log_info. Info log messages are disable at run time by setting the minimum severity to Severity.warning in Configuration. Disabling info log messages at compile time or at run time also disables verbose log messages.

auto vlog(string file = __FILE__)(int level);
Verbose log messages are log at the info severity level. To disable them at compile time set the version to strip_log_info which also disables all messages of info severity at compile time. To enable verbose log messages at run time use the Configuration.maxVerboseLevel property and the Configuration.verboseFilter property.

Example:
vlog(1)("A verbose 1 message");

class LogFilter;
Conditionally records a log message by checking the severity level and any user defined condition. Instances of LogFilter are alised by the log and vlog template and the fatal, dfatal, critical, error, warning and info aliases.

Examples:
error("Log an %s message!", Severity.error);
error.write("Log an ", Severity.error, " message!");
error.writef("Also logs an %s message!", Severity.error);
Logs a message if the specified severity level is enable.

void coolFunction(Object object)
{
    fatal.when(object is null)("I don't like null objects!");
    // ...
}

foreach(i; 0 .. 10)
{
    info.when(first())("Only log this one time per thread run");
}
Logs a message if the specified severity level is enable and all the user defined condition are true.

void removeDirectory(string dir = "/tmp/log")
{
    info.when(rich!"!="(dir, "/tmp/log"))("Trying to remove dir");
    // ...
}
Logs a rich message if the specified severity level is enable and all the user defined condition are true.

@property bool willLog();
Returns true if a message to this logger will be recorded.

Example:
if(error.willLog)
{
    string message;
    // Perform some computation
    // ...
    error(message);
}

LogFilter when(lazy bool now);
Returns this object if the parameter now evaluates to true and willLog returns true. Otherwise, it returns an object that will not log messages. Note: The now parameter is only evaluated if willLog returns true.

Example:
foreach(i; 0 .. 10)
{
   warning.when(i == 9)("Executed loop when i = 9");
   // ...
}

LogFilter when(lazy Rich!(bool) now);
Returns this object and appends the log message with a reason if the parameter now evaluates to true and willLog returns true. Otherwise, it returns an object that will not log messages. Note: The now parameter is only evaluated if willLog return true.

Example:
foreach(i; 0 .. 10)
{
   warning.when(rich!"=="(i, 9))("Executed loop when i = 9");
   // ...
}

void write(string file = __FILE__, int line = __LINE__, T...)(lazy T args);
Concatenates all the arguments and logs them. Note: The parameters are only evaluated if willLog returns true.

Example:
auto pi = 3.14159265;

info.write("The value of pi is ", pi);

void writef(string file = __FILE__, int line = __LINE__, T...)(lazy string fmt, lazy T args);
alias opCall;
Formats the parameters args given the format string fmt and logs them. Note: The parameters are only evaluated if willLog evaluates to true. For a description of the format string see std.format.formattedWrite.

Example:
auto goldenRatio = 1.61803399;

vlog(1).writef("The number %s is the golden ratio", goldenRatio);

// The same as above...
vlog(1)("The number %s is the golden ration", goldenRatio);

class CriticalException: object.Exception;
Exception thrown when logging a critical message. See critical.

enum Severity;
Defines the severity levels supported by the logging library. Should be used in conjuntion with the log template. See log for an explanation of their semantic.

fatal
critical
error
warning
info

class Configuration;
Configuration config;
Module configuration.

This object is used to configure the logging module if the default behavior is not wanted.

void parseCommandLine(ref string[] commandLine);
Modifies the configuration object based on the passed parameter.

The function processes every entry in commandLine looking for valid command line options. All of the valid options are enumerated in the fields of this structure that end in 'Flag', e.g. minSeverityFlag. When a valid command line option is found its value is stored in the mapping object's property and it is removed from commandLine. For any property not set explicitly the value used before this call is used. Here is a list of all the flags and how they map to the object's property:

  • minSeverityFlag maps to minSeverity
  • verboseFilterFlag maps to verboseFilter
  • maxVerboseLevelFlag maps to maxVerboseLevel

Example:
import std.log;

void main(string[] args)
{
    // Overwrite the defaults...
    config.minSeverity = Severity.info;
    // ...

    // Parse the command line
    config.parseCommandLine(args);
}
This example overrites the default for the minimum severity property and later configures logging to any configuration option passed through the command line.

Note:
A call to this function is not required if the module will be initialized using the default options.

@property string minSeverityFlag(string minSeverityFlag);
@property string minSeverityFlag();
Command line flag for setting the minimum severity level. The default value is "minloglevel" which at the command line is --minloglevel.

@property string verboseFilterFlag(string verboseFilterFlag);
@property string verboseFilterFlag();
Command line flag for setting the per module verbose filter configuration. The default value is "vmodule" which at the command line is --vmodule.

@property string maxVerboseLevelFlag(string maxVerboseLevelFlag);
@property string maxVerboseLevelFlag();
Command line flag for setting the maximum verbose level. The default value is "v" which at the command line is --v.

@property Severity minSeverity(Severity severity);
@property Severity minSeverity();
Specifies the minimum severity for logging messages.

Only messages with a severity greater than or equal to the value of this property are logged.

Example:
config.minSeverity = Severity.warning
This example will enable logging for messages with severity Severity.fatal, Severity.critical, Severity.error and Severity.warning.

The default value is Severity.error.

@property int maxVerboseLevel(int level);
@property int maxVerboseLevel();
Specifies the maximum verbose level for logging verbose messages.

Verbose messages are logged if their verbose level is less than or equal to the value of this property. This property is ignore if the module logging the verbose message matches an entry specified in the property for per module verbose filtering.

Example:
config.minSeverity = Severity.info;
config.maxVerboseLevel(5);

vlog(4)("Log this message");
vlog(5)("Also log this message");
vlog(6)("Don't log this message");
This example will enable verbose logging for verbose message with a level of 5 or less.

The default value is int.min.

@property string verboseFilter(string vmodule);
@property string verboseFilter();
Specifies the per module verbose filter configuration.

A verbose message with level x gets logged at severity level info if there is an entry that matches the source file, and if the verbose level of that entry is greater than or equal to x.

The format of the configuration string is as follow [pattern]=[level],..., where [pattern] may contain any character allowed in a file name and [level] is convertible to an integer. For an exmplanation of how [pattern] matches the source file please see std.path.globMatch.

For every [pattern]=[level] in the configuration string an entry is created.

Example:
config.verboseFilter = "module=2,great*=3,*test=1";
The code above sets a verbose logging configuration that:
  • Logs verbose 2 and lower messages from 'module{,.d}'
  • Logs verbose 3 and lower messages from anything starting with 'great'
  • Logs verbose 1 and lower messages from any file that ends with 'test{,.d}'

Note:
If the verbose message matches the pattern part of the entry, then the maximum verbose level property is ignored.

For example in the default configuration if the command line contains --minloglevel=info --v=2 --vmodule=web=1.
module web;

// ...

vlog(2)("Verbose message is not logged");
The verbose message above is not logged even though it is less than or equal to 2, as specified in the command line.

The default value is null.

@property void function() fatalHandler(void function() handler);
Function pointer for handling log message with a severity of fatal.

This function is called by the thread trying to log a fatal message. The function handler should not return; otherwise std.log will assert(false).

The default value is function void() {}.

@property shared(Logger) logger(shared(Logger) logger);
@property shared(Logger) logger();
Implementation of the Logger interface used to persiste log messages

This property allows the caller to change and configure the backend logger to a different Logger. It will throw an exception if it is changed after a logging call has been made.

The default value a FileLogger.

Example:
import std.log;

final class NullLogger : Logger
{
   shared void log(const ref LogMessage message) {}
   shared void flush() {}
}

void main(string[] args)
{
   config.logger = new shared(NullLogger);
   // ...
}
This example disables writing log messages at run time.

class FileLogger: std.log.Logger;
Default Logger implementation.

This logger implements all the configuration option described in FileLogger.Configuration. This logger writes log messages to multiple files. There is a file for every severity level. Log messages of a given severity are written to all the log files of an equal or lower severity. E.g. A log message of severity warning will be written to the log files for warning and info but not to the log files for fatal and error.

struct Configuration;
Structure for configuring the default backend logger.

void parseCommandLine(ref string[] commandLine);
Modifies the configuration object based on the passed parameter.

The function processes every entry in commandLine looking for valid command line options. All of the valid options are enumerated in the fields of this structure that end in 'Flag', e.g. logToStderrFlag. When a valid command line option is found its value is stored in the mapping object's property and it is removed from commandLine. For any property not set explicitly its default value is used. Here is a list of all the flags and how they map to the object's property:

  • logToStderrFlag maps to logToStderr
  • alsoLogToStderrFlag maps to alsoLogToStderr
  • stderrThresholdFlag maps to stderrThreshold
  • logDirectoryFlag maps to logDirectory

The name property is set to the program name, for example the first element of commandLine.

Example:
void main(string[] args)
{
    auto loggerConfig = FileLogger.Configuration.create();

    // overwrite some default values
    loggerConfig.logDirectory = "/tmp/" ~ args[0];

    // Parse the command line
    loggerConfig.parseCommandLine(args);

    config.logger = new shared(FileLogger(loggerConfig));
}
This example overwrites the default log directory and later configures the file logger to any configuration option passed through the command line.

@property string logToStderrFlag(string logToStderrFlag);
const const @property string logToStderrFlag();
Command line flag for logging to stderr. The default value is "logtostderr" which at the command line is --logtostderr.

@property string alsoLogToStderrFlag(string alsoLogToStderrFlag);
const const @property string alsoLogToStderrFlag();
Command line flag for logging to stderr and files. The default value is "alsologtostderr" which at the command line is --alsologtostderr.

@property string stderrThresholdFlag(string stderrThresholdFlag);
const const @property string stderrThresholdFlag();
Command line flag for setting the stderr logging threshold. The default value is "stderrthreshold" which at the command line is --stderrthreshold.

@property string logDirectoryFlag(string logDirectoryFlag);
const const @property string logDirectoryFlag();
Command line flag for setting the logging directory. The default value is "logdir" which at the command line is --logdir.

static Configuration create();
Creates a default file logger configuration.

@property string name(string name);
const const @property string name();
Name to use when generating log file names.

The default value is the program name.

@property bool logToStderr(bool logToStderr);
const const @property bool logToStderr();
Specifies if the logger should write to stderr. If this property is set, then it only logs to stderr and not to files.

The default value is false.

@property bool alsoLogToStderr(bool alsoLogToStderr);
const const @property bool alsoLogToStderr();
Specifies if the logger should also write to stderr. If this property is set, then it logs to stderr and to files.

The default value is false.

@property Severity stderrThreshold(Severity threshold);
const const @property Severity stderrThreshold();
Specifies the threshold at which log messages are logged to stderr. Any message with a severity higher or equal to threshold is written to stderr.

The default value is Severity.error.

@property string logDirectory(string logDirectory);
const const @property string logDirectory();
Specifies the directory where log files are created.

The default value for this property is the value in the environment variable LOGDIR. If LOGDIR is not set, then TEST_TMPDIR is used. If TEST_TMPDIR is not set, then it logs to the current directory.

@property size_t bufferSize(size_t bufferSize);
const const @property size_t bufferSize();
Specifies the buffer size for each log file.

The default value is 4KB.

@property string lineFormat(string format);
const const @property string lineFormat();
Specifies the format for every log line.

The attributes of a log line are logged by placing % directives in the format string.

Directives are mapped to logging values as follow.
Directive Semantics
%% The percent sign.
%{...}t The time when the log line was generated.
%i The id of the thread which generated the log line.
%s The severity of the log line.
%f The name of the file which generated the log line.
%l The line number which generated the log line.
%m The log message.

The directive %t is the same as %{%m%d %H:%M:%S}t as described below.

Directives inside the curly brackets in %{...}t are mapped as follows.
Directive Semantics
%% The percent sign.
%m The month as a decimal number.
%d The day of the month as a decimal number.
%Y The year as a decimal number including the century.
%H The hour as a decimal number using a 24-hour clock.
%M The minute as a decimal number.
%S The second as a decimal number.

The default value is "%s%t %i %f:%l] %m".

@property dstring severitySymbols(dstring symbols);
const const @property dstring severitySymbols();
Specifies the symbols to use for each severities when writing to file.

The value of the severities as define in Severity is used to index into the string. The length of the string must equal Severity.max + 1.

Example:
auto loggerConfig = FileLogger.Configuration.create();
loggerConfig.severitySymbols = "12345";
assert(loggerConfig.severitySymbols[Severity.fatal] == '1');
The default value is "FCEWI".

@property string[] fileNamePrefixes(string[] prefixes);
const const @property const(immutable(char)[][]) fileNamePrefixes();
Specifies the prefix for the name of the log files.

The parameter should either by null or be a length of Severity.max + 1.

If the value is not null the value stored in prefixes[i] will be used as the prefix for severity i, where i is a value defined in Severity. For example the file name for severity error will have the prefix fileNamePrefixes[Severity.error]. If an entry in the array contains the empty string, then no log file is created for that severity.

If the value is null then log file names are [program].[hostname].[user].[severity].log.[datetime].[pid]. For example if the program is hello, the host name is example.com and the user name is guest then the file name for severity info will be: hello.example.com.guest.INFO.log.20110609T050018Z.743.

The default value is null.

Example:
import std.log;

void name(string[] args) {
  auto loggerConfig = FileLogger.Configuration.create();
  loggerConfig.fileNamePrefixes = ["", "", "", "", args[0]];

  config.logger = new shared(FileLogger(loggerConfig));
}
The example above will log every log message to one file with the name [program].log.[datetime].[pid].

@property string fileNameExtension(string extension);
const const @property string fileNameExtension();
Specifies the extension for the name of log files.

The default value is ".log".

this(Configuration loggerConfig);
Constructs a logger with the configuration specified in loggerConfig.

shared void log(ref const LogMessage message);
Writes a log message to all the log files of equal or lower severity.

shared void flush();
Flushes the buffer of all the log files.

abstract interface Logger;
Extension point for the module.

abstract shared void log(ref const LogMessage message);
Logs a message.

The method is called by std.log whenever it decides that a message should be logged. It is not required that the implementation of this method do any filtering based on severity since at this point all configured filters were performed.

The method is allow to return immediately without persisting the message.

abstract shared void flush();
Flushes pending log operations.

The method is called by std.log whenever it requires the persistence of all the previous messages. For example the method is called when the client logs a fatal message.

The method must not return until all pending log operations complete.

struct LogMessage;
Log message constructed by std.log and passed to the Logger for recording.

string file;
Name of the source file that created the log message.

int line;
Line number in the source file that created the log message.

Severity severity;
Severity of the log message.

ulong threadId;
Thread that created the log message.

char[] message;
User defined message.

SysTime time;
Time when the log message was created.

Rich!(bool) every(string file = __FILE__, int line = __LINE__)(uint n);
Rich!(bool) every(string file = __FILE__, int line = __LINE__)(Duration n);
The first version of this function returns true once every n times it is called at a specific call site; otherwise it returns false.

The second version of this function return true only after n unit of time has passed after the previous call from a specific call site returned true; otherwise it returns false. The first call returns true.

Example:
auto firstCounter = 0;
auto secondCounter = 0;

foreach(i; 0 .. 10)
{
    if(every(2)) firstCounter += i;

    if(every(3)) secondCounter += i;
}
assert(firstCounter == 20); // 0 + 2 + 4 + 6 + 8
assert(secondCounter == 18); // 0 + 3 + 6 + 9

foreach(i; 0 .. 3)
{
    if(every(dur!"msecs"(40))) assert(i == 0 || i == 2);
    Thread.sleep(dur!"msecs"(21));
}

Rich!(bool) first(string file = __FILE__, int line = __LINE__)(uint n = 1);
Rich!(bool) first(string file = __FILE__, int line = __LINE__)(Duration n);
The first version of this function returns true the first n times it is called at a specific call site; otherwise it returns false.

The second version of this function returns true every time it is called in the first n unit of time at a specific call site; otherwise it returns false.

Example:
auto firstCounter = 0;
auto secondCounter = 0;

foreach(i; 0 .. 10)
{
    if(first(2)) firstCounter += i;

    if(first(3)) secondCounter += i;
}
assert(firstCounter == 1); // 0 + 1
assert(secondCounter == 3); // 0 + 1 + 2

foreach(i; 0 .. 3)
{
    if(first(dur!"msecs"(40))) assert(i == 0 || i == 1);
    Thread.sleep(dur!"msecs"(21));
}

Rich!(bool) after(string file = __FILE__, int line = __LINE__)(uint n);
Rich!(bool) after(string file = __FILE__, int line = __LINE__)(Duration n);
The first version of this function returns true after it is called n time at a specific call site.

The second version of this function returns true after n unit of time has passed since the first call at a specific call site.

Example:
auto firstCounter = 0;
auto secondCounter = 0;

foreach(i; 0 .. 10)
{
    if(after(8)) firstCounter += i;

    if(after(7)) secondCounter += i;
}
assert(firstCounter == 17); // 8 + 9
assert(secondCounter == 24); // 7 + 8 + 9

foreach(i; 0 .. 3)
{
    if(after(dur!"msecs"(40))) assert(i == 2);
    Thread.sleep(dur!"msecs"(21));
}

template rich(string exp) if (isBinaryOp(exp))
template rich(string exp) if (exp == "!")
struct Rich(Type) if (is(Type == bool));
Rich data type

Defines a data type for bool which behaves just like a bool but support the pretty printing and analysis of why the variable got its value.

The rich template support both binary (e.g. ==, >, etc) and unary (!) operations. For binary operations the call rich!"op"(a, b) is translated to a op b. For the unary operation the call rich!"!"(a) is translated to !a. The supported operations are: ==, !=, >, >=, <, <=, &&, || and !.

Example:
auto value = rich!"=="(1, 1);
assert(value);
assert(value.reason == "true = (1 == 1)");