tango.util.log.Log

License:

BSD style: see license.txt

Version:

May 2004 : Initial release

Version:

Oct 2004: Hierarchy moved due to circular dependencies

Version:

Apr 2008: Lazy delegates removed due to awkward usage

Author:

Kris

Simplified, pedestrian usage:
1
2
3
4
import tango.util.log.Config;

Log ("hello world");
Log ("temperature is {} degrees", 75);

Generic usage:

Loggers are named entities, sometimes shared, sometimes specific to a particular portion of code. The names are generally hierarchical in nature, using dot notation (with '.') to separate each named section. For example, a typical name might be something like "mail.send.writer"
1
2
3
4
5
6
7
8
import tango.util.log.Log;

auto log = Log.lookup ("mail.send.writer");

log.info  ("an informational message");
log.error ("an exception message: {}", exception);

etc ...

It is considered good form to pass a logger instance as a function or class-ctor argument, or to assign a new logger instance during static class construction. For example: if it were considered appropriate to have one logger instance per class, each might be constructed like so:
1
2
3
4
5
6
private Logger log;

static this()
{
    log = Log.lookup (nameOfThisClassOrStructOrModule);
}

Messages passed to a Logger are assumed to be either self-contained or configured with "{}" notation a la Layout & Stdout:
1
log.warn ("temperature is {} degrees!", 101);

Note that an internal workspace is used to format the message, which is limited to 2000 bytes. Use "{.256}" truncation notation to limit the size of individual message components, or use explicit formatting:
1
2
3
char[4096] buf = void;

log.warn (log.format (buf, "a very long message: {}", someLongMessage));

To avoid overhead when constructing arguments passed to formatted messages, you should check to see whether a logger is active or not:
1
2
if (log.warn)
    log.warn ("temperature is {} degrees!", complexFunction());

tango.log closely follows both the API and the behaviour as documented at the official Log4J site, where you'll find a good tutorial. Those pages are hosted over here.
alias ILogger.Level Level
These represent the standard LOG4J event levels. Note that Debug is called Trace here, because debug is a reserved word in D
struct Log [public]
Manager for routing Logger calls to the default hierarchy. Note that you may have multiple hierarchies per application, but must access the hierarchy directly for root() and lookup() methods within each additional instance.
static this() [shared]
Initialize the base hierarchy
Level convert(const(char[]) name, Level def = Trace) [static]
Return the level of a given name
Time time() [@property, static]
Return the current time
Logger root() [@property, static]
Return the root Logger instance. This is the ancestor of all loggers and, as such, can be used to manipulate the entire hierarchy. For instance, setting the root 'level' attribute will affect all other loggers in the tree.
Logger lookup(const(char[]) name) [static]
Return an instance of the named logger. Names should be hierarchical in nature, using dot notation (with '.') to separate each name section. For example, a typical name might be something like "tango.io.Stdout".
If the logger does not currently exist, it is created and inserted into the hierarchy. A parent will be attached to it, which will be either the root logger or the closest ancestor in terms of the hierarchical name space.
const(char)[] convert(int level) [static]
Return text name for a log level
Hierarchy hierarchy() [static]
Return the singleton hierarchy.
void formatln(const(char[]) fmt, ...) [static]
Pedestrian usage support, as an alias for Log.root.info()
void config(OutputStream stream, bool flush = true) [static]
Initialize the behaviour of a basic logging hierarchy.
Adds a StreamAppender to the root node, and sets the activity level to be everything enabled.
class Logger : ILogger [public]
Loggers are named entities, sometimes shared, sometimes specific to a particular portion of code. The names are generally hierarchical in nature, using dot notation (with '.') to separate each named section. For example, a typical name might be something like "mail.send.writer"
1
2
3
4
5
6
7
8
import tango.util.log.Log;format

auto log = Log.lookup ("mail.send.writer");

log.info  ("an informational message");
log.error ("an exception message: {}", exception.toString);

etc ...
It is considered good form to pass a logger instance as a function or class-ctor argument, or to assign a new logger instance during static class construction. For example: if it were considered appropriate to have one logger instance per class, each might be constructed like so:
1
2
3
4
5
6
private Logger log;

static this()
{
    log = Log.lookup (nameOfThisClassOrStructOrModule);
}

Messages passed to a Logger are assumed to be either self-contained or configured with "{}" notation a la Layout & Stdout:
1
log.warn ("temperature is {} degrees!", 101);

Note that an internal workspace is used to format the message, which is limited to 2048 bytes. Use "{.256}" truncation notation to limit the size of individual message components. You can also use your own formatting buffer:
1
2
3
log.buffer (new char[](4096));

log.warn ("a very long warning: {}", someLongWarning);

Or you can use explicit formatting:
1
2
3
char[4096] buf = void;

log.warn (log.format (buf, "a very long warning: {}", someLongWarning));

To avoid overhead when constructing argument passed to formatted messages, you should check to see whether a logger is active or not:
1
2
if (log.enabled (log.Warn))
    log.warn ("temperature is {} degrees!", complexFunction());

The above will be handled implicitly by the logging system when macros are added to the language (used to be handled implicitly via lazy delegates, but usage of those turned out to be awkward).

tango.log closely follows both the API and the behaviour as documented at the official Log4J site, where you'll find a good tutorial. Those pages are hosted over here.
interface Context
Context for a hierarchy, used for customizing behaviour of log hierarchies. You can use this to implement dynamic log-levels, based upon filtering or some other mechanism
const(char)[] label() [@property, const]
return a label for this context
bool enabled(Level setting, Level target) [const]
first arg is the setting of the logger itself, and the second arg is what kind of message we're being asked to produce
bool enabled(Level level = Fatal) [final]
Is this logger enabed for the specified Level?
bool trace() [final]
Is trace enabled?
void trace(const(char[]) fmt, ...) [final]
Append a trace message
bool info() [final]
Is info enabled?
void info(const(char[]) fmt, ...) [final]
Append an info message
bool warn() [final]
Is warn enabled?
void warn(const(char[]) fmt, ...) [final]
Append a warning message
bool error() [final]
Is error enabled?
void error(const(char[]) fmt, ...) [final]
Append an error message
bool fatal() [final]
Is fatal enabled?
void fatal(const(char[]) fmt, ...) [final]
Append a fatal message
const(char)[] name() [@property, final]
Return the name of this Logger (sans the appended dot).
Level level() [final]
Return the Level this logger is set to
Logger level(Level l) [final]
Set the current level for this logger (and only this logger).
Logger level(Level level, bool propagate) [final]
Set the current level for this logger, and (optionally) all of its descendents.
bool additive() [@property, final, const]
Is this logger additive? That is, should we walk ancestors looking for more appenders?
Logger additive(bool enabled) [@property, final]
Set the additive status of this logger. See bool additive().
Logger add(Appender another) [final]
Add (another) appender to this logger. Appenders are each invoked for log events as they are produced. At most, one instance of each appender will be invoked.
Logger clear() [final]
Remove all appenders from this Logger
char[] buffer() [@property, final]
Get the current formatting buffer (null if none).
Logger buffer(char[] buf) [@property, final]
Set the current formatting buffer.
Set to null to use the default internal buffer.
TimeSpan runtime() [@property, final, const]
Get time since this application started
Logger append(Level level, lazy const(char[]) exp) [final]
Send a message to this logger via its appender list.
char[] format(char[] buffer, const(char[]) formatStr, ...) [final]
Return a formatted string from the given arguments
Logger format(Level level, const(char[]) fmt, TypeInfo[] types, ArgList args) [final]
Format and emit text from the given arguments
struct LogEvent [package]
Contains all information about a logging event, and is passed around between methods once it has been determined that the invoking logger is enabled for output.
Note that Event instances are maintained in a freelist rather than being allocated each time, and they include a scratchpad area for EventLayout formatters to use.
void set(Hierarchy host, Level level, const(char[]) msg, const(char[]) name)
Set the various attributes of this event.
const(char)[] toString() [const]
Return the message attached to this event.
const(char)[] name() [@property, const]
Return the name of the logger which produced this event
Level level() [@property, const]
Return the logger level of this event.
Hierarchy host() [@property]
Return the hierarchy where the event was produced from
TimeSpan span() [@property, const]
Return the time this event was produced, relative to the start of this executable
const(Time) time() [@property, const]
Return the time this event was produced relative to Epoch
const(Time) started() [@property]
Return time when the executable started
const(char)[] levelName() [@property]
Return the logger level name of this event.
char[] toMilli(char[] s, TimeSpan time) [static]
Convert a time value (in milliseconds) to ascii
class Appender [public]
Base class for all Appenders. These objects are responsible for emitting messages sent to a particular logger. There may be more than one appender attached to any logger. The actual message is constructed by another class known as an EventLayout.
interface Layout
Interface for all logging layout instances
Implement this method to perform the formatting of message content.
Mask mask() [@property, const, abstract]
Return the mask used to identify this Appender. The mask is used to figure out whether an appender has already been invoked for a particular logger.
const(char)[] name() [@property, const, abstract]
Return the name of this Appender.
void append(LogEvent event) [abstract]
Append a message to the output.
this()
Create an Appender and default its layout to LayoutSimple.
static this() [shared]
Create an Appender and default its layout to LayoutSimple.
Level level() [@property, final]
Return the current Level setting
Appender level(Level l) [@property, final]
Return the current Level setting
Mask register(const(char)[] tag) [protected]
Static method to return a mask for identifying the Appender. Each Appender class should have a unique fingerprint so that we can figure out which ones have been invoked for a given event. A bitmask is a simple an efficient way to do that.
void layout(Layout how) [@property]
Set the current layout to be that of the argument, or the generic layout where the argument is null
Layout layout() [@property]
Return the current Layout
void next(Appender appender) [@property]
Attach another appender to this one
Appender next() [@property]
Return the next appender in the list
void close()
Close this appender. This would be used for file, sockets, and such like.
class AppendNull : Appender [public]
An appender that does nothing. This is useful for cutting and pasting, and for benchmarking the tango.log environment.
this(Layout how = null)
Create with the given Layout
Mask mask() [@property, override, final, const]
Return the fingerprint for this class
const(char)[] name() [@property, override, final, const]
Return the name of this class
void append(LogEvent event) [override, final]
Append an event to the output.
class AppendStream : Appender [public]
Append to a configured OutputStream
this(OutputStream stream, bool flush = false, Appender.Layout how = null)
Create with the given stream and layout
Mask mask() [@property, override, final, const]
Return the fingerprint for this class
const(char)[] name() [@property, override, const]
Return the name of this class
void append(LogEvent event) [override, final]
Append an event to the output.
class LayoutTimer : Appender.Layout [public]
A simple layout comprised only of time(ms), level, name, and message
void format(LogEvent event, scope size_t delegate(const(void)[]) dg)
Subclasses should implement this method to perform the formatting of the actual message content.