diff options
Diffstat (limited to 'src/lib/log/logging.dox')
-rw-r--r-- | src/lib/log/logging.dox | 698 |
1 files changed, 698 insertions, 0 deletions
diff --git a/src/lib/log/logging.dox b/src/lib/log/logging.dox new file mode 100644 index 0000000..8dbc02f --- /dev/null +++ b/src/lib/log/logging.dox @@ -0,0 +1,698 @@ +// Copyright (C) 2013-2021 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// 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 logKeaLogging Kea Logging + +@section logBasicIdeas Basic Ideas + +The Kea 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 Kea 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 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 visualize 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 Kea, +each component (kea-dhcp4, kea-dhcp-ddns 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 kea-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="https://kea.readthedocs.io/">Kea Administrator +Reference Manual</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 Kea, 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 Kea. + + + +@section logDeveloperUse Using Logging in a Kea Component + +The steps in using the logging system in a Kea component (such as +an executable or library) are: + +<ol> +<li>Create a message file. This defines messages by an identification +string 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 Kea 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 Kea 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".</li> + +<li>Include the resultant files in your source code to define message symbols, +and 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 Kea logging. +An example file could be: + +@code +# Example message file + +$NAMESPACE isc::log + +% LOG_UNRECOGNIZED_DIRECTIVE line %1: unrecognized 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 recognized 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 recognized: + <dl> + <dt>$NAMESPACE <namespace-name></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 +identification and text, there are a number of conventions used by Kea, +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, +"RECEIVED_EMPTY_HOSTNAME_FROM_CLIENT" is excessively long, +"EMPTY_HOSTNAME" 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 Kea +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 Kea 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 Kea message manual. It +should: + +<ul> +<li>Describe the severity 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 Kea +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 +kea-msg-compiler [-h] [-v] [-d dir] <message-file> +@endcode +"-v" prints the version number and exits; "-h" prints brief help text. +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/> + +<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> + +@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 must be compiled and linked are the output of +the message compiler. (The compiler is produced very early on in the +Kea 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 +# Ensure that the message file is included in the distribution +EXTRA_DIST = hooks_messages.mes + +# If we want to get rid of all generated messages files, we need to use +# make maintainer-clean. The proper way to introduce custom commands for +# that operation is to define maintainer-clean-local target. However, +# make maintainer-clean also removes Makefile, so running configure script +# is required. To make it easy to rebuild messages without going through +# reconfigure, a new target messages-clean has been added. +maintainer-clean-local: + rm -f hooks_messages.h hooks_messages.cc + +# To regenerate messages files, one can do: +# +# make messages-clean +# make messages +# +# This is needed only when a .mes file is modified. +messages-clean: maintainer-clean-local + +if GENERATE_MESSAGES + +# Define rule to build logging source files from message file +messages: hooks_messages.h hooks_messages.cc + @echo Message files regenerated + +hooks_messages.h hooks_messages.cc: hooks_messages.mes + $(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/lib/hooks/hooks_messages.mes + +else + +messages hooks_messages.h hooks_messages.cc: + @echo Messages generation disabled. Configure with --enable-generate-messages to enable it. + +endif +@endcode +The first rule adds a hook to make maintainer-clean which is the standard +way to regenerate all messages files. The second rule adds the new +messages-clean target to regenerate local messages files. + +The GENERATE_MESSAGES conditional part is the (re)generation of +the messages files. When configured with --enable-generate-messages +and the source (.mes file) is newer these files are generated using +the Kea message compiler. When configured without --enable-generate-messages +(the default) and the source (.mes file) is newer a message is emitted. + +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. + +And finally please note the message header (e.g. hooks_messages.h) +should be installed, i.e. in the include_HEADERS list. + +@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 "kea-resolver" program, the +full name of the logger will be "kea-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> + +@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. "kea-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 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>KEA_LOGGER_ROOT</dt> +<dd>Sets the "root" for the unit test. If not defined, the name "kea" +is used.</dd> + +<dt>KEA_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>KEA_LOGGER_DBGLEVEL</dt> +<dd>If KEA_LOGGER_SEVERITY is set to "DEBUG", the debug level. This can +be a number between 0 and 99, and defaults to 0.</dd> + +<dt>KEA_LOGGER_LOCALMSG</dt> +<dd>If defined, points to a local message file. The default is not to +use a local message file.</dd> + +<dt>KEA_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 logInitializationHooks Hooks Specific Notes +All hooks libraries should use Kea logging mechanisms. The loggers and the +library specific log messages are created in the same way as for the core +Kea modules. The loggers created within the hook library belong to the +logging hierarchy of the Kea process and their configuration can be +controlled from the Kea configuration file. If the configuration file doesn't +contain the specific configuration for the logger used in the library, +this logger is given the configuration of the root Kea logger. + +The hook libraries are loaded dynamically. This requires that the global log +messages dictionary, holding the mapping of specific log message +identifiers to the actual messages, is updated to include the messages +specified in the hook library when the library is loaded. Conversely, the +messages have to be removed from the dictionary when the library is unloaded. + +The new messages are added to the global dictionary using the +@ref isc::log::MessageInitializer::loadDictionary static function. It is +called by the @ref isc::hooks::LibraryManager::loadLibrary for each loaded +library. + +When the library is unloaded, the instance of the +@ref isc::log::MessageInitializer defined in the library is destroyed +and its destructor removes the messages registered by the destroyed +instance from the global dictionary. + +The hook library itself must not perform any action to register or +unregister log messages in the global dictionary! + +@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> + +@section logMTConsiderations Multi-Threading Consideration for Logging + +Logging is thread safe: messages emitted at the same time do not mix. + +When the KEA_LOCKFILE_DIR environment variable is not set to none +Logging to files is multi-process safe too: for instance two servers +can be configured to put log messages in the same file. + +The @c isc::log::Logger class initializes its implementation in a lazy +(i.e. on demand) but thread safe way so it is always initialized at most +once even in a multi-threaded environment. + +*/ |