1 Introduction

Introduction

NOTE - Because of some mishap with QuickLisp, June 2013 QuickLisp distribution
pulled the master branch of Log4CL instead of stable branch as intended.

Very few incompatibilities been reported, and it makes no sense to downgrade
version that been already available in QuickLisp, therefore QuickLisp will
continue to pull the master branch from now on.

The major difference of Log4CL 1.1.x version from 1.0.x is the Emacs/Slime integration
module, called Log4Slime. This document is written with assumption that you will
have Log4Slime loaded and enabled in Emacs.

Installation

Log4CL is available from QuickLisp. To load it use (ql:quickload :log4cl)
command from REPL. Log4Slime is available in QuickLisp since June 2013.

You can intermix strings and expressions, and expressions will be
printed as their un-evaluated form as well as the their value;
using a constant FORMAT control string as first argument
automatically switches to FORMAT mode.

Log statements without arguments, turn into conditional expression
that tells you if logging is enabled or not

The log output contains some headers in addition to the raw log
message, such as the log level that message was submitted with,
the time of the message as well as what looks like the name of the
current package, and (If you have Log4Slime loaded and turned on),
these headers use different faces from actual log message.

Changing the log level

You can change the log level with by doing
(log:config :debug) from REPL. Alternatively, with
Log4Slime enabled in REPL buffer, you can right-click on the
cl-user part and change the log level from a popup menu.

There is a slight difference between doing it using above two
methods, with log:config command, the level is changed for the
ROOTcategory, but right clicking on the package
name, changes the log level only for that package.

To change the ROOTcategory from Emacs, you can use Log4CL
dropdown submenu, or Emacs command log4slime-level-selection which
is bound to C-c C-g by default.

After pressing C-c C-g which invokes the log4slime-level-selection command
you get the following window.

Pressing "p" to select the package category shows effective log level
and allows you to change like so

This concludes the very basic introduction, if you were confused by
what various terms such as "category" mean, click on the hyperlink
to read more about Log4CL concepts.

Or you can skip the theory and just continue to learn by example.

Automatic category naming

Try putting the from the previous section into a DEFUN instead of a
PROGN form like so:

If you run it now, the output under both SBCL and CCL should
look like this.

Right click on the blue function name, allows you to change the log
level for that specific function.

That is because Log4CL logging macros, automatically determine the
category for logging, based on the context where log statement
appears. In above example the function was defined in the package
CL-USER and function name was HELLO, so the target category of any
logging inside the function, was automatically CL-USER.HELLO

It starts with the package, then function. You can try
putting one of the log statements inside of a LABELS or FLET
forms, to see what happens.

Also note the farthest to the right in the logging category
name, the more specific. The level for "hello" overrides that for
"cl-user", which in turn overrides that of the root category.

Naming in source files

For the next few examples, it is recommended that you load the
examples come together with Log4CL, by doing (ql:quickload :log4cl-examples)

It should produce the following output:

One thing you should notice, is that source file where function is
defined now appears as part of the log message too. Go to the source
of "greetings". Before you try to use Slime's famous M-. shortcut, try
clicking on blue "greetings" word with a left mouse button.

If everything went better then expected, it should land you at the first
log statement of the (defun greetings ()). Cool eh?

Naming in CLOS methods

Quickly browse through naming-examples.lisp. There are a few methods defined,
including :after/:around methods, as well as some with EQL specializers.

Run a few of them from REPL, like so:

Log statements inside of methods, are using the category name of the
generic function, extended with qualifier, and all non-T specializers.

Try going to the source of the above methods by clicking on them. It should land
in the right method, without showing Slime's XREF window.

Note how by changing the level of the foobar you control all the
methods, but can override them based on their specializers. Try
setting :after category to different levels, to control all
the :after methods together.

In addition to playing with methods, try (setf (test.package.one:greetings) "Hey") too.

Context sensitivity

As you browse through source, and are inside of one of the methods,
check out the Log4CL dropdown menu. Note that "Defun" submenu changes
for each method.

Keyboard level selection

Also try C-c C-g shortcut in the same place. You can configure it
not to show the selection window at all, by customizing the
log4slime-level-selection-single-key Emacs variable.

After pressing C-c C-g while inside of the method

You can change keys for the selecting various levels by doing M-x customize-group RET log4slime RET

Note that keyboard selection ignores the Control key so C-c C-g p u is same as C-c C-g C-p C-u

Resetting the mess

If you had forgotten which levels you set for what, and just want
to see which levels are set where.

You can display current logging configuration by doing
(log:config) without any arguments, it willdisplay a tree

If you have had set a lot of custom levels, and now need to get rid
of them, "Reset Children" menu item will nukes the log level from
everything underneath the parent. Doing "Reset Children" on the
ROOT category, gets rid of every other log level that was set
anywhere. Keyboard equivalent is C-c C-g r

Logging configurations

After setting the log levels of a few methods, try doing (log:save :foo)
then messing around.. You can restore the named configuration with
(log:restore :foo). Configurations are saved in a file in the
home directory, so they survive image restarts

Pattern Layout

Common Practices

Some common recipes.

Log levels for production

Generally log levels INFO and below, are used in normal
operations of software, while levels higher then INFO are used
by programmers.

FATAL is used for un-recoverable errors, that
require restart of an application or major component, the FATAL
messages are to inform the user that something had died in a
way that should not normally happen.

ERROR is for serious but generally recoverable errors, that occur
doing a normal operation of software. File not found, or such.

WARN is for "suspicious" things, or to inform the user that
some automatic corrective action had failed. Maximum number of retries reached
or such.

INFO is for informing on major steps that software is performing, and
is usually thought of the maximum log level used in normal operations, its
"Say what you are doing but don't flood" type of messages.

By default Log4CL is configured with root category having INFO
log level.

Log levels for development

DEBUG is for for informing about detailed steps taken by operations
and printing intermediate values.

TRACE is for very detailed debugging, like printing variables inside
loops and such.

DEBU1..DEBU9 log levels are numerically around the TRACE and can be used
if you need more granularity. One possibility is that (log:expr) macro, can
be configured via LOG:PACKAGE-OPTIONS mechanism, to use different
log level then DEBUG and can set to use one of the extra levels.

OFF log level is very important counter-part for DEBUG and
TRACE. Its used for "narrowing things down in reverse", which is
described in the next section

Finding needle in a haystack

Programmers often need to concentrate on a specific area of their
software. With traditional non-hierarchical logging system,
having a lot of debug sprinkled around the code, flood the
programmers with a lot of information they don't need, and makes
it hard to find the messages relevant to the problem being
debugged.

Because Log4CL is hierarchical, its easy to narrow down the
logging, to focus on exactly the right area, by using the
following process.

Turn DEBUG on for the root category, or entire package and
then run your code through the functionality that you are
focusing on. REPL will fill with a lot of debugging output.

Right-click on each message that is not related to a problem,
and turn the corresponding category OFF. You can how go wide
or narrow, turn off entire packages or source files, or by
individual methods, functions or local functions. If you went
too far, use Reset children command on the parent category.

If you use CLOS, use the category hierarchy to your advantage,
if for example you think problem relates to before or after
method, you can can control logging for all :AFTER methods of
generic function by clicking :after category in
(<gf name> :after <specializer> ...)

Once you narrowed down the logging to your liking, you can
quickly save that configuration of log levels with
(LOG:SAVE), and later (may be in a different image, or even
different machine) restore it with (LOG:RESTORE), and you can
give these saved configuration names, such as
(LOG:SAVE :bug-123)

Glossary

Very small glossary of Log4CL concepts

Loggers and categories

Loggers are named singleton objects that form a hierarchy, and are
sources of log messages, or more correctly entry points where log
message enter the logging system. Each call to a logging macro like
(log:debug ...) operates on a specific logger object
(See also naming section).

Logger's unique name is called "logger's category", or "category
name". Loggers form a hierarchy, based on their category names,
where child loggers have their category name prefixed by that of the
parent, followed by a dot. So if we have loggers A, A.B, A.B.C
and A.B.D then logger A is parent of A.B, which has two
children A.B.C and A.B.D - as shown on below diagram. (Note:
ROOT logger category name is empty string)

ROOT---A---A.B---A.B.C
|
\---A.B.D

Because loggers are singletons, logger category name is usually shortened to just
CATEGORY and is used inter-changeably with the word LOGGER; the convention
is that thing is "a logger" when talking about actual Lisp object, and
"category" otherwise.

Each logger can have a log level threshold, or if its
does not have one, it inherits one from its parent. To ensure that
for any logger, an effective log level can be determined, the ROOT
logger always have a level.

Loggers will only pass through messages, if logger's threshold level
is equal or greater verbosity, then log message. For example if in
above example logger A is configured with info log level, then
(log:warn ...) and (log:info) messages will be passed through,
but (log:debug) messages would not.

Appenders

Appenders process log messages by writing them to files, or
displaying them on the screen. Appenders attach to a specific
logger, and each logger can have many appenders attached.

When a log message passes through a logger that has appenders, they
are all called in turn to do appender specific processing, be it
writing log message to a file, or a terminal. After all of logger's
appenders had processed the message, its passed on to the parent
logger.

So log messages inheritance flows in reverse order from the log
level one, tricking up from child loggers towards root, with below
exception.

Each logger has a property called additivity, which is T by
default, which controls the above process. When additivity is
NIL, logger is called non-additive and any messages that reach
it, will not be passed to the parents.

Usually only root logger, or non non-additive loggers will have any
appenders attached to them.

Layouts

When appender decide they want to process the log message, they format
the log message by means of a layout. Layout is a separate object, that attaches
to each appender, and is responsible for the textual formatting of the message.

So while appender provides and manages any serialization for the
stream to write to, the layout is actually formatting the log
message into that stream.

Log4CL provides two layouts, SIMPLE-LAYOUT which is well, simple,
and a very configurable PATTERN-LAYOUT, which specifies the formatting
of log messages by mean of printf/format like control string.

Easiest way to use the pattern layout, is by using LOG:CONFIG
command to select between several predefined formats.

Or you can look for list of all supported format documentation for
the PATTERN-LAYOUT class. Please note that if you are
drafting your own format, that Log4SLime fontification relies on
regular expressions and the log messages being in a certain
order. If your layout is not a minor modification of an built-in
one, the Log4Slime fontification may stop working. You can of
course adjust the regular expressions used by Log4Slime to match
your own custom layout to compensate.

Log Levels

In Log4CL log levels are numeric constants, in order of increased
verbosity:

Turn off logging 0=OFF

Standard log levels 1=FATAL, 2=ERROR, 3=WARN, 4=INFO, 5=DEBUG

Extra debug levels 6..9 named DEBU1 through DEBU4

Standard log level 10=TRACE

Extra debug level 11..15 named DEBU5 through DEBU9

Effective log level

Effective log level of the logger X is determined as follows.

If logger has level threshold set, then this level is the effective log level.

If logger is not first child of a parent, whose category is same as the package
name logger was instantiated from, the effective log level of X is the effective
log level of its parent logger.

If logger is first child of a parent P named same as package,
and there exists a sibling logger S, with the last part of
category name equal to that of a source file logger X was
instantiated from, and S has a level threshold set, that level
is effective level of logger X

Otherwise effective level of logger X is effective level of its parent.

ROOT logger always has a level threshold set, so above steps always
result in a valid log level.

Effective log level is returned by the function (log4cl:effective-log-level LOGGER)

FAQ

I don't see log messages from other threads.

The *TERMINAL-IO* value bound in the other threads is probably different and points
to other place (likely *inferior-lisp* buffer under Slime)

(log:config :sane2) will copy messages from other threads to REPL
while continuing output to thread specific *TERMINAL-IO* (REPL
thread will still only log to REPL)

(log:config :sane :this-console) will redirect all logging to current console
regardless of thread local values of *TERMINAL-IO*

Why Log4CL starts its own thread, and how I get rid of it

Its a flusher thread to flush the appenders, it increases
performance greatly when there is a lot of logging.oe

You can stop it by calling (log4cl:stop-hierarchy-watcher-thread)

On SBCL Log4CL uses *EXIT-HOOKS* and *SAVE-HOOKS* to
automatically flush all appenders on exit, so that last second of
logging is not lost, and to terminate the watcher thread when
saving image, which can't be done with multiple threads running.

I'd like just the log messages, and not all the extra stuff

Use pattern layout with just %m%n format (message + newline)

How do I log into a file

(log:config :daily "file.txt") which will be backed up each day to
file.txt.YYYYMMDD

I want both log file and backup log file to have YYYYMMDD prefix or roll once per week

6.1.3 Macros

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into LOG-<LEVEL> log statement that will print each element
of SEXPS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. Constant string elements will be output directly.

A pretty printer (pprint-newline :fill) format will be used as a
separator between expressions, so that long expressions start
on a new line, if *PRINT-PRETTY* is non-NIL

Separator between expression and value, which defaults to equal sign,
and a suffix after each value, which defaults to " ~:_" (a space
followed by conditional newline) can be customized per package via
NAMING-OPTION generic function

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Expands into the log statement that will print each
element of ARGS in the form of ELEMENT=VALUE where ELEMENT will be the
literal argument without evaluating it, and VALUE will be the result
of evaluation. For constant string elements, it is output literally
without printing its value.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

Submit log message to the logging system. Whenever
the message is actually displayed or not depends on logging system
configuration at run-time.

The ARGS are parsed as follows:

1. Determine a logger object

If first argument is a constant list, constant symbol or a keyword, it
is made into a logger object as described in the MAKE-LOGGER macro
documentation

If first argument is a constant string, logger name is auto-determined
from context as described in the MAKE-LOGGER macro documentation, and
system proceeds to step 2.

Otherwise any non-NIL first argument is assumed to be a form, that
when evaluated will return a logger object.

2. If there are remaining arguments, they are used as format control
string and format arguments, to be passed into the FORMAT function to
produce the log message, when one is produced.

If there were no other arguments, then this macro expands into a form,
that will return T or NIL depending if logging with specified log
level will actually produce any log messages. Note that having log
level enabled does not necessary mean logging with log level is
enabled, it also takes into account whenever log message will reach
any appenders.

6.1.4 Functions

CATEGORIES – List of category names
SEPARATOR – Category separator. Will only be used if logger did not
exist before.
CAT-CASE – How each category case is treated. See NAMING-OPTION
generic function for description

FORCE-STRING-CASE – Whenever elements of category which are strings,
should also undergo case conversion according to CAT-CASE

CREATEP – Create the logger if it does not exist
FILE – pathname, source file being compiled

PKG-IDX-START/PKG-IDX-END – zero based indexes as to where
in CATEGORIES package name starts ends, meaning of indexes
is like SUBSEQ.. If package is unknown, both must be NIL

For historical reason the above indexes are incremented by one before
being stored in FLAGS slot, and functions LOGGER-PKG-IDX-START/END
return them 1 based, with 0 being used as a flag that there is no
package name in the category.

IS-FILE-P – T when its an actual SOURCE-FILE-LOGGER being requested,
which is a special type of leaf logger representing the source file.

Add unique watch token to the HIERARCHY, uniqueness is determined
by TEST and KEY arguments which are passed to FIND and REMOVE. Any
matching token is already present, the old token is removed and new
one is inserted.

The per-hierarchy lock is held doing the operation.

Automatically starts hierarchy watcher thread, if it was not already started

LOGGER-IDENTIFIER is optional and defaults to the root logger. It can be
one of the following:

- Logger instance ie result of (LOG:CATEGORY) expansion, or any other form
that returns a logger.

- A list of logger categories, basically a shortcut for (LOG:CATEGORY
’(CAT1 CAT2 CAT3)). An error will be given if logger does not exist. If you want
to ensure logger is created, even if it did not exist before, use
(LOG:CONFIG (LOG:CATEGORY ...) ...)

Without any options (LOG:CONFIG) displays current configuration

—————|—————————————————————
Option | Description
—————|—————————————————————
MAIN OPTIONS.
—————|—————————————————————
:INFO | Or any other keyword identifying a log level, which can be
:DEBUG | shortened to its shortest unambiguous prefix, such as :D.
| Changes the logger level to that level.
—————|—————————————————————
:SANE | Removes logger appenders, then arranges for the logging output
| to be always logged to dynamic value of *TERMINAL-IO*
|
| If used with :DAILY then console appender is not added, unless
| :CONSOLE, :THIS-CONSOLE or :TRICKY-CONSOLE is also specified.
|
| The pattern layout added is affected by many of the pattern
| options below.
—————|—————————————————————
APPENDER OPTIONS
—————|—————————————————————
:CONSOLE | Adds CONSOLE-APPENDER to the logger. Console appender logs
| into current console as indicated by *TERMINAL-IO* stream
—————|—————————————————————
:THIS-CONSOLE | Adds THIS-CONSOLE-APPENDER to the logger. It captures the
(or :THIS) | current value of *TERMINAL-IO* by recursively resolving any
| synonym or two-way streams, and continues to log the
| remembered value, even if it goes out dynamic scope.
|
| On any stream errors it will auto-remove itself.
—————|—————————————————————
:TRICKY-CONSOLE| Adds TRICKY-CONSOLE-APPENDER which acts exactly like
(or :TRICKY) | THIS-CONSOLE appender above, but it checks if dynamic value
| of *TERMINAL-IO* resolves to the same stream and ignores the
| log message if it does.
|
| When debugging multi-threaded code from REPL, this results in
| REPL thread logging to REPL, while threads with some other
| value of *TERMINAL-IO* stream will output to both.
|
| As a shortcut, if THIS-CONSOLE is specified and global console
| appender already exists, it will add TRICKY-CONSOLE instead.
—————|—————————————————————
:SANE2 | Shortcut for :SANE :TRICKY (mnemonic two -> multiple threads)
—————|—————————————————————
:STREAM stream| Changes the stream used for above two dedicated stream
| appenders.
—————|—————————————————————
:DAILY FILE | Adds file appender logging to the named file, which will be
| re-opened every day, with old log file renamed to FILE.%Y%m%d.
|
| Removes any other file based appenders from the logger.
|
| FILE can also contain %Y%m%d like pattern, expansion of which
| will determine when new log file would be opened.
—————|—————————————————————
:FILTER level | Makes all appenders added by above keywords drop messages
| below specified level.
—————|—————————————————————

LAYOUT OPTIONS

General note about layout options, if any appender options are specified
the layout options only affect PATTERN-LAYOUT for new appenders created
by LOG:CONFIG command

But if no appender options are specified, but layout options are, LOG:CONFIG
will change the pattern layout on all console based appenders that output
current *TERMINAL-IO*
—————|—————————————————————
:PATTERN | For any new appenders added, specifies the conversion pattern
| for the PATTERN-LAYOUT. If not given, default pattern will be
| used, modified by below options
—————|—————————————————————
:PRETTY | Add {pretty} option to the pattern to force pretty printing
:NOPRETTY | Add {nopretty} option to the pattern to force no pretty printing
| without one of these, global value is in effect
—————|—————————————————————
:TIME/:NOTIME | Include time into default pattern, default is :TIME
—————|—————————————————————
:FILE or | Include file name into default pattern, :FILE2 uses alternate
:FILE2 | position for the file (in front of the package).
:NOFILE | :NOFILE does not show the file
—————|—————————————————————
:THREAD | Include thread name into default pattern, it will be after the
[<n>[<n2>]] | time, in [%t] format. If :THREAD argument is followed by one
| or two numbers, they will be used as min/max field width.
—————|—————————————————————
:NDC | Include NDC context into default pattern, with optional min/max
[<n>[<n2>]] | field width flags. When used together with :THREAD NDC will be
| printed after the thread name, separated by dash, like this
| example: "[threadname-ndc]"; it will not be shown if unbound
|
| Without :THREAD, its shown in its own square brackets, with
| entire construct not shown if unbound.
—————|—————————————————————
:NOPACKAGE | Add {nopackage} option to the pattern (binds orig package at
:PACKAGE | the site of the log statement. PACKAGE binds keyword package,
| so everything is printed with package prefix
—————|—————————————————————
:TWOLINE | Changes pattern layout to print hard newline before actual log
(or :2LINE) | message. Only makes sense with NOPRETTY or when logging into
| files.
|
| Pretty printing does better job at line splitting then forced
| two line layout, with short log statements placed on a single
| line and longer ones wrapping.
—————|—————————————————————
ASSORTED OTHER OPTIONS
—————|—————————————————————
:PROPERTIES | Configure with PROPERTY-CONFIGURATOR by parsing specified
FILE | properties file
—————|—————————————————————
:WATCH | Used with :PROPERTIES, uses watcher thread to check
| properties file modification time, and reloads if it changes
—————|—————————————————————
:IMMEDIATE- | Used with :SANE, :DAILY or :CONSOLE to create new appenders
FLUSH | with :IMMEDIATE-FLUSH T option, which prevents automatic
| startup of hierarchy watcher thread, which is used for
| auto-flushing.
—————|—————————————————————
:NOADDITIVE | Makes logger non-additive (does not propagate to parent)
:OWN | Shortcut for non-additive (usually has appenders on its own)
:ADDITIVE | Sets additive flag back to T.
—————|—————————————————————
:CLEAR | Reset the child in the hierarchy, by unsetting their log level
| and/or removing appenders from them. Without any other flags
| unset the log levels.
|
:LEVELS | Clears the log levels, this is the default
:APPENDERS | Removes any appenders, levels will not be cleared unless
| :LEVELS is also specified
|
:ALL | Normally :CLEAR does not touch non-additive loggers, that is
| the ones that don’t pass messages to parents. This flag forces
| clearing of non-additive loggers
|
| Note that this option does not change the logger being acted
| upon, just its children. See next option
—————|—————————————————————
:REMOVE <num> | Removes specific appender from the logger. Numbers are 1-based,
| and are same ones displayed by LOG:CONFIG without arguments
—————|—————————————————————
:SELF | Configures the LOG4CL logger, which can be used to debug
| Log4CL itself. Normally all other LOG:CONFIG hides the
| it from view.
—————|—————————————————————
:FORCE-ADD | Normally if you specify :CONSOLE :THIS-CONSOLE or
| :TRICKY-CONSOLE without :SANE (which clears out existing
| appenders), an error will be given if there are any standard
| console appenders that already log to *TERMINAL-IO* or :STREAM
| argument.
|
| This is to prevent from creating duplicate output.
|
| Adding :FORCE-ADD flag skips the above check, and allows you
| to add new console appender regardless.
—————|—————————————————————
:BACKUP | Used together with :DAILY, specifies the :BACKUP-NAME-FORMAT,
| see docstring for the DAILY-FILE-APPENDER class.
|
| For example specifying a DAILY <file> :BACKUP NIL will always
| log to statically named FILE without rolling.
|
| Defaults to NIL if FILE contains percent character or
| FILE.%Y%m%d otherwise.
—————|—————————————————————

Configures the logger PACKAGE with debug log level, logging into
the file "package-log.20130510" which will be rolled over daily;
makes logger non-additive so messages will not be propagated to
logger parents. (To see them on console, remove the :OWN flag, or
add :CONSOLE to the command)

Note: in above example if package name is dotted, you need to
specify the split category list, so if your package name is
COM.EXAMPLE.FOO logger categories will be ’(COM EXAMPLE FOO)

LOGGER-IDENTIFIER is optional and defaults to the root logger. It can be
one of the following:

- Logger instance ie result of (LOG:CATEGORY) expansion, or any other form
that returns a logger.

- A list of logger categories, basically a shortcut for (LOG:CATEGORY
’(CAT1 CAT2 CAT3)). An error will be given if logger does not exist. If you want
to ensure logger is created, even if it did not exist before, use
(LOG:CONFIG (LOG:CATEGORY ...) ...)

Without any options (LOG:CONFIG) displays current configuration

—————|—————————————————————
Option | Description
—————|—————————————————————
MAIN OPTIONS.
—————|—————————————————————
:INFO | Or any other keyword identifying a log level, which can be
:DEBUG | shortened to its shortest unambiguous prefix, such as :D.
| Changes the logger level to that level.
—————|—————————————————————
:SANE | Removes logger appenders, then arranges for the logging output
| to be always logged to dynamic value of *TERMINAL-IO*
|
| If used with :DAILY then console appender is not added, unless
| :CONSOLE, :THIS-CONSOLE or :TRICKY-CONSOLE is also specified.
|
| The pattern layout added is affected by many of the pattern
| options below.
—————|—————————————————————
APPENDER OPTIONS
—————|—————————————————————
:CONSOLE | Adds CONSOLE-APPENDER to the logger. Console appender logs
| into current console as indicated by *TERMINAL-IO* stream
—————|—————————————————————
:THIS-CONSOLE | Adds THIS-CONSOLE-APPENDER to the logger. It captures the
(or :THIS) | current value of *TERMINAL-IO* by recursively resolving any
| synonym or two-way streams, and continues to log the
| remembered value, even if it goes out dynamic scope.
|
| On any stream errors it will auto-remove itself.
—————|—————————————————————
:TRICKY-CONSOLE| Adds TRICKY-CONSOLE-APPENDER which acts exactly like
(or :TRICKY) | THIS-CONSOLE appender above, but it checks if dynamic value
| of *TERMINAL-IO* resolves to the same stream and ignores the
| log message if it does.
|
| When debugging multi-threaded code from REPL, this results in
| REPL thread logging to REPL, while threads with some other
| value of *TERMINAL-IO* stream will output to both.
|
| As a shortcut, if THIS-CONSOLE is specified and global console
| appender already exists, it will add TRICKY-CONSOLE instead.
—————|—————————————————————
:SANE2 | Shortcut for :SANE :TRICKY (mnemonic two -> multiple threads)
—————|—————————————————————
:STREAM stream| Changes the stream used for above two dedicated stream
| appenders.
—————|—————————————————————
:DAILY FILE | Adds file appender logging to the named file, which will be
| re-opened every day, with old log file renamed to FILE.%Y%m%d.
|
| Removes any other file based appenders from the logger.
|
| FILE can also contain %Y%m%d like pattern, expansion of which
| will determine when new log file would be opened.
—————|—————————————————————
:FILTER level | Makes all appenders added by above keywords drop messages
| below specified level.
—————|—————————————————————

LAYOUT OPTIONS

General note about layout options, if any appender options are specified
the layout options only affect PATTERN-LAYOUT for new appenders created
by LOG:CONFIG command

But if no appender options are specified, but layout options are, LOG:CONFIG
will change the pattern layout on all console based appenders that output
current *TERMINAL-IO*
—————|—————————————————————
:PATTERN | For any new appenders added, specifies the conversion pattern
| for the PATTERN-LAYOUT. If not given, default pattern will be
| used, modified by below options
—————|—————————————————————
:PRETTY | Add {pretty} option to the pattern to force pretty printing
:NOPRETTY | Add {nopretty} option to the pattern to force no pretty printing
| without one of these, global value is in effect
—————|—————————————————————
:TIME/:NOTIME | Include time into default pattern, default is :TIME
—————|—————————————————————
:FILE or | Include file name into default pattern, :FILE2 uses alternate
:FILE2 | position for the file (in front of the package).
:NOFILE | :NOFILE does not show the file
—————|—————————————————————
:THREAD | Include thread name into default pattern, it will be after the
[<n>[<n2>]] | time, in [%t] format. If :THREAD argument is followed by one
| or two numbers, they will be used as min/max field width.
—————|—————————————————————
:NDC | Include NDC context into default pattern, with optional min/max
[<n>[<n2>]] | field width flags. When used together with :THREAD NDC will be
| printed after the thread name, separated by dash, like this
| example: "[threadname-ndc]"; it will not be shown if unbound
|
| Without :THREAD, its shown in its own square brackets, with
| entire construct not shown if unbound.
—————|—————————————————————
:NOPACKAGE | Add {nopackage} option to the pattern (binds orig package at
:PACKAGE | the site of the log statement. PACKAGE binds keyword package,
| so everything is printed with package prefix
—————|—————————————————————
:TWOLINE | Changes pattern layout to print hard newline before actual log
(or :2LINE) | message. Only makes sense with NOPRETTY or when logging into
| files.
|
| Pretty printing does better job at line splitting then forced
| two line layout, with short log statements placed on a single
| line and longer ones wrapping.
—————|—————————————————————
ASSORTED OTHER OPTIONS
—————|—————————————————————
:PROPERTIES | Configure with PROPERTY-CONFIGURATOR by parsing specified
FILE | properties file
—————|—————————————————————
:WATCH | Used with :PROPERTIES, uses watcher thread to check
| properties file modification time, and reloads if it changes
—————|—————————————————————
:IMMEDIATE- | Used with :SANE, :DAILY or :CONSOLE to create new appenders
FLUSH | with :IMMEDIATE-FLUSH T option, which prevents automatic
| startup of hierarchy watcher thread, which is used for
| auto-flushing.
—————|—————————————————————
:NOADDITIVE | Makes logger non-additive (does not propagate to parent)
:OWN | Shortcut for non-additive (usually has appenders on its own)
:ADDITIVE | Sets additive flag back to T.
—————|—————————————————————
:CLEAR | Reset the child in the hierarchy, by unsetting their log level
| and/or removing appenders from them. Without any other flags
| unset the log levels.
|
:LEVELS | Clears the log levels, this is the default
:APPENDERS | Removes any appenders, levels will not be cleared unless
| :LEVELS is also specified
|
:ALL | Normally :CLEAR does not touch non-additive loggers, that is
| the ones that don’t pass messages to parents. This flag forces
| clearing of non-additive loggers
|
| Note that this option does not change the logger being acted
| upon, just its children. See next option
—————|—————————————————————
:REMOVE <num> | Removes specific appender from the logger. Numbers are 1-based,
| and are same ones displayed by LOG:CONFIG without arguments
—————|—————————————————————
:SELF | Configures the LOG4CL logger, which can be used to debug
| Log4CL itself. Normally all other LOG:CONFIG hides the
| it from view.
—————|—————————————————————
:FORCE-ADD | Normally if you specify :CONSOLE :THIS-CONSOLE or
| :TRICKY-CONSOLE without :SANE (which clears out existing
| appenders), an error will be given if there are any standard
| console appenders that already log to *TERMINAL-IO* or :STREAM
| argument.
|
| This is to prevent from creating duplicate output.
|
| Adding :FORCE-ADD flag skips the above check, and allows you
| to add new console appender regardless.
—————|—————————————————————
:BACKUP | Used together with :DAILY, specifies the :BACKUP-NAME-FORMAT,
| see docstring for the DAILY-FILE-APPENDER class.
|
| For example specifying a DAILY <file> :BACKUP NIL will always
| log to statically named FILE without rolling.
|
| Defaults to NIL if FILE contains percent character or
| FILE.%Y%m%d otherwise.
—————|—————————————————————

Configures the logger PACKAGE with debug log level, logging into
the file "package-log.20130510" which will be rolled over daily;
makes logger non-additive so messages will not be propagated to
logger parents. (To see them on console, remove the :OWN flag, or
add :CONSOLE to the command)

Note: in above example if package name is dotted, you need to
specify the split category list, so if your package name is
COM.EXAMPLE.FOO logger categories will be ’(COM EXAMPLE FOO)

Return the hierarchy index for the specified hierarchy. Hierarchy
must be already a number or a unique identifier suitable for comparing
using EQL. If hierarchy is a string, it will be interned in the current
package

LOGGER-IDENTIFIER is optional and defaults to the root logger. It can be
one of the following:

- Logger instance ie result of (LOG:CATEGORY) expansion, or any other form
that returns a logger.

- A list of logger categories, basically a shortcut for (LOG:CATEGORY
’(CAT1 CAT2 CAT3)). An error will be given if logger does not exist. If you want
to ensure logger is created, even if it did not exist before, use
(LOG:CONFIG (LOG:CATEGORY ...) ...)

Without any options (LOG:CONFIG) displays current configuration

—————|—————————————————————
Option | Description
—————|—————————————————————
MAIN OPTIONS.
—————|—————————————————————
:INFO | Or any other keyword identifying a log level, which can be
:DEBUG | shortened to its shortest unambiguous prefix, such as :D.
| Changes the logger level to that level.
—————|—————————————————————
:SANE | Removes logger appenders, then arranges for the logging output
| to be always logged to dynamic value of *TERMINAL-IO*
|
| If used with :DAILY then console appender is not added, unless
| :CONSOLE, :THIS-CONSOLE or :TRICKY-CONSOLE is also specified.
|
| The pattern layout added is affected by many of the pattern
| options below.
—————|—————————————————————
APPENDER OPTIONS
—————|—————————————————————
:CONSOLE | Adds CONSOLE-APPENDER to the logger. Console appender logs
| into current console as indicated by *TERMINAL-IO* stream
—————|—————————————————————
:THIS-CONSOLE | Adds THIS-CONSOLE-APPENDER to the logger. It captures the
(or :THIS) | current value of *TERMINAL-IO* by recursively resolving any
| synonym or two-way streams, and continues to log the
| remembered value, even if it goes out dynamic scope.
|
| On any stream errors it will auto-remove itself.
—————|—————————————————————
:TRICKY-CONSOLE| Adds TRICKY-CONSOLE-APPENDER which acts exactly like
(or :TRICKY) | THIS-CONSOLE appender above, but it checks if dynamic value
| of *TERMINAL-IO* resolves to the same stream and ignores the
| log message if it does.
|
| When debugging multi-threaded code from REPL, this results in
| REPL thread logging to REPL, while threads with some other
| value of *TERMINAL-IO* stream will output to both.
|
| As a shortcut, if THIS-CONSOLE is specified and global console
| appender already exists, it will add TRICKY-CONSOLE instead.
—————|—————————————————————
:SANE2 | Shortcut for :SANE :TRICKY (mnemonic two -> multiple threads)
—————|—————————————————————
:STREAM stream| Changes the stream used for above two dedicated stream
| appenders.
—————|—————————————————————
:DAILY FILE | Adds file appender logging to the named file, which will be
| re-opened every day, with old log file renamed to FILE.%Y%m%d.
|
| Removes any other file based appenders from the logger.
|
| FILE can also contain %Y%m%d like pattern, expansion of which
| will determine when new log file would be opened.
—————|—————————————————————
:FILTER level | Makes all appenders added by above keywords drop messages
| below specified level.
—————|—————————————————————

LAYOUT OPTIONS

General note about layout options, if any appender options are specified
the layout options only affect PATTERN-LAYOUT for new appenders created
by LOG:CONFIG command

But if no appender options are specified, but layout options are, LOG:CONFIG
will change the pattern layout on all console based appenders that output
current *TERMINAL-IO*
—————|—————————————————————
:PATTERN | For any new appenders added, specifies the conversion pattern
| for the PATTERN-LAYOUT. If not given, default pattern will be
| used, modified by below options
—————|—————————————————————
:PRETTY | Add {pretty} option to the pattern to force pretty printing
:NOPRETTY | Add {nopretty} option to the pattern to force no pretty printing
| without one of these, global value is in effect
—————|—————————————————————
:TIME/:NOTIME | Include time into default pattern, default is :TIME
—————|—————————————————————
:FILE or | Include file name into default pattern, :FILE2 uses alternate
:FILE2 | position for the file (in front of the package).
:NOFILE | :NOFILE does not show the file
—————|—————————————————————
:THREAD | Include thread name into default pattern, it will be after the
[<n>[<n2>]] | time, in [%t] format. If :THREAD argument is followed by one
| or two numbers, they will be used as min/max field width.
—————|—————————————————————
:NDC | Include NDC context into default pattern, with optional min/max
[<n>[<n2>]] | field width flags. When used together with :THREAD NDC will be
| printed after the thread name, separated by dash, like this
| example: "[threadname-ndc]"; it will not be shown if unbound
|
| Without :THREAD, its shown in its own square brackets, with
| entire construct not shown if unbound.
—————|—————————————————————
:NOPACKAGE | Add {nopackage} option to the pattern (binds orig package at
:PACKAGE | the site of the log statement. PACKAGE binds keyword package,
| so everything is printed with package prefix
—————|—————————————————————
:TWOLINE | Changes pattern layout to print hard newline before actual log
(or :2LINE) | message. Only makes sense with NOPRETTY or when logging into
| files.
|
| Pretty printing does better job at line splitting then forced
| two line layout, with short log statements placed on a single
| line and longer ones wrapping.
—————|—————————————————————
ASSORTED OTHER OPTIONS
—————|—————————————————————
:PROPERTIES | Configure with PROPERTY-CONFIGURATOR by parsing specified
FILE | properties file
—————|—————————————————————
:WATCH | Used with :PROPERTIES, uses watcher thread to check
| properties file modification time, and reloads if it changes
—————|—————————————————————
:IMMEDIATE- | Used with :SANE, :DAILY or :CONSOLE to create new appenders
FLUSH | with :IMMEDIATE-FLUSH T option, which prevents automatic
| startup of hierarchy watcher thread, which is used for
| auto-flushing.
—————|—————————————————————
:NOADDITIVE | Makes logger non-additive (does not propagate to parent)
:OWN | Shortcut for non-additive (usually has appenders on its own)
:ADDITIVE | Sets additive flag back to T.
—————|—————————————————————
:CLEAR | Reset the child in the hierarchy, by unsetting their log level
| and/or removing appenders from them. Without any other flags
| unset the log levels.
|
:LEVELS | Clears the log levels, this is the default
:APPENDERS | Removes any appenders, levels will not be cleared unless
| :LEVELS is also specified
|
:ALL | Normally :CLEAR does not touch non-additive loggers, that is
| the ones that don’t pass messages to parents. This flag forces
| clearing of non-additive loggers
|
| Note that this option does not change the logger being acted
| upon, just its children. See next option
—————|—————————————————————
:REMOVE <num> | Removes specific appender from the logger. Numbers are 1-based,
| and are same ones displayed by LOG:CONFIG without arguments
—————|—————————————————————
:SELF | Configures the LOG4CL logger, which can be used to debug
| Log4CL itself. Normally all other LOG:CONFIG hides the
| it from view.
—————|—————————————————————
:FORCE-ADD | Normally if you specify :CONSOLE :THIS-CONSOLE or
| :TRICKY-CONSOLE without :SANE (which clears out existing
| appenders), an error will be given if there are any standard
| console appenders that already log to *TERMINAL-IO* or :STREAM
| argument.
|
| This is to prevent from creating duplicate output.
|
| Adding :FORCE-ADD flag skips the above check, and allows you
| to add new console appender regardless.
—————|—————————————————————
:BACKUP | Used together with :DAILY, specifies the :BACKUP-NAME-FORMAT,
| see docstring for the DAILY-FILE-APPENDER class.
|
| For example specifying a DAILY <file> :BACKUP NIL will always
| log to statically named FILE without rolling.
|
| Defaults to NIL if FILE contains percent character or
| FILE.%Y%m%d otherwise.
—————|—————————————————————

Configures the logger PACKAGE with debug log level, logging into
the file "package-log.20130510" which will be rolled over daily;
makes logger non-additive so messages will not be propagated to
logger parents. (To see them on console, remove the :OWN flag, or
add :CONSOLE to the command)

Note: in above example if package name is dotted, you need to
specify the split category list, so if your package name is
COM.EXAMPLE.FOO logger categories will be ’(COM EXAMPLE FOO)

NAME – specifies the name of this logging configuration, if NAME is not
specified, one is automatically provided as "Saved on <timestamp>".

If its equivalent to some other configuration, save it only if it had
a different name, otherwise lift the older equivalent configuration to
the top of the list.

When *SAVE-CONFIGURATIONS-TO-FILE* is T (default) the configuration
list list will also be saved to a file
".log4cl-configurations.lisp-expr" in user home directory. File name
can be customized by changing *CONFIGURATIONS-FILE* variable

NAME – specifies the name of this logging configuration, if NAME is not
specified, one is automatically provided as "Saved on <timestamp>".

If its equivalent to some other configuration, save it only if it had
a different name, otherwise lift the older equivalent configuration to
the top of the list.

When *SAVE-CONFIGURATIONS-TO-FILE* is T (default) the configuration
list list will also be saved to a file
".log4cl-configurations.lisp-expr" in user home directory. File name
can be customized by changing *CONFIGURATIONS-FILE* variable

Set the log level of a logger. Log level is passed to
MAKE-LOG-LEVEL to determine canonical log level. ADJUST-P controls if
logger effective log level needs to be recalculated, the caller should
NIL doing bulk operations that change the level of many loggers, as to
avoid overhead.

Returns if log level had changed as the 1st value and new level as the
second value.

Writes the log message into the appender. Text of the log message
is specified indirectly via LOG-FUNC argument, which will be a
function that accepts a stream, and writes the text of log message to
it.

This function should first figure out or obtain the stream to write
the log message to, and then call the LAYOUT-TO-STREAM function to have
layout do actual formatting.

If appender destination is ultimately not a stream, then it can
obtain the full text of the log message by calling LAYOUT-TO-STREAM
inside of WITH-OUTPUT-TO-STRING

Should move or rename LOG-FILENAME into the
BACKUP-FILENAME. When this function is called, LOG-FILENAME is already
closed.

Implemented as generic function so its possible to write extensions
that compress the backup log files automatically, or append to
them. One possible extension could be having daily log file and a
weekly backup, that is appended to each day

Configures logging from the specified file. If AUTO-RELOAD is
non-NIL, then after initial configuration will watch the file for
modifications and re-configure when it changes. Note that auto-reload
will not be configured if initial configuration signaled a error

Is called by RESOLVE-DEFAULT-LOGGER-FORM to try to
determine the enclosing lexical scope name. For example if logging
macro is being expanded while compiling local function BAR inside of a
definition of function FOO, the implementation of this method should
strive to return ’(FOO BAR) if possible.

For CLOS method it is recommended that return value be a generic
function name, followed by optional qualifier, and then followed by
any non-T specializers, with EQL specializers flattened to their
values, for example for the :AROUND method FOO with lambda list
of ((OBJ1 BAR) (OPTION (EQL :BAZ)) OBJ3) should strive to return
’(FOO AROUND BAR BAZ)

Should return numeric log level from the user
representation, can be specialized per-package to have custom log
level names. Default implementation converts object to string and
parses "fatal" "debug" and so on. Called by MAKE-LOG-LEVEL
function

Allows packages to optionally massage logger names in their
namespace. CATEGORIES will be a list of category names from parent
to child, and EXPLICIT-P will be non-NIL if that list was specified as
an explicit list constant in a logging macro.

Should return (values NEW-CATEGORIES [CAT-LIST-INDEXES])

Where NEW-CATEGORIES should be a new list of categories to use instead
of CATEGORIES.

CAT-LIST-INDEXES should be a list of three numbers (FILE-IDX
PACKAGE-START-IDX PACKAGE-END-IDX) which have the following meaning:

* FILE-IDX – index of the category representing file name (zero based)
* PACKAGE-IDX – index of the first and last (exclusive) category representing
the package.

Based on the above indexes, the pattern layout %g (package) and
%F (file name) and %G (everything else) will be able to return correct
values, on matter where in the package or filename are located in the
category hierarchy.

Default method will first find PACKAGE shortest nickname, then split
it according to category-separator naming option, then return the
values like so:

Is called by all logging macros to figure out the
logger to log into. PACKAGE and ENV are the current value of *PACKAGE*
and the macro environment of the logging macro, and ARGS
are its arguments.

Returns two values, first being either a logger, or a form that when
evaluated will return a logger, and second value being list of
arguments to be passed to the format statement that will log the
message.

When second value returned is NIL, then logging macro will not log any
message but will rather expand into a non-NIL value if logging is
enabled on that logger.

Will be called on each member of WATCH-TOKENS list
when hierarchy watcher thread is started. If a unhandled condition is
signaled from this function the watcher thread will remove
corresponding token from the list

An appender that writes to the file named by
expanding a pattern. The expansion is done by the same
converter as the %d conversion pattern of the PATTERN-LAYOUT, which is
a subset of patterns supported by strftime POSIX function.

Properties:

NAME-FORMAT
: Expanded with date formatter to get the name of the current log file

BACKUP-NAME-FORMAT
: Expanded with date formatter to get the name of the backup log file

UTC-P
: Should be non-NIL if name and backup patterns expand the UTC time
instead of local. Defaults to NIL.

MAYBE-ROLL-FILE method works as follows. It expands both name and
backup format (if present).

If either of them differs from their previous values, current log file
will be closed, and a new current log file will be opened.

The old log file will be renamed to %NEXT-BACKUP-NAME, which is a
value of the backup format expansion remembered when original log file
was opened. The new value of the backup format expansion is
remembered in the %NEXT-BACKUP-NAME slot.

In below examples it is assumed that current log file was created an
2012-02-21, and the event being logged is the first one on the next
day.

1) Example: NAME-FORMAT is "test.log" and backup is unset, will
always log to the file named test.log

2) Example: NAME-FORMAT is "test.%Y%m%d.log" and
BACKUP-NAME-FORMAT is unset. Will log into the file
test.20120221.log file, on the rollover it will be closed and
test.20120222.file will be opened.

3) Example: NAME-FORMAT is "test.log" and BACKUP-NAME-FORMAT is
"test.%Y%m%d.log". Will log into the file test.log. On rollover
test.log will be renamed to test.20120221.log, and new test.log
will be created.

4) Example: NAME-FORMAT is "test.%Y%m%d" and BACKUP-NAME-FORMAT is
"test.log.bak". Will log into the file test.20120210.log and
when the day changes, will rename it to test.log.bak (erasing old
one if it exists)

If a string resulting from the pattern expansion is longer then MAX
its truncated by omitting characters from the start. Then if its
shorter then MIN its padded with spaces to the right or left (when
preceded by a minus)

If PREFIX and/or SUFFIX is specified, then string is wrapped with them
and all padding for justification, is done before the prefix and after
the suffix. The length of prefix and suffix are not included into
MIN/MAX or/padding calculations.

Example: %-7;<;;>;p with p expanding to INFO, will produce the string
" <INFO>"

If : flag is specified, and string is empty, then no output is made, including
not outputting any prefix or suffix.

Performance considerations: All formatting is done without consing,
except for the case of %m (user message) format, when it has MIN or
MAX field width flags. That is because user message is passed around
as a lambda that writes to the stream, and in order for its length to
be known, (with-output-to-string) is used.

Second extra argument is SEPARATOR and will be a separator used
between category names. If not present then the loggers native
value will be used, which can be overwritten per package by
NAMING-OPTION method

Third extra argument if present, can be one of :UPCASE, :DOWNCASE or
:INVERT and will result in printing of the category name in the
corresponding manner, similar to using non-standard readtable-case

For example when logger category is CL-USER.FOO.BAR outputting it
with conversion pattern of %c{}{–}{:invert} will result print it
as cl-user–foo–bar
——————————————————————–
%g - like to %c, but only portion of the categories that represent
the package name

%C - like to %c, but only portion of the categories that are not
the package name.

Example: assuming category separator setup for the package was a
dot, and a (log:logger :one.two.three) was instantiated in package
cl.dotted.package:

%F namestring of a file where logger was instantiated, same as
returned by LOGGER-FILE-NAMESTRING
——————————————————————–
%d The date/time of the log message in UTC, extra argument
can be a date pattern. Default date pattern is
%d{%Y-%m-%d %H:%M:%S}

To facilitate testing there can be optional second extra
argument, which could be decimal value that will be used as
universal time instead calling (GET-UNIVERSAL-TIME)

Lisp does not have portable facility to get week and month
names, so date format is printed by PATTERN-LAYOUT-FORMAT-DATE
generic function, default method of which uses hard-coded
English week/month/weekday names.

Valid date format values are same as C strftime function, with
GNU extensions.

%A – Full weekday name
%A – Abbreviated weekday name
%B – Full month name
%b – Abbreviated month name
%c – Standard date and time string
%d – Day of month as a decimal(01-31)
%H – Hour(00-23)
%I – Hour(01-12)
%m – Month as decimal(01-12)
%M – Minute as decimal(00-59)
%p – AM or PM
%P – am or pm
%S – Second as decimal(00-59)
%y – Year in decimal without century(0-99)
%Y – Year including century as decimal
%z – Time zone offset from UTC in -hhmm or +hhmm format
%% – The percent sign
——————————————————————–
%D date-time in local time, extra arguments can contain a strftime pattern

%h hostname of the system (implementation dependent, obtained once
when pattern is parsed, and cached

%t Current thread name

%x Value of *ndc-context* variable from (with-ndc (context)) macro

%i Process id of the lisp process, implementation dependent.

%I Two spaces repeated *log-indent* times. Different padding string
can be specified in an extra argument.

%< and %> the formatting inside is wrapped into
PPRINT-LOGICAL-BLOCK. Whenever pretty printing is actually used
depends on runtime value of *PRINT-PRETTY* at call site

The opening pattern can have extra arguments, with following
meaning:

%<{pretty}[{<num>}] - bind *PRINT-PRETTY* to T at runtime,if followed
by a number, set *print-right-margin* to it
%<{nopretty} - bind *PRINT-PRETTY* to NIL at runtime
%<{package} - bind *PACKAGE* to :KEYWORD package
%<{nopackage} - bind *PACKAGE* to original package

Both pretty and package can be used together like this %<{pretty}{package} ... %>

Appender that writes message to stream. Stream is
obtained on each output by calling APPENDER-STREAM function.

Properties:

IMMEDIATE-FLUSH

: When non-NIL will call FINISH-OUTPUT after every log message

FLUSH-INTERVAL

: When set, will only flush if previous flush was earlier than
FLUSH-INTERVAL seconds ago. In addition a background thread will be
used to flush all appenders with FLUSH-INTERVAL set. See
ADD-WATCH-TOKEN

Captures the *TERMINAL-IO* stream just like the
THIS-CONSOLE-APPENDER does, but at runtime checks if current value of
*TERMINAL-IO* resolves to the same value and only writes the
message if its different.

When used together with CONSOLE-APPENDER, results that current REPL
thread logs to REPL, while other threads log both to their
*TERMINAL-IO* and REPL.

When STOPCHAR is specified, the pattern format will be parsed until
%<STOPCHAR> is encountered, and the formatting function that outputs
everything in between will be passed as the extra argument to the
formatter, making the signature

The WRAPPED-FORMATTER will be a function with the same signature as regular
non-wrapped formatter.

This second form allows writing formatters that establish the dynamic
context for the pattern inside, for example %< %> formatter that wraps
everything inside into PPRINT-LOGICAL-BLOCK is implemented this way.

EXPR-PRINT-FORMAT - The FORMAT control string, for two arguments
used to print expressions, first argument is quoted expression form,
and second argument is value. Default is "~W=~W~^ ~:_". If
format string contains ~:> directive (terminate pretty printing block),
then corresponding format argument will be a (NAME VALUE) list

EXPR-LOG-LEVEL - the log level for the (LOG:EXPR) macro. Default
is :DEBUG.

OLD-LOGGING-MACROS - If set, log statements without constant format
string such as (LOG:DEBUG a b c d) will be interpreted as logging to
logger stored in variable A with format string B and more format
arguments, instead of treating them as (LOG:EXPR a b c d)

CATEGORIES – List of category names
SEPARATOR – Category separator. Will only be used if logger did not
exist before.
CAT-CASE – How each category case is treated. See NAMING-OPTION
generic function for description

FORCE-STRING-CASE – Whenever elements of category which are strings,
should also undergo case conversion according to CAT-CASE

CREATEP – Create the logger if it does not exist
FILE – pathname, source file being compiled

PKG-IDX-START/PKG-IDX-END – zero based indexes as to where
in CATEGORIES package name starts ends, meaning of indexes
is like SUBSEQ.. If package is unknown, both must be NIL

For historical reason the above indexes are incremented by one before
being stored in FLAGS slot, and functions LOGGER-PKG-IDX-START/END
return them 1 based, with 0 being used as a flag that there is no
package name in the category.

IS-FILE-P – T when its an actual SOURCE-FILE-LOGGER being requested,
which is a special type of leaf logger representing the source file.

Different version of loggers load-form, that does not
remember the file name. This allows saved logging configuration
to be restored, even if loggers had moved to a different file,
without overwriting their file with its value when configuration
was saved.

Save CNF logging configuration into *CONFIGURATIONS* list. If its equivalent
to some other configuration, save it only if it had a different name, otherwise
lift the older equivalent configuration to the top of the list

Should parse extra arguments after the end of the
conversion character in the PATTERN-STRING and return next parse
position. The START is the index of the first character in the
conversion pattern after the PATTERN-CHAR, ie in the string
%-5p{foobar} it will be at the opening curly brace.

Should return two values, new parse position and either FMT-INFO or
its subclass.

Handles two special cases of SEPARATOR=VALUE and
READ-CASE=VALUE (ignoring case differences), and updates the parser
accordingly, otherwise splits NAME with current separator, converts
tokens according to read case, and forwards to PARSE-PROPERTY-TOKENS

Generic Function: parse-property-tokensPARSER TOKENS VALUE

Called by default PARSE-PROPERTY-LINE
method. TOKENS will be the NAME part of the NAME=VALUE line, split
according to NAME-TOKEN-SEPARATOR and their case adjusted by
NAME-TOKEN-READ-CASE

Overriding this method to add extra properties is the only thing
needed to allow extra properties in custom appenders/layouts to be
configurable from by property file configurator. See also
PROPERTY-INITARG-FROM-STRING

Called on appenders and layouts to possibly convert
property value from a string into whatever its supposed to be. Default
method will handle numeric, boolean and string properties, by calling
PROPERTY-ALIST function