Browse Source

[2566] Include logging maintenance guide into BIND 10 Developer's Manual

Convert the old logging "README" file to Doxygen format.  The opportunity
was taken to expand and edit it at the same time.
Stephen Morris 11 years ago
parent
commit
7fbc3fad3e
4 changed files with 736 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. 731 0
      src/lib/log/logging.dox

+ 4 - 4
doc/devel/mainpage.dox

@@ -81,10 +81,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.

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

@@ -0,0 +1,731 @@
+// Copyright (C) 2013  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:
+
+- <b>FATAL</b> 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.
+
+- <b>ERROR</b> 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.
+
+- <b>WARN</b> (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.
+
+- <b>INFO</b> (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.
+
+- <b>DEBUG</b> 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.
+
+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   Lease 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
+is explicitly assigned an attribute (such as severity of messages it
+should log), it picks it up 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 is in the component a child of that.  So in the
+example above, the error/syslog attributes could be associated with the
+b10-resolver logger while the debug/file attributes are associated with
+the logger associated with the cache.
+
+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 is identified by an identifier e.g. "LOG_WRITE_ERROR".
+Within the program, this is the symbol passed to the logging system.
+That 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 is a file containing 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 space 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 the line.</li>
+
+<li>Lines starting with "$" are directives.  At present, just one directive is
+recognised:
+    <ul>
+    <li><b>$NAMESPACE &lt;namespace-name&gt;</b> 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.</li>
+    </ul>
+</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.
+Neither should the message text 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
+
+@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 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:
+@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.  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 describe 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:
+</li>
+The settings remain in effect until the logging configuration is read,
+and so provide the default logging during program initialization.
+</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:
+
+<b>root</b> Name of the root logger.  This should be the name of the
+program (e.g. "b10-auth") and is used when configuring logging.
+
+<b>severity</b> 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
+
+<b>dbglevel</b> 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.
+
+<b>file</b> 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.
+
+<b>buffer</b> 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).
+
+@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:
+
+<b>B10_LOGGER_ROOT</b> Sets the "root" for the unit test.  If not defined,
+the name "bind10" is used.
+
+<b>B10_LOGGER_SEVERITY</b> 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.
+
+<b>B10_LOGGER_DBGLEVEL</b> If B10_LOGGER_SEVERITY is set to "DEBUG", the
+debug level.  This can be a number between 0 and 99, and defaults to 0.
+
+<b>B10_LOGGER_LOCALMSG</b> If defined, points to a local message file.
+The default is not to use a local message file.
+
+<b>B10_LOGGER_DESTINATION</b> 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.
+
+@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
+<b>name</b> is string giving the name of the root logger.  This is
+the only mandatory argument, the rest are optional.
+
+<b>severity</b> is the deverity, and is one of the strings "DEBUG", INFO" etc.
+The deafult is "INFO".
+
+<b>debuglevel</b> is the debug level, an integer between 0 and 99. A
+default value of 0 will be used if this is not specified.
+
+<b>file</b> is the name of the external message file (if present).
+By default, no external message file is used.
+
+<b>buffer</b> 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.
+
+
+@section logNotes Notes on the Use of Logging
+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.)
+
+@subsection logSourcesSeverities Logging Sources v Logging Severities
+When logging events, make a distinction between events related to the
+server and events related to 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 DNS server 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:
+- DEBUG is not enabled by default, so these events will not be recorded
+unless DEBUG is specifically chosen.
+
+- 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.
+
+*/