BSD style: see
license.txt
May 2004 : Initial release
Oct 2004: Hierarchy moved due to circular dependencies
Apr 2008: Lazy delegates removed due to awkward usage
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.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 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 argument 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() ¶#
-
Initialize the base hierarchy
- Level convert(char[] name, Level def = Level.Trace) [static] ¶#
-
Return the level of a given name
- Time time() [static] ¶#
-
Return the current time
- Logger root() [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(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.
- char[] convert(int level) [static] ¶#
-
Return text name for a log level
- Hierarchy hierarchy() [static] ¶#
-
Return the singleton hierarchy.
- void formatln(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 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 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
- char[] label() ¶#
-
return a label for this context
- bool enabled(Level setting, Level target) ¶#
-
first arg is the setting of the logger itself, and
the second arg is what kind of message we're being
asked to produce
- Logger next [private] ¶#
- Logger parent [private] ¶#
-
- this(Hierarchy host, char[] name) [private] ¶#
-
Construct a LoggerInstance with the specified name for the
given hierarchy. By default, logger instances are additive
and are set to emit all events.
- bool enabled(Level level = Level.Fatal) [final] ¶#
-
Is this logger enabed for the specified Level?
- bool trace() [final] ¶#
-
Is trace enabled?
- void trace(char[] fmt, ...) [final] ¶#
-
Append a trace message
- bool info() [final] ¶#
-
Is info enabled?
- void info(char[] fmt, ...) [final] ¶#
-
Append an info message
- bool warn() [final] ¶#
-
Is warn enabled?
- void warn(char[] fmt, ...) [final] ¶#
-
Append a warning message
- bool error() [final] ¶#
-
Is error enabled?
- void error(char[] fmt, ...) [final] ¶#
-
Append an error message
- bool fatal() [final] ¶#
-
Is fatal enabled?
- void fatal(char[] fmt, ...) [final] ¶#
-
Append a fatal message
- char[] name() [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() [final] ¶#
-
Is this logger additive? That is, should we walk ancestors
looking for more appenders?
- Logger additive(bool enabled) [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
- TimeSpan runtime() [final] ¶#
-
Get time since this application started
- Logger append(Level level, lazy char[] exp) [final] ¶#
-
Send a message to this logger via its appender list.
- void append(LogEvent event) [private] ¶#
-
Send a message to this logger via its appender list.
- char[] format(char[] buffer, char[] formatStr, ...) [final] ¶#
-
Format text using the formatter configured in the associated
hierarchy
- Logger format(Level level, char[] fmt, TypeInfo[] types, ArgList args) [final] ¶#
-
Format text using the formatter configured in the associated
hierarchy.
- bool isChildOf(char[] candidate) [private, final] ¶#
-
See if the provided Logger name is a parent of this one. Note
that each Logger name has a '.' appended to the end, such that
name segments will not partially match.
- bool isCloserAncestor(Logger other) [private, final] ¶#
-
See if the provided Logger is a better match as a parent of
this one. This is used to restructure the hierarchy when a
new logger instance is introduced
- class Hierarchy : Logger.Context [private] ¶#
-
The Logger hierarchy implementation. We keep a reference to each
logger in a hash-table for convenient lookup purposes, plus keep
each logger linked to the others in an ordered group. Ordering
places shortest names at the head and longest ones at the tail,
making the job of identifying ancestors easier in an orderly
fashion. For example, when propagating levels across descendents
it would be a mistake to propagate to a child before all of its
ancestors were taken care of.
- this(char[] name) ¶#
-
Construct a hierarchy with the given name.
- char[] label() [final] ¶#
-
- bool enabled(Level level, Level test) [final] ¶#
-
- char[] name() [final] ¶#
-
Return the name of this Hierarchy
- void name(char[] name) [final] ¶#
-
Set the name of this Hierarchy
- char[] address() [final] ¶#
-
Return the address of this Hierarchy. This is typically
attached when sending events to remote monitors.
- void address(char[] address) [final] ¶#
-
Set the address of this Hierarchy. The address is attached
used when sending events to remote monitors.
- Logger.Context context() [final] ¶#
-
Return the diagnostic context. Useful for setting an
override logging level.
- void context(Logger.Context context) [final] ¶#
-
Set the diagnostic context. Not usually necessary, as a
default was created. Useful when you need to provide a
different implementation, such as a ThreadLocal variant.
- Logger root() [final] ¶#
-
Return the root node.
- Logger lookup(char[] label) [final] ¶#
-
Return the instance of a Logger with the provided label. If
the instance does not exist, it is created at this time.
Note that an empty label is considered illegal, and will be
ignored.
- int opApply(int delegate(ref Logger) dg) [final] ¶#
-
traverse the set of configured loggers
- Logger inject(char[] label, Logger delegate(char[] name) dg) [private, synchronized] ¶#
-
Return the instance of a Logger with the provided label. If
the instance does not exist, it is created at this time.
- void insert(Logger l) [private] ¶#
-
Loggers are maintained in a sorted linked-list. The order
is maintained such that the shortest name is at the root,
and the longest at the tail.
This is done so that updateLoggers() will always have a
known environment to manipulate, making it much faster.
- void update(Logger changed, bool force = false) [private] ¶#
-
Propagate hierarchical changes across known loggers.
This includes changes in the hierarchy itself, and to
the various settings of child loggers with respect to
their parent(s).
- void propagate(Logger logger, Logger changed, bool force = false) [private] ¶#
-
Propagate changes in the hierarchy downward to child Loggers.
Note that while 'parent' and 'breakpoint' are always forced
to update, the update of 'level' is selectable.
- 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, char[] msg, char[] name) ¶#
-
Set the various attributes of this event.
- char[] toString() ¶#
-
Return the message attached to this event.
- char[] name() ¶#
-
Return the name of the logger which produced this event
- Level level() ¶#
-
Return the logger level of this event.
- Hierarchy host() ¶#
-
Return the hierarchy where the event was produced from
- TimeSpan span() ¶#
-
Return the time this event was produced, relative to the
start of this executable
- Time time() ¶#
-
Return the time this event was produced relative to Epoch
- Time started() ¶#
-
Return time when the executable started
- char[] levelName() ¶#
-
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() [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.
- char[] name() [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() ¶#
-
Create an Appender and default its layout to LayoutSimple.
- Mask register(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) ¶#
-
Set the current layout to be that of the argument, or the
generic layout where the argument is null
- Layout layout() ¶#
-
Return the current Layout
- void next(Appender appender) ¶#
-
Attach another appender to this one
- Appender next() ¶#
-
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() [final] ¶#
-
Return the fingerprint for this class
- char[] name() [final] ¶#
-
Return the name of this class
- void append(LogEvent event) [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() [final] ¶#
-
Return the fingerprint for this class
- char[] name() ¶#
-
Return the name of this class
- void append(LogEvent event) [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, size_t delegate(void[]) dg) ¶#
-
Subclasses should implement this method to perform the
formatting of the actual message content.