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
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"
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:
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:
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:
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:
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.
$(DDOC_MODULE_MEMBERS
alias
Arg
;
Platform issues ...
alias
ArgList
;
Platform issues ...
alias
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
;
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 Level
convert
(char[] name, Level def = cast(Level)0);
- Return the level of a given name
- static Time
time
();
- Return the current
time
- static Logger
root
();
- 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.
- static Logger
lookup
(char[] name);
- 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.Buffer".
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.
- static char[]
convert
(int level);
- Return text name for a log level
- static Hierarchy
hierarchy
();
- Return the singleton
hierarchy
.
- static void
config
(OutputStream stream, bool flush = true);
- 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
: tango.util.log.model.ILogger.ILogger;
$(DDOC_DECL_DD 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"
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:
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:
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:
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:
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
- abstract char[]
label
();
- return a
label
for this context
- abstract 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
- final bool
enabled
(Level level = cast(Level)4);
- Is this logger enabed for the specified Level?
- final bool
trace
();
- Is
trace
enabled?
- final void
trace
(char[] fmt,...);
- Append a
trace
message
- final bool
info
();
- Is
info
enabled?
- final void
info
(char[] fmt,...);
- Append an
info
message
- final bool
warn
();
- Is
warn
enabled?
- final void
warn
(char[] fmt,...);
- Append a warning message
- final bool
error
();
- Is
error
enabled?
- final void
error
(char[] fmt,...);
- Append an
error
message
- final bool
fatal
();
- Is
fatal
enabled?
- final void
fatal
(char[] fmt,...);
- Append a
fatal
message
- final char[]
name
();
- Return the
name
of this Logger (sans the appended dot).
- final Level
level
();
- Return the Level this logger is set to
- final Logger
level
(Level l);
- Set the current
level
for this logger (and only this logger).
- final Logger
level
(Level
level
, bool propagate);
- Set the current
level
for this logger, and (optionally) all
of its descendents.
- final bool
additive
();
- Is this logger
additive
? That is, should we walk ancestors
looking for more appenders?
- final Logger
additive
(bool enabled);
- Set the
additive
status of this logger. See bool
additive
().
- final Logger
add
(Appender another);
- 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.
- final Logger
clear
();
- Remove all appenders from this Logger
- final TimeSpan
runtime
();
- Get time since this application started
- final Logger
append
(Level level, lazy char[] exp);
- Send a message to this logger via its appender list.
- final char[]
format
(char[] buffer, char[] formatStr,...);
- Format text using the formatter configured in the associated
hierarchy
- final Logger
format
(Level level, char[] fmt, TypeInfo[] types, void* args);
- Format text using the formatter configured in the associated
hierarchy.
struct
LogEvent
;
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.
- static char[]
toMilli
(char[] s, TimeSpan time);
- Convert a time value (in milliseconds) to ascii
class
Appender
;
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.
- abstract Mask
mask
();
- 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.
- abstract char[]
name
();
- Return the
name
of this Appender.
- abstract void
append
(LogEvent event);
- Append a message to the output.
- this();
- Create an Appender and default its layout to LayoutSimple.
- protected Mask
register
(char[] tag);
- 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
: tango.util.log.Log.Appender;
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
- final Mask
mask
();
- Return the fingerprint for this class
- final char[]
name
();
- Return the
name
of this class
- final void
append
(LogEvent event);
- Append an event to the output.
class
AppendStream
: tango.util.log.Log.Appender;
Append to a configured OutputStream
- this(OutputStream stream, bool flush = false, Appender.Layout how = null);
- Create with the given stream and layout
- final Mask
mask
();
- Return the fingerprint for this class
- char[]
name
();
- Return the
name
of this class
- final void
append
(LogEvent event);
- Append an event to the output.
class
LayoutTimer
: tango.util.log.Log.Appender.Layout;
A simple layout comprised only of time(ms), level, name, and message
- void
format
(LogEvent event, void delegate(void[]) dg);
- Subclasses should implement this method to perform the
formatting of the actual message content.
|