Browse Source

[master] Merge branch 'trac2566'

Stephen Morris 11 years ago
parent
commit
a08d702839
4 changed files with 767 additions and 532 deletions
  1. 4 4
      doc/devel/mainpage.dox
  2. 1 1
      src/lib/log/Makefile.am
  3. 0 527
      src/lib/log/README
  4. 762 0
      src/lib/log/logging.dox

+ 4 - 4
doc/devel/mainpage.dox

@@ -86,10 +86,10 @@
  * - @subpage libdhcp_ddns
  *
  * @section miscellaneousTopics Miscellaneous Topics
- * - @subpage LoggingApi
- *   - @subpage LoggingApiOverview
- *   - @subpage LoggingApiLoggerNames
- *   - @subpage LoggingApiLoggingMessages
+ * - @subpage logBind10Logging
+ *   - @subpage logBasicIdeas
+ *   - @subpage logDeveloperUse
+ *   - @subpage logNotes
  * - @subpage SocketSessionUtility
  * - <a href="./doxygen-error.log">Documentation warnings and errors</a>
  *

+ 1 - 1
src/lib/log/Makefile.am

@@ -32,7 +32,7 @@ libb10_log_la_SOURCES += message_types.h
 libb10_log_la_SOURCES += output_option.cc output_option.h
 libb10_log_la_SOURCES += buffer_appender_impl.cc buffer_appender_impl.h
 
-EXTRA_DIST  = README
+EXTRA_DIST  = logging.dox
 EXTRA_DIST += logimpl_messages.mes
 EXTRA_DIST += log_messages.mes
 

+ 0 - 527
src/lib/log/README

@@ -1,529 +0,0 @@
-This directory holds the first release of the logging system.
-
-
-Basic Ideas
-===========
-The BIND-10 logging system merges two ideas:
-
-* A hierarchical logging system similar to that used in Java (i.e. log4j)
-* Separation of message use from message text
-
-
-Hierarchical Logging System
-===========================
-When a program writes a message to the logging system, it does so using an
-instance of the Logger class.  As well as performing the write of the message,
-the logger identifies the source of the message: different sources can write
-to different destinations and can log different severities of messages.
-For example, the "cache" logger could write messages of DEBUG severity or
-above to a file while all other components write messages of "INFO" severity
-or above to the Syslog file.
-
-The loggers are hierarchical in that each logger is the child of another
-logger.  The top of the hierarchy is the root logger, which does not have
-a parent.  The point of the hierarchy is that unless a logger is explicitly
-assigned an attribute (such as severity of message being logger), it picks
-it up from the parent.  (In BIND-10, there is the root logger (named after
-the program) and every other logger is a child of that.)  So in the example
-above, the INFO/Syslog attributes could be associated with the root logger
-while the DEBUG/file attributes are associated with the "cache" logger.
-
-
-Separation of Messages Use from Message Text
-============================================
-By separating the use of the message from the text associated with this -
-in essence, defining message text in an external file - it is possible to
-replace the supplied text of the messages with a local language version.
-
-Each message is identified by an identifier e.g. "LOG_WRITE_ERROR".
-Within the program, this is the symbol passed to the logging system.
-The logger system uses the symbol as an index into a dictionary to
-retrieve the message associated with it (e.g. "unable to open %s for
-input").  It then substitutes any message parameters (in this example,
-the name of the file where the write operation failed) and logs it to
-the destination.
-
-In BIND-10, a the default text for each message is linked into the
-program.  Each program is able to read a locally-defined message file
-when it starts, updating the stored definitions with site-specific text.
-When the message is logged, the updated text is output. However, the
-message identifier is always included in the output so that the origin
-of the message can be identified even if the text has been changed.
-
-
-Using The System
-================
-The steps in using the system are:
-
-1. Create a message file.  This defines messages by an identification - a
-   mnemonic for the message, the convention being that these are a few
-   words separated by underscores - and text that explains the message in
-   more detail.  The file is described in more detail below.
-
-   Ideally the file should have a file type of ".mes".
-
-2. Run it through the message compiler to produce the .h and .cc files.  This
-   step should be included in the build process. (For an example of how to
-   do this, see src/lib/nsas/Makefile.am.) During development though, the
-   message compiler (found in the "src/lib/log/compiler" directory) will need
-   to be run manually.  The only argument is the name of the message file: it
-   will produce as output two files in the default directory, having the same
-   name as the input file but with file types of ".h" and ".cc".
-
-3. Include the .h file in your source code to define message symbols, and
-   make sure that the .cc file is compiled and linked into your program -
-   static initialization will add the symbols to the global dictionary.
-
-4. Declare loggers in your code and use them to log messages.  This is
-   described in more detail below.
-
-5. To set the debug level and run-time message file, call initLogger (declared
-   in logger_support.h) in the main program unit.
-
-
-Message Files
-=============
-
-File Contents and Format
-------------------------
-A message file is a file containing message definitions.  Typically there
-will be one message file for each component that declares message symbols.
-An example file could be:
-
-
-# Example message file
-
-$NAMESPACE isc::log
-
-% LOG_UNRECOGNISED_DIRECTIVE line %1: unrecognised directive '%2'
-A line starting with a dollar symbol was found, but the first word on the line
-(shown in the message) was not a recognised message compiler directive.
-
-% LOG_WRITE_ERROR error writing to %1: %2
-The specified error was encountered by the message compiler when writing to
-the named output file.
-
-
-Points to note:
-* Leading and trailing space are trimmed from the line.  Although the above
-  example has every line starting at column 1, the lines could be indented
-  if desired.
-
-* Blank lines are ignored.
-
-* Lines starting with "#" are comments are are ignored.  Comments must be on
-  a line by themselves - inline comments will be interpreted as part of the
-  text of the line.
-
-* Lines starting $ are directives.  At present, just one directive is
-  recognised:
-
-  * $NAMESPACE, which has one argument: the namespace in which the symbols are
-    created.  In the absence of a $NAMESPACE directive, symbols will be put in
-    the anonymous namespace.
-
-* Message lines.  These start with a "%" and are followed by the message
-  identification and the message text, the latter including zero or more
-  replacement tokens, e.g.
-
-     % LOG_WRITE_ERROR error writing to %1: %2
-
-  * There may be zero or more spaces between the leading "%" and the message
-    identification (which, in the example above, is the string
-    "LOG_WRITE_ERROR").
-
-  * The message identification can be any string of letters, digits and
-    underscores, but should not start with a digit.  The convention adopted
-    in BIND 10 is for the first component (before the first underscore) to be
-    a string indicating the origin of the message, and the remainder to
-    describe the message.  So in the example above, the LOG_ indicates that
-    the error originated from the logging library and the "WRITE_ERROR"
-    indicates that there was a problem in a write operation.
-
-  * The rest of the line - from the first non-space character to the
-    last non- space character - is taken exactly for the text
-    of the message. There are no restrictions on what characters may
-    be in this text, other than they be printable.  (This means that
-    both single-quote (') and double-quote (") characters are allowed.)
-    The message text may include replacement tokens (the strings "%1",
-    "%2" etc.).  When a message is logged, these are replaced with the
-    arguments passed to the logging call: %1 refers to the first argument,
-    %2 to the second etc.  Within the message text, the placeholders
-    can appear in any order and placeholders can be repeated. Otherwise,
-    the message is printed unmodified.
-
-* Remaining lines indicate an explanation for the preceding message. These
-  are intended to be processed by a separate program and used to generate
-  an error messages manual.  They are ignored by the message compiler.
-
-Message Compiler
-----------------
-The message compiler is a program built in the src/log/compiler directory.
-It is invoked by the command:
-
-    message [-h] [-v] -p] <message-file>
-
-("-v" prints the version number and exits; "-h" prints brief help text.)  The
-compiler produces source files for C++ and Python.
-
-C++ Files
----------
-Without the "-p" option, the message compiler processes the message file
-to produce two files:
-
-1) A C++ header file (called <message-file-name>.h) that holds lines of
-the form:
-
-   namespace <namespace> {
-   extern const isc::log::MessageID LOG_WRITE_ERROR;
-      :
-   }
-
-The symbols define the keys in the global message dictionary, with the
-namespace enclosing the symbols set by the $NAMESPACE directive.
-
-(This is the reason for the restriction on message identifiers - they
-have to be valid C++ symbol names.)
-
-2) A C++ source file (called <message-file-name>.cc) that holds the definitions
-of the global symbols and code to insert the symbols and messages into the map.
-
-Symbols are defined to be equal to strings holding the identifier, e.g.
-
-   extern const isc::log::MessageID LOG_WRITE_ERROR = "LOG_WRITE_ERROR";
-
-(The implementation allows symbols to be compared.  However, use of strings
-should not be assumed - a future implementation may change this.)
-
-In addition, the file declares an array of identifiers/messages and an object
-to add them to the global dictionary:
-
-    namespace {
-    const char* values[] = {
-        identifier1, text1,
-        identifier2, text2,
-        :
-        NULL
-    };
-
-    const isc::log::MessageInitializer initializer(values);
-    }
-
-The constructor of the MessageInitializer object retrieves the singleton
-global Dictionary object (created using standard methods to avoid the
-"static initialization fiasco") and adds each identifier and text to it.
-A check is made as each is added; if the identifier already exists, it is
-added to "overflow" vector; the vector is printed to the main logging output
-when logging is finally enabled (to indicate a programming error).
-
-Python Files
-------------
-If the "-p" option is given, the compiler produces a Python module defining
-the messages.  The format of this is:
-
-import isc.log
-    :
-LOG_WRITE_ERROR = isc.log.create_message("LOG_WRITE_ERROR",
-        "error writing to %1 : %2")
-
-(The definition is output on one line - it is split across two lines in this
-document for readability.)
-
-The module can be imported into other Python code, and messages logged
-in a similar way to C++ using the Python logging library.
-
-Using the Logging - C++
-=======================
-1. Build message header file and source file as describe above.
-
-2. The main program unit must include a call to isc::log::initLogger()
-   (described in more detail below) to set the logging severity, debug log
-   level, and external message file:
-
-   a) The logging severity is one of the enum defined in logger.h, i.e.
-
-        isc::log::DEBUG
-        isc::log::INFO
-        isc::log::WARN
-        isc::log::ERROR
-        isc::log::FATAL
-        isc::log::NONE
-
-   b) The debug log level is only interpreted when the severity is
-      DEBUG and is an integer ranging from 0 to 99.  0 should be used
-      for the highest-level debug messages and 99 for the lowest-level
-      (and typically more verbose) messages.
-
-   c) The external message file.  If present, this is the same as a
-      standard message file, although it should not include any
-      directives. (A single directive of a particular type will be
-      ignored; multiple directives will cause the read of the file to
-      fail with an error.)
-
-   The settings remain in effect until the logging configuration is read,
-   and so provide the default logging during program initialization.
-
-3. Declare a logger through which the message will be logged.
-
-       isc::log::Logger logger("name");
-
-   The string passed to the constructor is the name of the logger (it
-   can be any string) and is used when configuring it.  Loggers with
-   the same name share the same configuration.
-
-4. Issue logging calls using supplied macros in "log/macros.h", e.g.
-
-       LOG_ERROR(logger, LOG_WRITE_ERROR).arg("output.txt");
-
-   (The macros are more efficient that calls to the methods on the logger
-   class: they avoid the overhead of evaluating the parameters to arg()
-   if the settings are such that the message is not going to be output.)
-
-Using the Logging - Python
-==========================
-1. Build message module as describe above.
-
-2. The main program unit must include a call to isc.log.init()
-   (described in more detail below) to set the to set the logging
-   severity, debug log level, and external message file:
-
-   a) The logging severity is one of the strings:
-
-        DEBUG
-        INFO
-        WARN
-        ERROR
-        FATAL
-        NONE
-
-   b) The debug log level is only interpreted when the severity is
-      DEBUG and is an integer ranging from 0 to 99.  0 should be used
-      for the highest-level debug messages and 99 for the lowest-level
-      (and typically more verbose) messages.
-
-   c) The external message file.  If present, this is the same as a
-      standard message file, although it should not include any
-      directives. (Any that are there will be ignored.)
-
-   The settings remain in effect until the logging configuration is read,
-   and so provide the default logging during program initialization.
-
-3. Declare a logger through which the message will be logged.
-
-       isc.log.Logger logger("name")
-
-   The string passed to the constructor is the name of the logger (it
-   can be any string) and is used when configuring it.  Loggers with
-   the same name share the same configuration.
-
-4. Issue calls to the logging methods:
-
-       logger.error(LOG_WRITE_ERROR, "output.txt");
-
-Logging Initialization
-======================
-In all cases, if an attempt is made to use a logging method before the logging
-has been initialized, the program will terminate with a LoggingNotInitialized
-exception.
-
-C++
----
-Logging Initialization is carried out by calling initLogger().  There are two
-variants to the call, one for use by production programs and one for use by
-unit tests.
-
-Variant #1, Used by Production Programs
----------------------------------------
-void isc::log::initLogger(const std::string& root,
-                          isc::log::Severity severity = isc::log::INFO,
-                          int dbglevel = 0, const char* file = NULL,
-                          bool buffer = false);
-
-This is the call that should be used by production programs:
-
-root
-Name of the program (e.g. "b10-auth").  This is also the name of the root
-logger and is used when configuring logging.
-
-severity
-Default severity that the program will start logging with.  Although this may
-be overridden when the program obtains its configuration from the configuration
-database, this is the severity that it used until then.  (This may be set by
-a command-line parameter.)
-
-dbglevel
-The debug level used if "severity" is set to isc::log::DEBUG.
-
-file
-The name of a local message file.  This will be read and its definitions used
-to replace the compiled-in text of the messages.
-
-buffer
-If set to true, initial log messages will be internally buffered, until the
-first time a logger specification is processed. This way the program can
-use logging before even processing its logging configuration. As soon as any
-specification is processed (even an empty one), the buffered log messages will
-be flushed according to the specification. Note that if this option is used,
-the program SHOULD call one of the LoggerManager's process() calls (if you
-are using the built-in logging configuration handling in ModuleCCSession,
-this is automatically handled). If the program exits before this is done,
-all log messages are dumped in a raw format to stdout (so that no messages
-get lost).
-
-Variant #2, Used by Unit Tests
-------------------------------
-    void isc::log::initLogger()
-
-This is the call that should be used by unit tests.  In this variant, all the
-options are supplied by environment variables. (It should not be used for
-production programs to avoid the chance that the program operation is affected
-by inadvertently-defined environment variables.)
-
-The environment variables are:
-
-B10_LOGGER_ROOT
-Sets the "root" for the unit test.  If not defined, the name "bind10" is used.
-
-B10_LOGGER_SEVERITY
-The severity to set for the root logger in the unit test.  Valid values are
-"DEBUG", "INFO", "WARN", "ERROR", "FATAL" and "NONE".  If not defined, "INFO"
-is used.
-
-B10_LOGGER_DBGLEVEL
-If B10_LOGGER_SEVERITY is set to "DEBUG", the debug level.  This can be a
-number between 0 and 99, and defaults to 0.
-
-B10_LOGGER_LOCALMSG
-If defined, points to a local message file.  The default is not to use a local
-message file.
-
-B10_LOGGER_DESTINATION
-The location to which log message are written.  This can be one of:
-
-   stdout               Message are written to stdout
-   stderr               Messages are written to stderr
-   syslog[:facility]    Messages are written to syslog.  If the optional
-                        "facility" is used, the messages are written using
-                        that facility.  (This defaults to "local0" if not
-                        specified.)
-   Anything else        Interpreted as the name of a file to which output
-                        is appended.  If the file does not exist, a new one
-                        is opened.
-
-In the case of "stdout", "stderr" and "syslog", they must be written exactly
-as is - no leading or trailing spaces, and in lower-case.
-
-Python
-------
-To be supplied
-
-
-Severity Guidelines
-===================
-When using logging, the question arises, what severity should a message
-be logged at?  The following is a suggestion - as always, the decision
-must be made in the context of which the message is logged.
-
-One thing that should always be borne in mind is whether the logging
-could be used as a vector for a DOS attack.  For example, if a warning
-message is logged every time an invalid packet is received, an attacker
-could simply send large numbers of invalid packets.  (Of course, warnings
-could be disabled (or just warnings for that that particular logger),
-but nevertheless the message is an attack vector.)
-
-FATAL
------
-The program has encountered an error that is so severe that it cannot
-continue (or there is no point in continuing).  When a fatal error
-has been logged, the program will usually exit immediately (or shortly
-afterwards) after dumping some diagnostic information.
-
-ERROR
------
-Something has happened such that the program can continue but the
-results for the current (or future) operations cannot be guaranteed to
-be correct, or the results will be correct but the service is impaired.
-For example, the program started but attempts to open one or more network
-interfaces failed.
-
-WARN
-----
-An unusual event  happened.  Although the program will continue working
-normally, the event was sufficiently out of the ordinary to warrant
-drawing attention to it.  For example, at program start-up a zone was
-loaded that contained no resource records,
-
-INFO
-----
-A normal but significant event has occurred that should be recorded,
-e.g. the program has started or is just about to terminate, a new zone
-has been created, etc.
-
-DEBUG
------
-This severity is only enabled on for debugging purposes.  A debug level is
-associated with debug messages, level 0 (the default) being for high-level
-messages and level 99 (the maximum) for the lowest level.  How the
-messages are distributed between the levels is up to the developer.
-So if debugging the NSAS (for example), a level 0 message might record
-the creation of a new zone, a level 10 recording a timeout when trying
-to get a nameserver address, but a level 50 would record every query for
-an address. (And we might add level 70 to record every update of the RTT.)
-
-Note that like severities, levels are cumulative; so if level 25 is
-set as the debug level, all debug levels from 0 to 25 will be output.
-In fact, it is probably easier to visualise the debug levels as part of
-the severity system:
-
-    FATAL                High
-    ERROR
-    WARN
-    INFO
-    DEBUG level 0
-    DEBUG level 1
-       :
-    DEBUG level 99       Low
-
-When a particular severity is set, it - and all severities and/or debug
-levels above it - will be logged.
-
-To try to ensure that the information from different modules is roughly
-comparable for the same debug level, a set of standard debug levels has
-been defined for common type of debug output.  However, modules are free
-to set their own debug levels or define additional ones.
-
-Logging Sources v Logging Severities
-------------------------------------
-When logging events, make a distinction between events related to the
-server and events related to DNS messages received.  Caution needs to
-be exercised with the latter as, if the logging is enabled in the normal
-course of events, such logging could be a denial of service vector. For
-example, suppose that the main authoritative service logger were to
-log both zone loading and unloading as INFO and a warning message if
-it received an invalid packet. An attacker could make the INFO messages
-unusable by flooding the server with malformed packets.
-
-There are two approaches to get round this:
-
-a) Make the logging of packet-dependent events a DEBUG-severity message.
-DEBUG is not enabled by default, so these events will not be recorded
-unless DEBUG is specifically chosen.
-
-b) Record system-related and packet-related messages via different loggers
-(e.g.  in the example given, server events could be logged using the
-logger "auth" and packet-related events at that level logged using the
-logger "pkt-auth".)  As the loggers are independent and the severity
-levels independent, fine-tuning of what and what is not recorded can
-be achieved.
-
-
-Notes
-=====
-The message compiler is written in C++ (instead of Python) because it
-contains a component that reads the message file.  This component is used
-in both the message compiler and the server; in the server it is used
-when the server starts up (or when triggered by a command) to read in
-a message file to overwrite the internal dictionary.  Writing it in C++
-means there is only one piece of code that does this functionality.

+ 762 - 0
src/lib/log/logging.dox

@@ -0,0 +1,762 @@
+// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Note: the prefix "log" to all labels is an abbreviation for "Logging"
+// and is used to prevent a clash with symbols in any other Doxygen file.
+
+/**
+@page logBind10Logging BIND 10 Logging
+
+@section logBasicIdeas Basic Ideas
+
+The BIND 10 logging system is based on the log4J logging system
+common in Java development, and includes the following ideas:
+
+- A set of severity levels.
+- A hierarchy of logging sources.
+- Separation of message use from message text.
+
+@subsection logSeverity Message Severity
+Each message logged by BIND 10 has a severity associated with it, ranging
+from FATAL - the most severe - to DEBUG - messages output as the code
+executes to facilitate debugging.  In order of decreasing severity,
+the levels are:
+
+<dl>
+<dt>FATAL</dt>
+<dd>The program has encountered an error that is so severe that it
+cannot continue (or there is no point in continuing).  For example, an
+unhandled exception generated deep within the code has been caught by the
+top-level program. When a fatal error has been logged, the program will
+exit immediately (or shortly afterwards) after dumping some diagnostic
+information.</dd>
+
+<dt>ERROR</dt>
+<dd>Something has happened such that the program can continue but the
+results for the current (or future) operations cannot be guaranteed to
+be correct, or the results will be correct but the service is impaired.
+For example, the program started but attempts to open one or more network
+interfaces failed.</dd>
+
+<dt>WARN</dt>
+<dd>(Warning) An unusual event  happened.  Although the program will
+continue working normally, the event was sufficiently out of the ordinary
+to warrant drawing attention to it.  For example, the authoritative
+server loaded a zone that contained no resource records.</dd>
+
+<dt>INFO</dt>
+<dd>(Information) A normal but significant event has occurred that should
+be recorded, e.g. the program has started or is just about to terminate,
+a new zone has been created, etc.</dd>
+
+<dt>DEBUG</dt>
+<dd>Debug messages are output at this severity.  Each message also
+has a debug level associated with it, ranging from 0 (the default)
+for high-level messages and level 99 (the maximum) for the the lowest
+level.</dd>
+</dl>
+
+When logging is enabled for a component, it is enabled for a particular
+severity level and all higher severities.  So if logging is enabled
+for INFO messages, WARN, ERROR and FATAL messages will also be logged,
+but not DEBUG ones.  If enabled for ERROR, only ERROR and FATAL messages
+will be logged.
+
+As noted above, DEBUG messages are also associated with a debug level.
+This allows the developer to control the amount of debugging information
+produced; the higher the debug level, the more information is output.
+For example, if debugging the NSAS (nameserver address store), debug
+levels might be assigned as follows: a level 0 debug message records
+the creation of a new zone, a level 10 logs every timeout when trying
+to get a nameserver address, a level of 50 records every query for an
+address and a level of 70 records every update of the round-trip time.
+
+Like severities, levels are cumulative; so if level 25 is set as the
+debug level, all debug messages associated levels 0 to 25 (inclusive)
+will be output.  In fact, it is probably easier to visualise the debug
+levels as part of the severity system:
+@code
+FATAL            Most severe
+ERROR
+WARN
+INFO
+DEBUG level 0
+DEBUG level 1
+   :
+DEBUG level 99   Least severe
+@endcode
+When a particular debug level is set, it - and all debug levels and
+severities above it - will be logged.
+
+To try to ensure that the information from different modules is roughly
+comparable for the same debug level, a set of standard debug levels has
+been defined for common types of debug output.  (These can be found in
+@ref log_dbglevels.h) However, modules are free to set their own debug
+levels or define additional ones.
+
+@subsection logHierarchical Hierarchical Logging System
+
+When a program writes a message to the logging system, it does so using an
+instance of the @ref isc::log::Logger class.  As well as performing the
+write of the message, the logger identifies the source of the message:
+different sources can write to different destinations and can log
+different severities of messages.  For example, the logger associated
+with the resolver's cache code could write debugging and other messages
+to a file while all other components only write messages relating to
+errors to the syslog file.
+
+The loggers are hierarchical in that each logger is the child of another
+logger.  The top of the hierarchy is the root logger; this does not
+have a parent.  The reason for this hierarchy is that unless a logger
+explicitly assigns a value to an attribute (such as severity of messages
+it should log), it picks it up the value from the parent.  In BIND 10,
+each component (b10-auth, b10-resolver etc.)  has a root logger (named
+after the program) and every other logger in the component is a child
+of that.  So in the example above, the error/syslog attributes could be
+associated with the b10-resolver logger while the logger associated with
+the cache sets its own values for the debug/file attributes.
+
+More information about the logging hierarchy can be found in the section
+on Logging configuration in the <a
+href="http://bind10.isc.org/docs/bind10-guide.html#logging">BIND 10
+Guide</a>.
+
+@subsection logSeparationUseText Separation of Messages Use from Message Text
+
+Separating the use of the message from the text associated with it -
+in essence, defining message text in an external file - allows for the
+replacement the supplied text of the messages with a local language version.
+It also means that other attributes can be associated with the message,
+for example, an explanation of the meaning of the message and other
+information such as remedial action in the case of errors.
+
+Each message has an identifier such as "LOG_WRITE_ERROR".
+Within the program, this is the symbol passed to the logging system
+which uses the symbol as an index into a dictionary to retrieve the message
+associated with it (e.g. "unable to open %1 for input"), after which it
+substitutes any message parameters (in this example, the name of the file
+where the write operation failed) and logs the result to the destination.
+
+In BIND 10, a the default text for each message is linked into the
+program.  Each program is able to read a locally-defined message file
+when it starts, updating the stored definitions with site-specific text.
+When the message is logged, the updated text is output. However, the
+message identifier is always included in the output so that the origin
+of the message can be identified even if the text has been changed.
+
+@note Local message files have not yet been implemented in BIND 10.
+
+
+
+@section logDeveloperUse Using Logging in a BIND 10 Component
+
+The steps in using the logging system in a BIND 10 component (such as
+an executable or library) are:
+
+<ol>
+<li>Create a message file.  This defines messages by an identification
+string and and text that explains the message in more detail.  Ideally the
+file should have a file type of ".mes".</li>
+
+<li>Run it through the message compiler to produce the files for your
+module.  This step should be included in the build process.  The message
+compiler is a BIND10 program and is one of the first programs built and
+linked in the build process. As a result, it should be available for
+compiling the message files of all BIND 10 components and libraries.
+
+For C++ development, the message compiler produces two files in the
+default directory, having the same name as the input file but with file
+types of ".h" and ".cc". For Python, the message compiler will produce
+a Python module containing the symbols.</li>
+
+<li>Include the resultant files in your source code to define message symbols,
+and (for C++) compile the code and link it into your program.</li>
+
+<li>Declare loggers in your code and use them to log messages.</li>
+
+<li>Call the logger initialization function in the program's main module.</li>
+
+</ol>
+
+The following sections describe these steps in more detail.
+
+
+@subsection logMessageFiles Create a Message File
+
+A message file contains message definitions.  Typically there
+will be one message file for each component that uses BIND 10 logging.
+An example file could be:
+
+@code
+# Example message file
+
+$NAMESPACE isc::log
+
+% LOG_UNRECOGNISED_DIRECTIVE line %1: unrecognised directive '%2'
+A line starting with a dollar symbol was found, but the first word on the line
+(shown in the message) was not a recognised message compiler directive.
+
+% LOG_WRITE_ERROR error writing to %1: %2
+The specified error was encountered by the message compiler when writing to
+the named output file.
+@endcode
+
+Points to note are:
+
+<ul>
+<li>Leading and trailing spaces are trimmed from each line before it
+is processed.  Although the above example has every line starting at
+column 1, the lines could be indented if desired.</li>
+
+<li>Lines starting with "#" are comments are are ignored.  Comments must
+be on a line by themselves; inline comments will be interpreted as part
+of the text of that line.</li>
+
+<li>Lines starting with "$" are directives.  At present, just one
+directive is recognised:
+    <dl>
+        <dt>$NAMESPACE &lt;namespace-name&gt;</dt>
+        <dd>The sole argument is the name of the namespace in which the
+        symbols are created.  In the absence of a $NAMESPACE directive,
+        symbols will be put in the anonymous namespace.</dd>
+    </dl>
+</li>
+
+<li>Lines starting with "%" are message definitions and comprise the message
+identification and the message text.  For example:
+@code
+% LOG_WRITE_ERROR error writing to %1: %2
+@endcode
+
+There may be zero or more spaces between the leading "%" and the
+message identification (which, in the example above, is the string
+"LOG_WRITE_ERROR").</li>
+
+<li>The message identification can be any string of letters, digits and
+underscores, but must not start with a digit.</li>
+
+<li>The rest of the line - from the first non-space character to the
+last non- space character - is the text of the message. There are no
+restrictions on what characters may be in this text, other than they be
+printable (so both single-quote (') and double-quote (") characters are
+allowed).  The message text may include replacement tokens (the strings
+"%1", "%2" etc.).  When a message is logged, these are replaced with the
+arguments passed to the logging call: %1 refers to the first argument,
+%2 to the second etc.  Within the message text, the placeholders can
+appear in any order and placeholders can be repeated. Otherwise, the
+message is printed unmodified.</li>
+
+<li>Remaining lines indicate an explanation for the preceding message.
+The explanation can comprise multiple paragraphs, the paragraphs being
+separated by blank lines.  These lines are intended to be processed by a
+separate program to generate an error messages manual; they are ignored
+by the message compiler.</li>
+
+<li>Except when used to separate paragraphs in the message explanation,
+blank lines are ignored.</li>
+</ul>
+
+Although there are few restriction on what can be in the message
+identifcation and text, there are a number of conventions used by BIND
+10, both in the contents of the message and in the usage.  All code
+should adhere to these:
+
+<ul>
+<li>Message identifications should include at least one underscore.
+The component before the first underscore is a string indicating the
+origin of the message, and the remainder describes the condition.
+So in the example above, the LOG indicates that the error originated
+from the logging library and the "WRITE_ERROR" indicates that there was
+a problem in a write operation.</li>
+
+<li>The part of the message identification describing the error (e.g.
+"WRITE_ERROR" in the example above) should comprise no more than
+two or three words separated by underscores.  An excessive number
+of words or overly long message identification should be avoided;
+such information should be put in the text of the message.  For example,
+"RESOLVER_ERROR_FETCHING_NAME_FROM_UPSTREAM_SERVER" is excessively long,
+"RESOLVER_FETCH_ERROR" being better.</li>
+
+<li>Similarly, the text of the message should be reasonably concise.  It should
+include enough information (possibly supplied at run-time in the form of
+parameters) to allow further investigations to be undertaken if required.
+
+Taking the above example, a suitable error message to indicate that the
+resolver has failed to read a name from an upstream authoritative server
+could be:
+
+@code
+% RESOLVER_FETCH_ERROR fetch from %1 failed, error code %2 (%3)
+@endcode
+
+... where %1 indicates the name or IP address of the server to which the
+fetch was sent, %2 the errno value returned and %3 the message associated
+with that error number (retrieved via a call to "strerror()").
+
+</li>
+
+<li>The message should not have a comma after the message identification.
+The message text should neither start with a capital letter (unless
+the first word is a proper noun or is normally written in capitals)
+nor end with a period. The message reporting system takes care of such
+punctuation.</li>
+
+<li>The parameters substituted into the message text should not include
+line breaks.  Messages are normally output to the syslog file which
+has the inbuilt assumption of one line per message. Splitting a message
+across multiple lines makes it awkward to search the file for messages
+and associated information.</li>
+
+<li>The message identifier should be unique across the entire BIND 10
+system.  (An error will be reported at system start-up if an identifier
+is repeated.)</li>
+
+<li>A particular message identifier should only be used at one place in
+the BIND 10 code. In this way, if the message indicates a problem, the
+code in question can be quickly identified.</li>
+
+<li>The explanation of the message - the free-form text following the
+message identification - appears in the BIND 10 message manual.  It
+should:
+
+<ul>
+<li>Describe the serverity of the message (debug, informational etc.)</li>
+
+<li>Expand on the text of the message.  In some cases, such as
+debug messages, the message text may provide more or less sufficient
+description.  For warnings and errors, the explanation should provide
+sufficient background to the problem to allow a non-developer to
+understand the issue and to begin fault-finding.  If possible, the
+explanation should also include suggested remedial action.</li>
+</ul>
+</ul>
+
+@subsection logSourceFiles Produce Source Files
+The message file created in the previous step is then run through the
+message compiler to produce source files that are included in the BIND
+10 programs.
+
+@subsubsection logMessageCompiler Message Compiler
+The message compiler is a program built in the src/log/compiler directory.
+It is invoked by the command:
+@code
+message [-h] [-v] [-p] [-d dir] <message-file>
+@endcode
+"-v" prints the version number and exits; "-h" prints brief help text.
+The compiler produces source files for C++ unless the "-p" switch is
+specified, in which case it produces Python code.  Finally, the "-d"
+switch directs the compiler to produce the output files in the specified
+directory (the default being the current working directory).
+
+<b>C++ Files</b><br/>
+Without the "-p" option, the message compiler processes the message file
+to produce two files:
+
+<ol>
+<li>A C++ header file (called <message-file-name>.h) holding lines of
+the form:
+@code
+namespace <namespace-name> {
+   extern const isc::log::MessageID LOG_BAD_DESTINATION;
+   extern const isc::log::MessageID LOG_BAD_SEVERITY;
+      :
+}
+@endcode
+The symbols define keys in the global message dictionary, with
+the namespace enclosing the symbols set by the $NAMESPACE directive.
+(This is the reason for the restriction on message identifiers - they
+have to be valid C++ symbol names.)</li>
+
+<li>A C++ source file (called <message-file-name>.cc) that holds the definitions
+of the global symbols and code to insert the symbols and messages into
+an internal dictionary.
+
+Symbols are defined to be equal to strings equal to the identifier, e.g.
+@code
+extern const isc::log::MessageID LOG_BAD_DESTINATION = "LOG_BAD_DESTINATION";
+extern const isc::log::MessageID LOG_BAD_SEVERITY = "LOG_BAD_SEVERITY";
+   :
+@endcode
+(The current implementation allows symbols to be compared.  However,
+use of strings should not be assumed - a future implementation may change
+this.)  In addition, the file declares an array of identifiers/messages
+and an object to add them to the global dictionary, e.g.:
+@code
+namespace {
+    const char* values[] = {
+       "LOG_BAD_DESTINATION", "unrecognized log destination: %1",
+       "LOG_BAD_SEVERITY", "unrecognized log severity: %1",
+        :
+        NULL
+    };
+    const isc::log::MessageInitializer initializer(values);
+}
+@endcode
+
+The constructor of the @ref isc::log::MessageInitializer object retrieves
+the singleton global @ref isc::log::MessageDictionary object (created
+using standard methods to avoid the "static initialization fiasco") and
+adds each identifier and associated text to it. These constructors are run
+when the program starts; a check is made as each identifier is added and,
+if the identifier already exists in the dictionary, a warning message
+is printed to the main logging output when logging is finally enabled.
+The appearance of such a message indicates a programming error.
+</li>
+</ol>
+
+<b>Python Files</b><br/>
+If the "-p" option is given, the compiler produces a Python module defining
+the messages.  The content of this is of the form:
+@code
+import isc.log
+    :
+LOG_WRITE_ERROR = isc.log.create_message("LOG_WRITE_ERROR",
+        "error writing to %1 : %2")
+@endcode
+(The definition is output on one line - it is split across two lines in this
+document for readability.)
+
+The module can be imported into other Python code, and messages logged
+in a similar way to C++ using the Python logging library.
+
+@subsubsection logMakefile Include Message Compilation in Makefile
+The source file for the messages is the ".mes" file, but the files used
+by the code (which, in the case of C++, must be compiled and linked)
+are the output of the message compiler.  (The compiler is produced very
+early on in the BIND 10 build sequence, so is available for use in the
+building of subsequent components.)  To allow this, certain dependencies
+must be included in the Makefile.am for each component that uses logging.
+
+<b>Including Message files in C++ Component Builds</b><br/>
+The following segment from the "hooks" Makefile.am illustrates
+the entries needed.
+@code
+# Define rule to build logging source files from message file
+hooks_messages.h hooks_messages.cc: s-messages
+
+s-messages: hooks_messages.mes
+	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/hooks/hooks_messages.mes
+	touch $@
+
+# Tell automake that the message files are built as part of the build process
+# (so that they are built before the main library is built).
+BUILT_SOURCES = hooks_messages.h hooks_messages.cc
+
+# Ensure that the message file is included in the distribution
+EXTRA_DIST = hooks_messages.mes
+
+# Get rid of generated message files on a clean
+CLEANFILES = *.gcno *.gcda hooks_messages.h hooks_messages.cc s-messages
+@endcode
+The first two rules relate the output .h and .cc files produced by the
+message compiler to the input .mes file.  The intermediate "s-messages"
+file is used to overcome synchronization issues with parallel builds
+(where "make" uses multiple processes running in parallel).  Note that the
+reference to both the compiler and the input message file are via absolute
+paths defined in terms of Automake macros.  In particular it is important
+that the message compiler - which is created during the build process - is
+referred to via the "top_builddir" macro, whereas the input message file -
+which is in the repository - is accessed through the "top_srcdir" macro.
+
+The BUILT_SOURCES line notifies the Automake that the .h and .cc files
+need to be created before they can be used in the compilation, so
+instructs it to organse things so that the message compiler is run first.
+
+As the .mes file is not directly included in any compilation, it will
+not be automatically copied into a distribution created through this
+Makefile.am.  The EXTRA_DIST line informs Automake that this file does
+need to be included.
+
+Finally, the intermediate files - the .cc and .h file, as well as the
+intermediate s-messages file - need to be removed when "make clean" is run.
+These files are therefore included in the definition of the CLEANFILES macro.
+
+Not shown are the Makefile.am lines where the .h and .cc file are used.  These
+are the same as other lines specifying .h and .cc source files.
+
+<b>Including Message files in Python Component Builds</b><br/>
+The following (modified) segments from the "xfrin" Makefile.am illustrates
+the entries needed.
+
+@code
+CLEANFILES  = $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py
+CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.pyc
+  :
+EXTRA_DIST += xfrin_messages.mes
+  :
+# Define rule to build logging source files from message file
+$(PYTHON_LOGMSGPKG_DIR)/work/xfrin_messages.py : xfrin_messages.mes
+	$(top_builddir)/src/lib/log/compiler/message \
+	-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/xfrin_messages.mes
+@endcode
+The CLEANFILES lines remove the created Python (and compiled Python)
+code when "make clean" is run.
+
+The EXTRA_DIST line ensures that the .mes file is copied to the
+distribution tarball.
+
+The final dependency shows the use of the message compiler to
+create the Python message module in a working directory.
+
+
+@subsection logUsage Using Logging Files in Program Development
+
+@subsubsection logCppUsage Use in a C++ Program or Module
+To use logging in a C++ program or module:
+
+<ol>
+<li>Build the message header file and source file as described above.</li>
+
+<li>In each C++ file in which logging is to be used, declare a logger
+through which the message will be logged.
+
+@code
+isc::log::Logger logger("name");
+@endcode
+This declaration can be per-function, or it can be declared statically
+in file scope.  The string passed to the constructor is the name of
+the logger (it can be any string) and is used when configuring it.
+(Remember though that the name of root logger for the program will be
+prepended to the name chosen.  So if, for example, the name "cache"
+is chosen and the model is included in the "b10-resolver" program, the
+full name of the logger will be "b10-resolver.cache".)  Loggers with
+the same name share the same configuration.  For this reason if, as is
+usual, messages logged in different files in the same component (e.g.
+hooks module, nameserver address store, etc.) originate from loggers
+with the same name, the logger declaration can be placed into a header
+file.</li>
+
+<li>Issue logging calls using supplied macros in "log/macros.h", e.g.
+@code
+LOG_ERROR(logger, LOG_WRITE_ERROR).arg("output.txt");
+LOG_DEBUG(nsas_logger, NSAS_DBG_TRACE, NSAS_LOOKUP_CANCEL).arg(zone);
+@endcode
+All macros (with the exception of LOG_DEBUG) take two arguments:
+the C++ logger object that will be used to log the message, and the
+identification of the message to be logged.  LOG_DEBUG takes three
+arguments, the additional one being the debug level associated with
+the message.  The .arg() call appended to the end of the LOG_XXX()
+macro handles the arguments to the message.  A chain of these is used
+in cases where a message takes multiple arguments, e.g.
+@code
+LOG_DEBUG(nsas_logger, NSAS_DBG_RTT, NSAS_UPDATE_RTT)
+          .arg(addresses_[family][index].getAddress().toText())
+          .arg(old_rtt).arg(new_rtt);
+@endcode
+Using the macros is more efficient than direct calls to the methods on
+the logger class: they avoid the overhead of evaluating the parameters
+to arg() if the logging settings are such that the message is not going
+to be output (e.g. it is a DEBUG message and the logging is set to output
+messages of INFO severity or above).</li>
+
+<li>The main program unit must include a call to isc::log::initLogger()
+(described in more detail below) to set the initial logging severity, debug log
+level, and external message file.
+</ol>
+
+@subsubsection logPythonUsage Use in a Python Module
+To use logging in a Python module:
+<ol>
+<li>Build message module as described above.</li>
+
+<li>Declare a logger through which the message will be logged.
+@code
+isc.log.Logger logger("name")
+@endcode
+The string passed to the constructor is the name of the logger (it can
+be any string) and is used when configuring it.  Loggers with the same
+name share the same configuration.</li>
+
+<li>Issue calls to the logging methods:
+@code
+logger.error(LOG_WRITE_ERROR, "output.txt")
+@endcode
+The message parameters are included as trailing arguments in the
+logger call.</li>
+
+<li>The main program unit must include a call to isc.log.init() (described
+in more detail below) to set the to set the logging severity, debug log
+level, and external message file.  The settings remain in effect until
+the logging configuration is read, so are the ones used during program
+initialization.</li>
+</ol>
+
+
+@subsection logInitialization Logging Initialization
+In all cases, if an attempt is made to use a logging method before
+the logging has been initialized, the program will terminate with a
+LoggingNotInitialized exception.
+
+@subsection logInitializationCpp C++ Initialization
+Logging Initialization is carried out by calling @ref
+isc::log::initLogger().  There are two variants to the call, one for
+use by production programs and one for use by unit tests.
+
+@subsubsection logInitializationCppVariant1 Variant #1, Used by Production Programs
+The call that should be used by all production programs is:
+@code
+void isc::log::initLogger(const std::string& root,
+                          isc::log::Severity severity = isc::log::INFO,
+                          int dbglevel = 0, const char* file = NULL,
+                          bool buffer = false);
+@endcode
+Arguments are:
+<dl>
+<dt><code>root</code></dt>
+<dd>Name of the root logger.  This should be the name of the program
+(e.g. "b10-auth") and is used when configuring logging.</dd>
+
+<dt><code>severity</code></dt>
+<dd>Default severity that the program will start logging with.  Although
+this may be overridden when the program obtains its configuration from
+the configuration database, this is the severity that it used until then.
+The logging severity is one of the enum defined in @ref logger.h, i.e.
+
+@code
+isc::log::DEBUG
+isc::log::INFO
+isc::log::WARN
+isc::log::ERROR
+isc::log::FATAL
+isc::log::NONE
+@endcode
+
+(The level NONE may be used to disable logging.)
+</dd>
+
+<dt><code>dbglevel</code></dt>
+<dd>The debug log level is only interpreted when the severity is
+isc::log::DEBUG and is an integer ranging from 0 to 99.  0 should be
+used for the highest-level debug messages and 99 for the lowest-level
+(and typically more verbose) messages.</dd>
+
+<dt><code>file</code></dt>
+<dd>The name of a local message file.  This will be read and its
+definitions used to replace the compiled-in text of the messages.
+The default value of NULL indicates that no local message file is
+supplied.</dd>
+
+<dt><code>buffer</code></dt>
+<dd>If set to true, initial log messages will be internally buffered,
+until the first time a logger specification is processed. This
+way the program can use logging before even processing its logging
+configuration. As soon as any specification is processed (even an
+empty one), the buffered log messages will be flushed according to
+the specification. Note that if this option is used, the program
+SHOULD call one of the @ref isc::log::LoggerManager::process() calls.
+(If you are using the built-in logging configuration handling in @ref
+isc::config::ModuleCCSession, this is automatically handled.) If the
+program exits before this is done, all log messages are dumped in a raw
+format to stdout (so that no messages get lost).</dd>
+</dl>
+
+@subsubsection logInitializationCppVariant2 Variant #2, Used by Unit Tests
+@code
+void isc::log::initLogger()
+@endcode
+This is the call that should be used by unit tests.  In this variant,
+all the options are supplied by environment variables: it should not
+be used for production programs to avoid the chance that the program
+operation is affected by inadvertently-defined environment variables. The
+environment variables are:
+
+<dl>
+<dt>B10_LOGGER_ROOT</dt>
+<dd>Sets the "root" for the unit test.  If not defined, the name "bind10"
+is used.</dd>
+
+<dt>B10_LOGGER_SEVERITY</dt>
+<dd>The severity to set for the root logger in the unit test.
+Valid values are "DEBUG", "INFO", "WARN", "ERROR", "FATAL" and "NONE".
+If not defined, "INFO" is used.</dd>
+
+<dt>B10_LOGGER_DBGLEVEL</dt>
+<dd>If B10_LOGGER_SEVERITY is set to "DEBUG", the debug level.  This can
+be a number between 0 and 99, and defaults to 0.</dd>
+
+<dt>B10_LOGGER_LOCALMSG</dt>
+<dd>If defined, points to a local message file.  The default is not to
+use a local message file.</dd>
+
+<dt>B10_LOGGER_DESTINATION</dt>
+<dd>The location to which log message are written.  This can be one of:
+<ul>
+<li><b>stdout</b> Message are written to stdout.</li>
+<li><b>stderr</b> Messages are written to stderr.</li>
+<li><b>syslog[:facility]</b> Messages are written to syslog.  If the
+optional "facility" is used, the messages are written using that facility.
+(This defaults to "local0" if not specified.)</li>
+<li><b>Anything else</b> Interpreted as the name of a file to which
+output is appended.  If the file does not exist, a new one is opened.</li>
+</ul>
+In the case of "stdout", "stderr" and "syslog", they must be written exactly
+as is - no leading or trailing spaces, and in lower-case.</dd>
+</dl>
+
+@subsection logInitializationPython Python Initialization
+To initialize the logger in a Python program, the "init" method must be
+called:
+@code
+isc.log.init(name, severity, debuglevel, file, buffer)
+@endcode
+
+<dl>
+<dt><code>name</code></dt>
+<dd>String giving the name of the root logger.  This is the only mandatory
+argument, the rest are optional.</dd>
+
+<dt><code>severity</code></dt>
+<dd>The severity, and is one of the strings "DEBUG", INFO" etc.
+The default is "INFO".</dd>
+
+<dt><code>debuglevel</code></dt>
+<dd>Debug level, an integer between 0 and 99. A default value of 0 will
+be used if this is not specified.</dd>
+
+<dt><code>file</code></dt>
+<dd>Name of the external message file (if present).  By default, no
+external message file is used.</dd>
+
+<dt><code>buffer</code></dt>
+<dd>If set to true, initial log messages will be internally buffered,
+until the first time a logger specification is processed. This
+way the program can use logging before even processing its logging
+configuration. By default, no buffer is used.</dd>
+</dl>
+
+
+@section logNotes Notes on the Use of Logging
+One thing that should always be kept in mind is whether the logging
+could be used as a means for a DOS attack.  For example, if a warning
+message is logged every time an invalid packet is received, an attacker
+could simply send large numbers of invalid packets.  Of course, warnings
+could be disabled (or just warnings for that that particular logger),
+but nevertheless the message is an attack vector.  As a general rule,
+if the message can be triggered by a user action, it can be used as an
+attack vector.
+
+There are two approaches to get round this:
+<ol>
+<li>Log messages generated by such user actions as DEBUG messages. DEBUG
+is not enabled by default, so these events will not be recorded unless
+DEBUG is specifically enabled.  Choosing a suitable debug level for
+such messages will select only those messages and not the more general
+debug messages.</li>
+
+<li>Record system-related and packet-related messages via different
+loggers.  As the loggers are independent and the severity levels
+independent, fine-tuning of what and what is not recorded can be achieved.</li>
+
+</ol>
+*/