mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
Check-in of some code prior to conversion of repository to git; the code is not finished!
git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac438@4169 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
35
configure.ac
35
configure.ac
@@ -327,6 +327,39 @@ if test "$lcov" != "no"; then
|
||||
fi
|
||||
AC_SUBST(USE_LCOV)
|
||||
|
||||
# Configure log4cxx header and library path
|
||||
#
|
||||
# If explicitly specified, use it.
|
||||
|
||||
AC_ARG_WITH([log4cxx],
|
||||
AC_HELP_STRING([--with-log4cxx=PATH],
|
||||
[specify directory where log4cxx is installed]),
|
||||
[log4cxx_include_path="${withval}/include"])
|
||||
|
||||
# If not specified, try some common paths. These default to
|
||||
# /usr/include if not found
|
||||
|
||||
if test -z "$with_log4cxx"; then
|
||||
log4cxxdirs="/usr/local /usr/pkg /opt /opt/local"
|
||||
for d in $log4cxxdirs
|
||||
do
|
||||
if test -d $d/include/log4cxx; then
|
||||
log4cxx_include_path=$d/include
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
CPPFLAGS_SAVES="$CPPFLAGS"
|
||||
if test "${log4cxx_include_path}" ; then
|
||||
LOG4CXX_INCLUDES="-I${log4cxx_include_path}"
|
||||
CPPFLAGS="$CPPFLAGS $LOG4CXX_INCLUDES"
|
||||
fi
|
||||
AC_CHECK_HEADER([log4cxx/logger.h],, AC_MSG_ERROR([Missing log4cxx header files.]))
|
||||
CPPFLAGS="$CPPFLAGS_SAVES"
|
||||
AC_SUBST(LOG4CXX_INCLUDES)
|
||||
|
||||
|
||||
#
|
||||
# Configure Boost header path
|
||||
#
|
||||
@@ -612,6 +645,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/lib/datasrc/tests/Makefile
|
||||
src/lib/xfr/Makefile
|
||||
src/lib/log/Makefile
|
||||
src/lib/log/tests/Makefile
|
||||
src/lib/testutils/Makefile
|
||||
src/lib/testutils/testdata/Makefile
|
||||
src/lib/nsas/Makefile
|
||||
@@ -721,6 +755,7 @@ dnl includes too
|
||||
${PYTHON_LDFLAGS}
|
||||
${PYTHON_LIB}
|
||||
Boost: ${BOOST_INCLUDES}
|
||||
log4cxx: ${LOG4CXX_INCLUDES}
|
||||
SQLite: $SQLITE_CFLAGS
|
||||
$SQLITE_LIBS
|
||||
|
||||
|
@@ -1,4 +1,27 @@
|
||||
AM_CXXFLAGS = $(B10_CXXFLAGS)
|
||||
SUBDIRS = . tests
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
lib_LTLIBRARIES = liblog.la
|
||||
liblog_la_SOURCES = dummylog.cc dummylog.h
|
||||
liblog_la_SOURCES = root_logger_name.cc root_logger_name.h
|
||||
liblog_la_SOURCES += xdebuglevel.cc xdebuglevel.h
|
||||
liblog_la_SOURCES += logger.cc logger.h
|
||||
liblog_la_SOURCES += message_reader.cc message_reader.h
|
||||
liblog_la_SOURCES += filename.h filename.cc
|
||||
liblog_la_SOURCES += stringutil.h stringutil.cc
|
||||
|
||||
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
|
||||
# B10_CXXFLAGS)
|
||||
liblog_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
if USE_GXX
|
||||
liblog_la_CXXFLAGS += -Wno-unused-parameter
|
||||
endif
|
||||
if USE_CLANGPP
|
||||
# Same for clang++, but we need to turn off -Werror completely.
|
||||
liblog_la_CXXFLAGS += -Wno-error
|
||||
endif
|
||||
liblog_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
72
src/lib/log/Message.h
Normal file
72
src/lib/log/Message.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __MESSAGE_H
|
||||
#define __MESSAGE_H
|
||||
|
||||
/// \brief Log Message
|
||||
///
|
||||
/// This class represents a message in which information about a logging event
|
||||
/// is encoded. This is invisible to the author of code doing logging unless
|
||||
/// they are planning on writing an Appender.
|
||||
|
||||
class Message {
|
||||
public:
|
||||
|
||||
// The following is a placeholder. It will be replaced with a finer-
|
||||
// grained time definition during implementation.
|
||||
typedef time_t Time; ///< To be replaced with a finer-grained time later
|
||||
|
||||
// Constructor/destructor stll to be determined
|
||||
|
||||
/// \brief Return Timestamp
|
||||
///
|
||||
/// \return Timestamp associated with the message.
|
||||
Time getTimestamp() const;
|
||||
|
||||
/// \brief Return Source
|
||||
///
|
||||
/// \return Returns the source of the message. This is a "."-separated
|
||||
/// string containing the hierarchy of the logger than generated this
|
||||
/// message.
|
||||
std::string getSource() const;
|
||||
|
||||
/// \brief Return ID
|
||||
///
|
||||
/// \return Returns the ID of the message, a 32-bit integer.
|
||||
uint32_t getId() const;
|
||||
|
||||
/// \brief Return Parameters
|
||||
///
|
||||
/// \return The parameters of the message in the form of a vector of
|
||||
/// strings. Numeric parameters have been converted to strings and
|
||||
/// included in the message.
|
||||
std::vector<std::string> getParameters() const;
|
||||
|
||||
/// \brief Return Encoded Message
|
||||
///
|
||||
/// The contents of the message are encoded as a string in the form
|
||||
///
|
||||
/// <message ID><'\0'><param 1><'\0'>...
|
||||
///
|
||||
/// Some Appenders may find this format useful, so the ability to retrieve
|
||||
/// it directly is provided.
|
||||
std::string getRawMessage() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __MESSAGE_H
|
119
src/lib/log/README.txt
Normal file
119
src/lib/log/README.txt
Normal file
@@ -0,0 +1,119 @@
|
||||
Logging Messages
|
||||
|
||||
Message Storage
|
||||
===============
|
||||
Each message is identified by a string identifier, e.g. "INVFILNAM", which is
|
||||
associated with some text (e.g. "%s is an invalid file name"). These are stored
|
||||
in a single std::map, in a class called the Dictionary.
|
||||
|
||||
The message identifier (along with parameters) is passed through the logging
|
||||
system to an appender, which uses the identifier to look up the message in
|
||||
the dictionary. The message is then formatted and written out.
|
||||
|
||||
Message File
|
||||
============
|
||||
A message file is a file containing message definitions. Typically there will
|
||||
be one message file for each component that declares message symbols.
|
||||
|
||||
|
||||
A example file could
|
||||
be:
|
||||
|
||||
# Example message file
|
||||
# $ID:$
|
||||
|
||||
$PREFIX TEST_
|
||||
TEST1 message %s is much too large
|
||||
+ This message is a test for the general message code
|
||||
|
||||
UNKNOWN unknown message
|
||||
+ Issued when the message is unknown.
|
||||
|
||||
Point to note:
|
||||
* Leading and trailing space are trimmed from the line.
|
||||
* Blank lines are ignored
|
||||
* Lines starting with "#" are comments are are ignored.
|
||||
* Lines starting $ are directives. At present, the only directive recognised
|
||||
is $PREFIX, which has one argument: the string used to prefix symbols. If
|
||||
there is no facility directive, there is no prefix to the symbols.
|
||||
* Lines starting + indicate an explanation for the preceding message. These
|
||||
are processed by a separate program and used to generate an error messages
|
||||
manual. However they are treated like comments here.
|
||||
* Message lines. These comprise a symbol name and a message (which includes
|
||||
C-style substitution strings).
|
||||
|
||||
Message Compiler
|
||||
================
|
||||
The message compiler produces two files:
|
||||
|
||||
1) A C++ header file (called <message-file-name>.h) that holds lines of the
|
||||
form:
|
||||
|
||||
namespace {
|
||||
const char* PREFIX_IDENTIFIER = "identifier";
|
||||
:
|
||||
|
||||
}
|
||||
|
||||
These are just convenience symbols to avoid the need to type in the string in
|
||||
quotes. PREFIX_ is the string in the $PREFIX directive and is used to avoid
|
||||
potential clashes with system-defined symbols.
|
||||
|
||||
2) A C++ source file (called <message-file-name>.cpp) that holds the code
|
||||
to insert the symbols and messages into the map.
|
||||
|
||||
This file declares an array of identifiers/messages in the form:
|
||||
|
||||
namespace {
|
||||
const char* messages = {
|
||||
identifier1, text1,
|
||||
identifier2, text2,
|
||||
:
|
||||
NULL
|
||||
};
|
||||
}
|
||||
|
||||
(A more complex structure to group identifiers and their messages could be
|
||||
imposed, but as the array is generated by code and will be read by code,
|
||||
it is not needed.)
|
||||
|
||||
It then declares an object that will add information to the global dictionary:
|
||||
|
||||
DictionaryAppender <message-file-name>_<prefix>_<time>(messages);
|
||||
|
||||
(Declaring the object as "static" or in the anonymous namespace runs the risk
|
||||
of it being optimised away when the module is compiled with optimisation. But
|
||||
giving it a standard name would cause a clash when multiple files are used,
|
||||
hence an attempt at disambiguation.)
|
||||
|
||||
The constructor of the DictionaryAppender object retrieves the singleton
|
||||
global Dictionary object (created using standard methods to avoid the "static
|
||||
initialization fiasco") and adds each identifier and text to the member
|
||||
std::map. 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).
|
||||
|
||||
User Message Files
|
||||
==================
|
||||
During logging initialization, a search is made for a user message file in a
|
||||
specific location. (The specification of the location has yet to be decided -
|
||||
it will probably be a command-line option.) These messages are read into a
|
||||
local Dictionary object (which performs the same checks as the global
|
||||
Dictionary for duplicate messages).
|
||||
|
||||
The local Dictionary is then merged with the global Dictionary. In this case
|
||||
though, warnings are issued where a message does not replace one in the global
|
||||
Dictionary.
|
||||
|
||||
An additional check that could be done is to compare the user message string
|
||||
with the main message string and to check that they have the same number of
|
||||
"%s" components. This will avoid potential problems in message formatting. (As
|
||||
noted in another design document, the intention within logging is to convert
|
||||
all parameters to strings at the point at which the logging call is made.)
|
||||
|
||||
Message Compiler Implementation
|
||||
===============================
|
||||
The fact that user files are read in at run-time implies that the code that
|
||||
reads the files should be C++. An implication of this is that the message
|
||||
compiler should be written in C++ (instead of Python, which is probably
|
||||
better for the task) to avoid two sets of code where message files are parsed.
|
41
src/lib/log/appender.h
Normal file
41
src/lib/log/appender.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __APPENDER_H
|
||||
#define __APPENDER_H
|
||||
|
||||
#include <message.h>
|
||||
|
||||
/// \brief Abstract Appender Class
|
||||
///
|
||||
/// This class is responsible for writing messages generated by loggers
|
||||
/// to destinations. It is an abstract class; particular appenders will
|
||||
/// control different destinations.
|
||||
///
|
||||
/// Multiple appenders can be attached to a logger. Output is routed to
|
||||
/// all appenders attached to a logger. The logger hierachy is then walked
|
||||
/// and the message passed to the appenders in parent loggers.
|
||||
|
||||
class AbstractAppender {
|
||||
public:
|
||||
|
||||
/// \brief Write the Output
|
||||
///
|
||||
/// Formats the message and writes it to the specified output.
|
||||
void write(Message& message);
|
||||
};
|
||||
|
||||
#endif // __APPENDER_H
|
130
src/lib/log/compiler/message.cc
Normal file
130
src/lib/log/compiler/message.cc
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const char* VERSION = "1.0-0";
|
||||
|
||||
/// \brief Message Compiler
|
||||
///
|
||||
/// \b Overview<BR>
|
||||
/// This is the program that takes as input a message file and produces:
|
||||
///
|
||||
/// \li A .h file containing message definition
|
||||
/// \li A .cc file containing code that adds the messages to the program's
|
||||
/// message disctionary at start-up time.
|
||||
///
|
||||
/// Alternatively, the program can produce a .py file that contains the
|
||||
/// message definitions.
|
||||
///
|
||||
|
||||
/// \b Invocation<BR>
|
||||
/// The program is invoked with the command:
|
||||
///
|
||||
/// <tt>message [-p] \<message-file\></tt>
|
||||
///
|
||||
/// It reads the message file and writes out two files of the same name but with
|
||||
/// extensions of .h and .cc.
|
||||
///
|
||||
/// If \c -p is specified, the C++ files are not written; instead a Python file
|
||||
/// of the same name (but with the file extension .py) is written.
|
||||
|
||||
|
||||
/// \brief Print Version
|
||||
///
|
||||
/// Prints the program's version number.
|
||||
|
||||
static void version() {
|
||||
cout << VERSION << "\n";
|
||||
}
|
||||
|
||||
/// \brief Print Usage
|
||||
///
|
||||
/// Prints program usage to stdout.
|
||||
|
||||
static void usage() {
|
||||
cout <<
|
||||
"Usage: message [-h] [-p] [-v] <message-file>\n" <<
|
||||
"\n" <<
|
||||
"-h Print this message and exit\n" <<
|
||||
"-p Output a Python module holding the message definitions.\n" <<
|
||||
" By default a C++ header file and implementation file are\n" <<
|
||||
" written.\n" <<
|
||||
"-v Print the program version and exit\n" <<
|
||||
"\n" <<
|
||||
"<message-file> is the name of the input message file.\n";
|
||||
}
|
||||
|
||||
/// \brief Main Program
|
||||
///
|
||||
/// Parses the options then dispatches to the appropriate function. See the
|
||||
/// main file header for the invocation.
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
const struct option loptions[] = { // Long options
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"python", no_argument, NULL, 'p'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, 0, NULL, 0 }
|
||||
};
|
||||
const char* soptions = "hpv"; // Short options
|
||||
|
||||
optind = 1; // Ensure we start a new scan
|
||||
int opt; // Value of the option
|
||||
bool python = false; // Set true if the -p flag is detected
|
||||
|
||||
while ((opt = getopt_long(argc, argv, soptions, loptions, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
|
||||
case 'v':
|
||||
version();
|
||||
return 0;
|
||||
|
||||
case 'p':
|
||||
python = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// A message will have already been output about the error.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have the message file?
|
||||
if (optind < (argc - 1)) {
|
||||
std::cout << "Error: excess arguments in command line\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
else if (optind >= argc) {
|
||||
std::cout << "Error: missing message file\n";
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Have identified the file, so process it.
|
||||
MessageFileProcessor fileProcessor();
|
||||
return fileProcessor.process(argv[argc - 1], python);
|
||||
|
||||
}
|
31
src/lib/log/dbglevels.h
Normal file
31
src/lib/log/dbglevels.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __DBGLEVELS_H
|
||||
#define __DBGLEVELS_H
|
||||
|
||||
/// \brief Defines Debug Levels
|
||||
///
|
||||
/// Defines the maximum and minimum debug levels and the number of levels.
|
||||
/// These are defined using #define as they are referenced in the construction
|
||||
/// of variables declared outside execution units. (In this way we avoid the
|
||||
/// "static initialization fiasco" problem.
|
||||
|
||||
#define MIN_DEBUG_LEVEL 0
|
||||
#define MAX_DEBUG_LEVEL 99
|
||||
#define NUM_DEBUG_LEVEL (MAX_DEBUG_LEVEL - MIN_DEBUG_LEVEL + 1)
|
||||
|
||||
#endif // __DBGLEVELS_H
|
132
src/lib/log/filename.cc
Normal file
132
src/lib/log/filename.cc
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <filename.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
// Split string into components. Any backslashes are assumed to have
|
||||
// been replaced by forward slashes.
|
||||
|
||||
void Filename::split(const string& full_name, string& directory,
|
||||
string& name, string& extension) const
|
||||
{
|
||||
directory = name = extension = "";
|
||||
bool dir_present = false;
|
||||
if (! full_name.empty()) {
|
||||
|
||||
// Find the directory.
|
||||
size_t last_slash = full_name.find_last_of('/');
|
||||
if (last_slash != string::npos) {
|
||||
|
||||
// Found the last slash, so extract directory component and
|
||||
// set where the scan for the last_dot should terminate.
|
||||
directory = full_name.substr(0, last_slash + 1);
|
||||
if (last_slash == full_name.size()) {
|
||||
|
||||
// The entire string was a directory, so exit not and don't
|
||||
// do any more searching.
|
||||
return;
|
||||
}
|
||||
|
||||
// Found a directory so note the fact.
|
||||
dir_present = true;
|
||||
}
|
||||
|
||||
// Now search backwards for the last ".".
|
||||
size_t last_dot = full_name.find_last_of('.');
|
||||
if ((last_dot == string::npos) ||
|
||||
(dir_present && (last_dot < last_slash))) {
|
||||
|
||||
// Last "." either not found or it occurs to the left of the last
|
||||
// slash if a directory was present (so it is part of a directory
|
||||
// name). In this case, the remainder of the string after the slash
|
||||
// is the name part.
|
||||
name = full_name.substr(last_slash + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Did find a valid dot, so it and everything to the right is the
|
||||
// extension...
|
||||
extension = full_name.substr(last_dot);
|
||||
|
||||
// ... and the name of the file is everything in between.
|
||||
if ((last_dot - last_slash) > 1) {
|
||||
name = full_name.substr(last_slash + 1, last_dot - last_slash - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Expand the stored filename with the default.
|
||||
|
||||
string Filename::expandWithDefault(const string& defname) const {
|
||||
|
||||
string def_directory("");
|
||||
string def_name("");
|
||||
string def_extension("");
|
||||
|
||||
// Normalize the input string.
|
||||
string copy_defname = StringUtil::trim(defname);
|
||||
StringUtil::normalizeSlash(copy_defname);
|
||||
|
||||
// Split into the components
|
||||
split(copy_defname, def_directory, def_name, def_extension);
|
||||
|
||||
// Now construct the result.
|
||||
string retstring =
|
||||
(directory_.empty() ? def_directory : directory_) +
|
||||
(name_.empty() ? def_name : name_) +
|
||||
(extension_.empty() ? def_extension : extension_);
|
||||
return retstring;
|
||||
}
|
||||
|
||||
// Use the stored name as default for a given name
|
||||
|
||||
string Filename::useAsDefault(const string& name) const {
|
||||
|
||||
string name_directory("");
|
||||
string name_name("");
|
||||
string name_extension("");
|
||||
|
||||
// Normalize the input string.
|
||||
string copy_name = StringUtil::trim(name);
|
||||
StringUtil::normalizeSlash(copy_name);
|
||||
|
||||
// Split into the components
|
||||
split(copy_name, name_directory, name_name, name_extension);
|
||||
|
||||
// Now construct the result.
|
||||
string retstring =
|
||||
(name_directory.empty() ? directory_ : name_directory) +
|
||||
(name_name.empty() ? name_ : name_name) +
|
||||
(name_extension.empty() ? extension_ : name_extension);
|
||||
return retstring;
|
||||
}
|
||||
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
163
src/lib/log/filename.h
Normal file
163
src/lib/log/filename.h
Normal file
@@ -0,0 +1,163 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __FILENAME_H
|
||||
#define __FILENAME_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <stringutil.h>
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
/// \brief Class to Manipulate Filenames
|
||||
///
|
||||
/// This is a utility class to manipulate filenames. It repeats some of the
|
||||
/// features found in the Boost filename class, but is self-contained so avoids
|
||||
/// the need to link in the Boost library.
|
||||
///
|
||||
/// A Unix-style filename comprises three parts:
|
||||
///
|
||||
/// Directory - everything up to and including the last "/". If there is no
|
||||
/// "/" in the string, there is no directory component. Note that the
|
||||
/// requirement of a trailing slash eliminates the ambiguity of whether a
|
||||
/// component is a directory or not, e.g. in /alpha/beta", "beta" could be the
|
||||
/// name of a directory or is could be a file. The interpretation here is that
|
||||
/// "beta" is the name of a file (although that file could be a directory).
|
||||
///
|
||||
/// Note: Under Windows, the drive letter is considered to be part of the
|
||||
/// directory specification. Unless this class becomes more widely-used on
|
||||
/// Windows, there is no point in adding redundant code.
|
||||
///
|
||||
/// Name - everthing from the character after the last "/" up to but not
|
||||
/// including the last ".".
|
||||
///
|
||||
/// Extension - everthing from the right-most "." (after the right-most "/") to
|
||||
/// the end of the string. If there is no "." after the last "/", there is
|
||||
/// no file extension.
|
||||
///
|
||||
/// (Note that on Windows, this function will replace all "\" characters
|
||||
/// with "/" characters on input strings.)
|
||||
///
|
||||
/// This class provides functions for extracting the components and for
|
||||
/// substituting components.
|
||||
|
||||
|
||||
class Filename {
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
Filename(const std::string& name) :
|
||||
full_name_(""), directory_(""), name_(""), extension_("")
|
||||
{
|
||||
setName(name);
|
||||
}
|
||||
|
||||
/// \brief Sets Stored Filename
|
||||
///
|
||||
/// \param name New name to replaced currently stored name
|
||||
void setName(const std::string& name) {
|
||||
full_name_ = StringUtil::trim(name);
|
||||
#ifdef WIN32
|
||||
StringUtil::normalizeSlash(full_name_);
|
||||
#endif
|
||||
split(full_name_, directory_, name_, extension_);
|
||||
}
|
||||
|
||||
/// \return Stored Filename
|
||||
std::string fullName() const {
|
||||
return full_name_;
|
||||
}
|
||||
|
||||
/// \return Directory of Given File Name
|
||||
std::string directory() const {
|
||||
return directory_;
|
||||
}
|
||||
|
||||
/// \return Name of Given File Name
|
||||
std::string name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
/// \return Extension of Given File Name
|
||||
std::string extension() const {
|
||||
return extension_;
|
||||
}
|
||||
|
||||
/// \brief Expand Name with Default
|
||||
///
|
||||
/// A default file specified is supplied and used to fill in any missing
|
||||
/// fields. For example, if the name stored is "/a/b" and the supplied
|
||||
/// name is "c.d", the result is "/a/b.d": the only field missing from the
|
||||
/// stored name is the extension, which is supplied by the default.
|
||||
/// Another example would be to store "a.b" and to supply a default of
|
||||
/// "/c/d/" - the result is "/c/d/a.b". (Note that if the supplied default
|
||||
/// was "/c/d", the result would be "/c/a.b", even if "/c/d" were actually
|
||||
/// a directory.)
|
||||
///
|
||||
/// \param defname Default name
|
||||
///
|
||||
/// \return Name expanded with defname.
|
||||
std::string expandWithDefault(const std::string& defname) const;
|
||||
|
||||
/// \brief Use as Default and Substitute into String
|
||||
///
|
||||
/// Does essentially the inverse of expand(); that filled in the stored
|
||||
/// name with a default and returned the result. This treats the stored
|
||||
/// name as the default and uses it to fill in a given name. In essence,
|
||||
/// the code:
|
||||
/// \code
|
||||
/// Filename f("/a/b");
|
||||
/// result = f.expandWithdefault("c.d");
|
||||
/// \endcode
|
||||
/// gives as a result "/a/b.d". This is the same as:
|
||||
/// \code
|
||||
/// Filename f("c.d");
|
||||
/// result = f.useAsDefault("/a/b");
|
||||
/// \endcode
|
||||
///
|
||||
/// \param name Name to expand
|
||||
///
|
||||
/// \return Name expanded with stored name
|
||||
std::string useAsDefault(const std::string&) const;
|
||||
|
||||
private:
|
||||
/// \brief Split Name into Components
|
||||
///
|
||||
/// Splits the file name into the directory, name and extension parts.
|
||||
/// The name is assumed to have had back slashes replaced by forward
|
||||
/// slashes (if appropriate).
|
||||
///
|
||||
/// \param full_name Name to split
|
||||
/// \param directory Returned directory part
|
||||
/// \param name Returned name part
|
||||
/// \param extension Returned extension part
|
||||
void split(const std::string& full_name, std::string& directory,
|
||||
std::string& name, std::string& extension) const;
|
||||
|
||||
// Members
|
||||
|
||||
std::string full_name_; ///< Given name
|
||||
std::string directory_; ///< Directory part
|
||||
std::string name_; ///< Name part
|
||||
std::string extension_; ///< Extension part
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
||||
|
||||
#endif // __FILENAME_H
|
50
src/lib/log/log.h
Normal file
50
src/lib/log/log.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __LOG_H
|
||||
#define __LOG_H
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
class RootLogger : public Logger
|
||||
{
|
||||
public:
|
||||
|
||||
/// \brief Return Root Logger
|
||||
///
|
||||
/// Returns the root logger for the system. Only one root logger is
|
||||
/// defined and the name corresponds to the
|
||||
static Log* getRootLogger() {
|
||||
static Log root_logger();
|
||||
|
||||
return &root_logger;
|
||||
}
|
||||
|
||||
/// \brief Set Logger Name
|
||||
///
|
||||
/// Sets the name of the root logger. This is dynamic, and
|
||||
|
||||
private:
|
||||
static std::string root_name_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // __LOG_H
|
187
src/lib/log/logger.cc
Normal file
187
src/lib/log/logger.cc
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright (C) 2010 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 SOFTWAR
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <log/root_logger_name.h>
|
||||
#include <log/logger.h>
|
||||
#include <log/xdebuglevel.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
// Constructor - create a logger as a child of the root logger. With log4cxx
|
||||
// this is assured by naming the logger <parent>.<child>.
|
||||
|
||||
Logger::Logger(const std::string& name) : loggerptr_()
|
||||
{
|
||||
string root_name = RootLoggerName::getName();
|
||||
if (root_name.empty() || (name == root_name)) {
|
||||
fullname_ = name;
|
||||
}
|
||||
else {
|
||||
fullname_ = root_name + "." + name;
|
||||
}
|
||||
loggerptr_ = log4cxx::Logger::getLogger(fullname_);
|
||||
}
|
||||
|
||||
// Set the severity for logging. There is a 1:1 mapping between the logging
|
||||
// severity and the log4cxx logging levels, apart from DEBUG.
|
||||
//
|
||||
// In log4cxx, each of the logging levels (DEBUG, INFO, WARNING etc.) has a
|
||||
// numeric value. The level is set to one of these and any numeric level equal
|
||||
// to or above it that is reported. For example INFO has a value of 20000 and
|
||||
// ERROR a value of 40000. So if a message of WARNING severity (= 30000) is
|
||||
// logged, it is not logged when the logger's severity level is ERROR (as
|
||||
// 30000 !>= 40000). It is reported if the logger's severity level is set to
|
||||
// WARNING (as 30000 >= 30000) or INFO (30000 >= 20000).
|
||||
//
|
||||
// This gives a simple system for handling different debug levels. The debug
|
||||
// level is a number between 0 and 99, with 0 being least verbose and 99 the
|
||||
// most. To implement this seamlessly, when DEBUG is set, the numeric value
|
||||
// of the logging level is actually set to (DEBUG - debug-level). Similarly
|
||||
// messages of level "n" are logged at a logging level of (DEBUG - n). Thus if
|
||||
// the logging level is set to DEBUG and the debug level set to 25, the actual
|
||||
// level set is 10000 - 25 = 99975.
|
||||
//
|
||||
// Attempting to log a debug message of level 26 is an attempt to log a message
|
||||
// of level 10000 - 26 = 99974. As 99974 !>= 99975, it is not logged. A
|
||||
// message of level 25 is, because 99975 >= 99975.
|
||||
//
|
||||
// The extended set of logging levels is implemented by the XDebugLevel class.
|
||||
|
||||
void Logger::setSeverity(Severity severity, int dbglevel) {
|
||||
switch (severity) {
|
||||
case NONE:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::Level::toLevel(
|
||||
log4cxx::Level::OFF_INT));
|
||||
break;
|
||||
|
||||
case FATAL:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::Level::toLevel(
|
||||
log4cxx::Level::FATAL_INT));
|
||||
break;
|
||||
|
||||
case ERROR:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::Level::toLevel(
|
||||
log4cxx::Level::ERROR_INT));
|
||||
break;
|
||||
|
||||
case WARNING:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::Level::toLevel(
|
||||
log4cxx::Level::WARN_INT));
|
||||
break;
|
||||
|
||||
case INFO:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::Level::toLevel(
|
||||
log4cxx::Level::INFO_INT));
|
||||
break;
|
||||
|
||||
case DEBUG:
|
||||
loggerptr_->setLevel(
|
||||
log4cxx::XDebugLevel::getExtendedDebug(dbglevel));
|
||||
break;
|
||||
|
||||
// Will get here for DEFAULT or any other value. This disables the
|
||||
// logger's own severity and it defaults to the severity of the parent
|
||||
// logger.
|
||||
default:
|
||||
loggerptr_->setLevel(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert between numeric log4cxx logging level and BIND-10 logging severity.
|
||||
|
||||
Logger::Severity Logger::convertLevel(int value) const {
|
||||
|
||||
// The order is optimised. This is only likely to be called when testing
|
||||
// for writing debug messages, so the check for DEBUG_INT is first.
|
||||
if (value <= log4cxx::Level::DEBUG_INT) {
|
||||
return (DEBUG);
|
||||
} else if (value <= log4cxx::Level::INFO_INT) {
|
||||
return (INFO);
|
||||
} else if (value <= log4cxx::Level::WARN_INT) {
|
||||
return (WARNING);
|
||||
} else if (value <= log4cxx::Level::ERROR_INT) {
|
||||
return (ERROR);
|
||||
} else if (value <= log4cxx::Level::FATAL_INT) {
|
||||
return (FATAL);
|
||||
} else {
|
||||
return (NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the logging severity associated with this logger.
|
||||
|
||||
Logger::Severity Logger::getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
|
||||
bool check_parent) const {
|
||||
|
||||
log4cxx::LevelPtr level = ptrlogger->getLevel();
|
||||
if (level == log4cxx::LevelPtr()) {
|
||||
|
||||
// Null level returned, logging should be that of the parent.
|
||||
|
||||
if (check_parent) {
|
||||
log4cxx::LoggerPtr parent = ptrlogger->getParent();
|
||||
if (parent == log4cxx::LoggerPtr()) {
|
||||
|
||||
// No parent, so reached the end of the chain. Return INFO
|
||||
// severity.
|
||||
return (INFO);
|
||||
}
|
||||
else {
|
||||
return getSeverityCommon(parent, check_parent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (DEFAULT);
|
||||
}
|
||||
} else {
|
||||
return convertLevel(level->toInt());
|
||||
}
|
||||
}
|
||||
// Get the debug level. This returns 0 unless the severity is DEBUG.
|
||||
|
||||
int Logger::getDebugLevel() const {
|
||||
|
||||
log4cxx::LevelPtr level = loggerptr_->getLevel();
|
||||
if (level == log4cxx::LevelPtr()) {
|
||||
|
||||
// Null pointer returned, logging should be that of the parent.
|
||||
return (0);
|
||||
|
||||
} else {
|
||||
int severity = level->toInt();
|
||||
if (severity <= log4cxx::Level::DEBUG_INT) {
|
||||
return (log4cxx::Level::DEBUG_INT - severity);
|
||||
}
|
||||
else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
490
src/lib/log/logger.h
Normal file
490
src/lib/log/logger.h
Normal file
@@ -0,0 +1,490 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __LOGGER_H
|
||||
#define __LOGGER_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <log4cxx/logger.h>
|
||||
|
||||
#include <log/dbglevels.h>
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
|
||||
typedef int MessageCode; ///< Type of the message code
|
||||
|
||||
/// \brief Severity Levels
|
||||
typedef enum {
|
||||
DEFAULT, // Default to logging level of parent
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR,
|
||||
CRITICAL,
|
||||
NONE, // Disable logging
|
||||
INFORMATION = INFO,
|
||||
WARN = WARNING,
|
||||
FATAL = CRITICAL
|
||||
} Severity;
|
||||
|
||||
/// \brief Return a logger of a given name
|
||||
///
|
||||
/// Returns a logger with the specified name.
|
||||
///
|
||||
/// \param name Name of the logger. Unless specified as a root logger
|
||||
/// (with a call to setRootLoggerName), the returned logger is a child
|
||||
/// of the root logger.
|
||||
///
|
||||
/// \return Pointer to Logger object
|
||||
// static Logger* getLogger(const char* name) {}
|
||||
|
||||
/// \brief Set Root Logger Name
|
||||
///
|
||||
/// One of the first calls in the program, this sets the name of the
|
||||
/// root logger. (The name appears in logging messages.)
|
||||
///
|
||||
/// \param name Name of the root logger.
|
||||
// static void setRootLoggerName(const char* name);
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// Creates/attaches to a logger of a specific name.
|
||||
///
|
||||
/// \param name Name of the logger. If the name is that of the root name,
|
||||
/// this creates an instance of the root logger; otherwise it creates a
|
||||
/// chold of the root logger.
|
||||
Logger(const std::string& name);
|
||||
|
||||
/// \brief Get Name of Logger
|
||||
///
|
||||
/// \return The full name of the logger (including the root name)
|
||||
virtual std::string getName() const {
|
||||
return loggerptr_->getName();
|
||||
}
|
||||
|
||||
/// \brief Set Severity Level for Logger
|
||||
///
|
||||
/// Sets the level at which this logger will log messages. If none is set,
|
||||
/// the level is inherited from the parent.
|
||||
///
|
||||
/// \param severity Severity level to log
|
||||
/// \param dbglevel If the severity is DEBUG, this is the debug level.
|
||||
/// This can be in the range 1 to 100 and controls the verbosity. A value
|
||||
/// outside these limits is silently coerced to the nearest boundary.
|
||||
virtual void setSeverity(Severity severity, int dbglevel = 1);
|
||||
|
||||
/// \brief Get Severity Level for Logger
|
||||
///
|
||||
/// \return The current logging level of this logger. In most cases though,
|
||||
/// the effective logging level is what is required.
|
||||
virtual Severity getSeverity() const {
|
||||
return getSeverityCommon(loggerptr_, false);
|
||||
}
|
||||
|
||||
/// \brief Get Effective Severity Level for Logger
|
||||
///
|
||||
/// \return The effective severity level of the logger. This is the same
|
||||
/// as getSeverity() if the logger has a severity level set, but otherwise
|
||||
/// is the severity of the parent.
|
||||
virtual Severity getEffectiveSeverity() const {
|
||||
return getSeverityCommon(loggerptr_, true);
|
||||
}
|
||||
|
||||
/// \brief Return DEBUG Level
|
||||
///
|
||||
/// \return Current setting of debug level. This is returned regardless of
|
||||
/// whether the
|
||||
virtual int getDebugLevel() const;
|
||||
|
||||
/// \brief Returns if Debug Message Should Be Output
|
||||
///
|
||||
/// \param dbglevel Level for which debugging is checked. Debugging is
|
||||
/// enabled only if the logger has DEBUG enabled and if the dbglevel
|
||||
/// checked is less than or equal to the debug level set for the logger.
|
||||
virtual bool
|
||||
isDebugEnabled(int dbglevel = MIN_DEBUG_LEVEL) const {
|
||||
return (loggerptr_->getEffectiveLevel()->toInt() <=
|
||||
(log4cxx::Level::DEBUG_INT - dbglevel));
|
||||
}
|
||||
|
||||
/// \brief Is INFO Enabled?
|
||||
virtual bool isInfoEnabled() const {
|
||||
return (loggerptr_->isInfoEnabled());
|
||||
}
|
||||
|
||||
/// \brief Is WARNING Enabled?
|
||||
virtual bool isWarnEnabled() const {
|
||||
return (loggerptr_->isWarnEnabled());
|
||||
}
|
||||
|
||||
/// \brief Is WARNING Enabled?
|
||||
virtual bool isWarningEnabled() const {
|
||||
return (loggerptr_->isWarnEnabled());
|
||||
}
|
||||
|
||||
/// \brief Is ERROR Enabled?
|
||||
virtual bool isErrorEnabled() const {
|
||||
return (loggerptr_->isErrorEnabled());
|
||||
}
|
||||
|
||||
/// \brief Is CRITICAL Enabled?
|
||||
virtual bool isCriticalEnabled() const {
|
||||
return (loggerptr_->isFatalEnabled());
|
||||
}
|
||||
|
||||
/// \brief Is FATAL Enabled?
|
||||
///
|
||||
/// FATAL is a synonym for CRITICAL.
|
||||
virtual bool isFatalEnabled() const {
|
||||
return (loggerptr_->isFatalEnabled());
|
||||
}
|
||||
/*
|
||||
/// \brief Add Appender
|
||||
///
|
||||
/// Adds an appender to the list of appenders for this logger. The
|
||||
/// appender is assumed to have an independent existence so although
|
||||
/// a pointer to the appender is added here, the logger does not
|
||||
/// assume responsibility for its destruction.
|
||||
///
|
||||
/// \param appender Pointer to the appender that should be added.
|
||||
/// If the appender is already added to this logger, a duplicate
|
||||
/// is not added.
|
||||
///
|
||||
/// \return true if the logger was added, false if it was already in the
|
||||
/// list of appenders for this logger.
|
||||
virtual bool addAppender(AbstractAppender* appender);
|
||||
|
||||
/// \brief Remove Appender
|
||||
///
|
||||
/// Removes the appender from the list of appenders for this logger.
|
||||
///
|
||||
/// \param appender Pointer to the appender that should be removed.
|
||||
///
|
||||
/// \return true if the appender was removed, false if it could not be
|
||||
/// found in the list.
|
||||
virtual bool removeAppender(AbstractAppender* appender);
|
||||
|
||||
/// \brief Get Effective Level for Logger
|
||||
///
|
||||
/// Gets the current effective logging level. If the current logger does
|
||||
/// not have a level set, the inheritance tree is traversed until a level
|
||||
/// is found.
|
||||
virtual Level getEffectiveLevel() const;
|
||||
/// \brief Debug Messages
|
||||
///
|
||||
/// A set of functions that control the output of the message and up to
|
||||
/// four parameters.
|
||||
void debugCommon(MessageCode code, std::string arg);
|
||||
|
||||
template <typename T1>
|
||||
void debug(Level level, MessageCode code, T1 arg1) {
|
||||
if (shouldOutputDebug(level)) {
|
||||
debugCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void debug(MessageCode code, T1 arg1, T2 arg2) {
|
||||
if (shouldOutputDebug(level)) {
|
||||
debugCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void debug(MessageCode code, T1 arg1, T2 arg2, T3 arg3) {
|
||||
if (shouldOutputDebug(level)) {
|
||||
debugCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void debug(MessageCode code, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
if (shouldOutputDebug(level)) {
|
||||
debugCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg4)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Informational Messages
|
||||
///
|
||||
/// A set of functions that control the output of the message and up to
|
||||
/// four parameters.
|
||||
void infoCommon(MessageCode code, std::string arg);
|
||||
|
||||
template <typename T1>
|
||||
void info(MessageCode code, T1 arg1) {
|
||||
if (isInfoEnabled()) {
|
||||
infoCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void info(MessageCode code, T1 arg1, T2 arg2) {
|
||||
if (isInfoEnabled()) {
|
||||
infoCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void info(MessageCode code, T1 arg1, T2 arg2, T3 arg3) {
|
||||
if (isInfoEnabled()) {
|
||||
infoCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void info(MessageCode code, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
if (isInfoEnabled()) {
|
||||
infoCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg4)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Warning Messages
|
||||
///
|
||||
/// A set of functions that control the output of the message and up to
|
||||
/// four parameters.
|
||||
void warnCommon(MessageCode code, std::string arg);
|
||||
|
||||
template <typename T1>
|
||||
void warn(MessageCode code, T1 arg1) {
|
||||
if (isWarnEnabled()) {
|
||||
warnCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void warn(MessageCode code, T1 arg1, T2 arg2) {
|
||||
if (isWarnEnabled()) {
|
||||
warnCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void warn(MessageCode code, T1 arg1, T2 arg2, T3 arg3) {
|
||||
if (isWarnEnabled()) {
|
||||
warnCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void warn(MessageCode code, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
if (isWarnEnabled()) {
|
||||
warnCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg4)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Error Messages
|
||||
///
|
||||
/// A set of functions that control the output of the message and up to
|
||||
/// four parameters.
|
||||
void errorCommon(MessageCode code, std::string arg);
|
||||
|
||||
template <typename T1>
|
||||
void error(MessageCode code, T1 arg1) {
|
||||
if (isErrorEnabled()) {
|
||||
errorCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void error(MessageCode code, T1 arg1, T2 arg2) {
|
||||
if (isErrorEnabled()) {
|
||||
errorCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void error(MessageCode code, T1 arg1, T2 arg2, T3 arg3) {
|
||||
if (isErrorEnabled()) {
|
||||
errorCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void error(MessageCode code, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
if (isErrorEnabled()) {
|
||||
errorCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg4)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Critical Messages
|
||||
///
|
||||
/// A set of functions that control the output of the message and up to
|
||||
/// four parameters.
|
||||
void criticalCommon(MessageCode code, std::string arg);
|
||||
|
||||
template <typename T1>
|
||||
void critical(MessageCode code, T1 arg1) {
|
||||
if (isCriticalEnabled()) {
|
||||
criticalCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void critical(MessageCode code, T1 arg1, T2 arg2) {
|
||||
if (isCriticalEnabled()) {
|
||||
criticalCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void critical(MessageCode code, T1 arg1, T2 arg2, T3 arg3) {
|
||||
if (isCriticalEnabled()) {
|
||||
criticalCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void critical(MessageCode code, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
|
||||
if (isCriticalEnabled()) {
|
||||
errorCommon(code,
|
||||
boost::lexical_cast<std::string>(arg1) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg2) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg3) + std::string('\0') +
|
||||
boost::lexical_cast<std::string>(arg4)
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
/// \brief Equality
|
||||
///
|
||||
/// Check if two instances of this logger refer to the same stream.
|
||||
/// (This method is principally for testing.)
|
||||
///
|
||||
/// \return true if the logger objects are instances of the same logger.
|
||||
bool operator==(const Logger& other) const {
|
||||
return (loggerptr_ == other.loggerptr_);
|
||||
}
|
||||
|
||||
/// \brief Logger Initialized
|
||||
///
|
||||
/// Check that the logger has been properly initialized. (This method
|
||||
/// is principally for testing.)
|
||||
///
|
||||
/// \return true if this logger object has been initialized.
|
||||
bool isInitialized() const {
|
||||
return (loggerptr_ != log4cxx::LoggerPtr());
|
||||
}
|
||||
|
||||
/// \brief Get Severity Level for Logger
|
||||
///
|
||||
/// This is common code for getSeverity() and getEffectiveSeverity() -
|
||||
/// it returns the severity of the logger; if not set (and the check_parent)
|
||||
/// flag is set, it searches up the parent-child tree until a severity
|
||||
/// level is found and uses that.
|
||||
///
|
||||
/// \param ptrlogger Pointer to the log4cxx logger to check.
|
||||
/// \param check_parent true to search up the tree, false to return the
|
||||
/// current level.
|
||||
///
|
||||
/// \return The effective severity level of the logger. This is the same
|
||||
/// as getSeverity() if the logger has a severity level set, but otherwise
|
||||
/// is the severity of the parent.
|
||||
Logger::Severity getSeverityCommon(const log4cxx::LoggerPtr& ptrlogger,
|
||||
bool check_parent) const;
|
||||
|
||||
/// \brief Convert Between BIND-10 and log4cxx Logging Levels
|
||||
///
|
||||
/// Converts between the numeric value of the log4cxx logging level
|
||||
/// and the BIND-10 severity level.
|
||||
///
|
||||
/// \param value log4cxx numeric logging level
|
||||
///
|
||||
/// \return BIND-10 logging severity
|
||||
Severity convertLevel(int value) const;
|
||||
|
||||
private:
|
||||
log4cxx::LoggerPtr loggerptr_; ///< Pointer to the underlying logger
|
||||
std::string fullname_; ///< Full name of this logger
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
||||
|
||||
|
||||
#endif // __LOGGER_H
|
137
src/lib/log/message_reader.cc
Normal file
137
src/lib/log/message_reader.cc
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright (C) 2011 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <log/message_reader.h>
|
||||
#include <log/stringutil.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
// Virtual destructor.
|
||||
MessageReader::~MessageReader() {
|
||||
}
|
||||
|
||||
// Return error text
|
||||
|
||||
string MessageReader::errorText(MessageReader::Status status) {
|
||||
switch (status) {
|
||||
case SUCCESS:
|
||||
return "Success";
|
||||
|
||||
case DUPLPRFX:
|
||||
return "Error, duplicate $PREFIX directive found";
|
||||
|
||||
case PRFXEXTRARG:
|
||||
return "Error, $PREFIX directive has extra arguments";
|
||||
|
||||
case PRFXINVARG:
|
||||
return "Error, $PREFIX directive has an invalid argument";
|
||||
|
||||
case PRFXNOARG:
|
||||
return "Error, $PREFIX directive has no arguments";
|
||||
|
||||
case UNRECDIR:
|
||||
return "Error, unrecognised directive";
|
||||
|
||||
default:
|
||||
return "Unknown message code";
|
||||
}
|
||||
}
|
||||
|
||||
// Read the file
|
||||
|
||||
MessageReader::Status MessageReader::readFile(const string&) {
|
||||
return OPENIN;
|
||||
}
|
||||
|
||||
// Clear the Message Map
|
||||
|
||||
void MessageReader::clear() {
|
||||
}
|
||||
|
||||
// Parse a line of the file
|
||||
|
||||
MessageReader::Status MessageReader::processLine(const string& line) {
|
||||
|
||||
// Get rid of leading and trailing spaces
|
||||
string text = StringUtil::trim(line);
|
||||
|
||||
if (text.empty()) {
|
||||
return SUCCESS; // Ignore blank lines
|
||||
|
||||
} else if ((text[0] == '#') || (text[0] == '+')) {
|
||||
return SUCCESS; // Ignore comments or descriptions
|
||||
|
||||
} else if (text[0] == '$') {
|
||||
return directive(text); // Process directives
|
||||
|
||||
} else {
|
||||
return OPENIN;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Process directive
|
||||
|
||||
MessageReader::Status MessageReader::directive(const std::string& text) {
|
||||
|
||||
static string valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||
|
||||
// Regardless of what happens, all prefixes will be uppercase (as will
|
||||
// all symbols).
|
||||
string line = text;
|
||||
StringUtil::uppercase(line);
|
||||
vector<string> tokens = StringUtil::tokens(line);
|
||||
|
||||
// Only $PREFIX is recognised so far, so we'll handle it here.
|
||||
if (tokens[0] != string("$PREFIX")) {
|
||||
return UNRECDIR; // Directive is not prefix
|
||||
|
||||
} else if (tokens.size() < 2) {
|
||||
return PRFXNOARG; // Does not have an argument
|
||||
|
||||
} else if (tokens.size() > 2) {
|
||||
return PRFXEXTRARG; // Too many arguments
|
||||
|
||||
}
|
||||
|
||||
// Token is potentially valid providing it only contains alphabetic
|
||||
// and numeric characters (and underscores) and does not start with a
|
||||
// digit.
|
||||
|
||||
if ((tokens[1].find_first_not_of(valid) != string::npos) ||
|
||||
(std::isdigit(tokens[1][0]))) {
|
||||
|
||||
// Invalid character in string opr it starts with a digit.
|
||||
return PRFXINVARG;
|
||||
}
|
||||
|
||||
// All OK - unless the prefix has already been set.
|
||||
|
||||
if (prefix_.size() != 0) {
|
||||
return DUPLPRFX;
|
||||
}
|
||||
|
||||
// Prefix has not been set, so set it and return success.
|
||||
|
||||
prefix_ = tokens[1];
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
156
src/lib/log/message_reader.h
Normal file
156
src/lib/log/message_reader.h
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright (C) 2011 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __MESSAGE_READER_H
|
||||
#define __MESSAGE_READER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
/// \brief Read Message File
|
||||
///
|
||||
/// Reads a message file and creates a map of identifier against the text of the
|
||||
/// message. This map can be retrieved for subsequent processing.
|
||||
|
||||
class MessageReader {
|
||||
public:
|
||||
|
||||
/// \brief Status Returns
|
||||
///
|
||||
/// It may seem odd that a class devoted to reading logfile messages does
|
||||
/// not have its own set of messages. The reason is that this class is
|
||||
/// used in both the server and in the message compiler. The latter is
|
||||
/// a stand-along program used to create message files, so at the time this
|
||||
/// file is compiled, there is nothing to build an associated message file.
|
||||
typedef enum {
|
||||
SUCCESS, // Success, all OK.
|
||||
DUPLPRFX, // Error, duplicate prefix found
|
||||
OPENIN, // Error openinin input file
|
||||
PRFXEXTRARG, // Error, $PREFIX directive has extra arguments
|
||||
PRFXINVARG, // Error, $PREFIX has invalid argument
|
||||
PRFXNOARG, // Error, $PREFIX directive has no arguments
|
||||
UNRECDIR // Error, unrecognised directive
|
||||
|
||||
} Status; // Status code
|
||||
|
||||
/// \brief Other Types
|
||||
typedef std::map<std::string, std::string> MessageMap;
|
||||
typedef std::vector<std::string> MessageDuplicates;
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// Default constructor. All work is done in the main readFile code (so
|
||||
/// that a status return can be returned instead of needing to throw an
|
||||
/// exception).
|
||||
MessageReader() : messages_(), duplicates_()
|
||||
{}
|
||||
|
||||
/// \brief Virtual Destructor
|
||||
virtual ~MessageReader();
|
||||
|
||||
/// \brief Return Error Text
|
||||
///
|
||||
/// Returns the message associated with the error code
|
||||
///
|
||||
/// \param status Status code for which a message is required
|
||||
///
|
||||
/// \return Text of the error.
|
||||
virtual std::string errorText(Status status);
|
||||
|
||||
|
||||
/// \brief Read File
|
||||
///
|
||||
/// This is the main method of the class and reads in the file, parses it,
|
||||
/// and stores the result in the message map.
|
||||
///
|
||||
/// \param file Name of the message file.
|
||||
///
|
||||
/// \return Status return. Should be SUCCESS, else an error has occurred.
|
||||
virtual Status readFile(const std::string& file);
|
||||
|
||||
|
||||
/// \brief Clears Message Mapgit find new files
|
||||
///
|
||||
/// In the event of an instance of the class needing to be reused, this
|
||||
/// method will clear the message map and the list of duplicated.
|
||||
virtual void clear();
|
||||
|
||||
|
||||
/// \brief Process Line
|
||||
///
|
||||
/// Parses a text line and adds it to the message map. Although this is
|
||||
/// for use in readFile, it can also be used to add individual messages
|
||||
/// to the message map.
|
||||
///
|
||||
/// \param line Line of text to process
|
||||
///
|
||||
/// \return Status return
|
||||
virtual Status processLine(const std::string& line);
|
||||
|
||||
|
||||
/// \brief Return Message Map
|
||||
///
|
||||
/// Returns the message map.
|
||||
///
|
||||
/// \return Returns a copy of the internal map.
|
||||
/// TODO: Usse a reference?
|
||||
virtual MessageMap getMessageMap() const {
|
||||
return messages_;
|
||||
}
|
||||
|
||||
/// \brief Return Message Duplicates
|
||||
///
|
||||
/// Returns a copy of the duplicates vector.
|
||||
///
|
||||
/// \return Copy of the duplicates vector
|
||||
virtual MessageDuplicates getMessageDuplicates() {
|
||||
return duplicates_;
|
||||
}
|
||||
|
||||
/// \brief Get Prefix
|
||||
///
|
||||
/// \return Argument to the $PREFIX directive (if present)
|
||||
virtual std::string getPrefix() const {
|
||||
return prefix_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// \brief Handle Directive
|
||||
///
|
||||
/// Passed a line starting with a "$", this handles the processing of
|
||||
/// directives.
|
||||
///
|
||||
/// \param line Line of text that starts with "$",
|
||||
///
|
||||
/// \return Status return code. NORMAL implies success
|
||||
Status directive(const std::string& line);
|
||||
|
||||
/// Attributes
|
||||
MessageMap messages_; // Message map
|
||||
MessageDuplicates duplicates_; // Duplicate messages
|
||||
std::string prefix_; // Input of $PREFIX statement
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
||||
|
||||
#endif // __MESSAGE_READER_H
|
26
src/lib/log/root_logger_name.cc
Normal file
26
src/lib/log/root_logger_name.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <string>
|
||||
#include <root_logger_name.h>
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
std::string RootLoggerName::name_("");
|
||||
|
||||
}
|
||||
}
|
57
src/lib/log/root_logger_name.h
Normal file
57
src/lib/log/root_logger_name.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __ROOT_LOGGER_NAME_H
|
||||
#define __ROOT_LOGGER_NAME_H
|
||||
|
||||
#include <string>
|
||||
|
||||
/// \brief Define Name of Root Logger
|
||||
///
|
||||
/// In the log4cxx system, the root logger is ".". The definition for the
|
||||
/// BIND-10 system is that the root logger of a program has the name of the
|
||||
/// program. This (trivial) class stores the name of the program in a
|
||||
/// location accessible to the logger classes.
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
class RootLoggerName {
|
||||
public:
|
||||
|
||||
/// \brief Set Root Logger Name
|
||||
///
|
||||
/// \param name Name of the root logger. This should be the program
|
||||
/// name.
|
||||
static void setName(const std::string& name) {
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
/// \brief Get Root Logger Name
|
||||
///
|
||||
/// \return Name of the root logger.
|
||||
static std::string getName() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string name_; ///< Name of the root logger
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __ROOT_LOGGER_NAME_H
|
83
src/lib/log/stringutil.cc
Normal file
83
src/lib/log/stringutil.cc
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <string.h>
|
||||
#include <stringutil.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
// Trim String
|
||||
|
||||
string StringUtil::trim(const string& instring) {
|
||||
static const char* blanks = " \t\n";
|
||||
|
||||
string retstring = "";
|
||||
if (! instring.empty()) {
|
||||
|
||||
// Search for first non-blank character in the string
|
||||
size_t first = instring.find_first_not_of(blanks);
|
||||
if (first != string::npos) {
|
||||
|
||||
// String not all blanks, so look for last character
|
||||
size_t last = instring.find_last_not_of(blanks);
|
||||
|
||||
// Extract the trimmed substring
|
||||
retstring = instring.substr(first, (last - first + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return retstring;
|
||||
}
|
||||
|
||||
// Tokenise string. As noted in the header, this is locally written to avoid
|
||||
// another dependency on a Boost library.
|
||||
|
||||
vector<string> StringUtil::tokens(const std::string text,
|
||||
const std::string& delim)
|
||||
{
|
||||
vector<string> result;
|
||||
|
||||
// Search for the first non-delimiter character
|
||||
size_t start = text.find_first_not_of(delim);
|
||||
while (start != string::npos) {
|
||||
|
||||
// Non-delimiter found, look for next delimiter
|
||||
size_t end = text.find_first_of(delim, start);
|
||||
if (end != string::npos) {
|
||||
|
||||
// Delimiter found, so extract string & search for start of next
|
||||
// non-delimiter segment.
|
||||
result.push_back(text.substr(start, (end - start)));
|
||||
start = text.find_first_not_of(delim, end);
|
||||
|
||||
} else {
|
||||
|
||||
// End of string found, extract rest of string and flag to exit
|
||||
result.push_back(text.substr(start));
|
||||
start = string::npos;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
129
src/lib/log/stringutil.h
Normal file
129
src/lib/log/stringutil.h
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __STRINGUTIL_H
|
||||
#define __STRINGUTIL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
/// \brief A Set of C++ Utilities for Manipulating Strings
|
||||
|
||||
class StringUtil {
|
||||
public:
|
||||
/// \brief Normalize Backslash
|
||||
///
|
||||
/// Only active on Windows, this replaces all "\" in a string with "/"
|
||||
/// and returns the result. On other systems it is a no-op. Note that
|
||||
/// Windows does recognise file names with the "\" replaced by "/" (at
|
||||
/// least in system calls, if not the command line).
|
||||
///
|
||||
/// \param name Name to be substituted
|
||||
static void normalizeSlash(std::string& name) {
|
||||
if (! name.empty()) {
|
||||
size_t pos = 0;
|
||||
while ((pos = name.find('\\', pos)) != std::string::npos) {
|
||||
name[pos] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Trim Leading and Trailing Spaces
|
||||
///
|
||||
/// Returns a copy of the input string but with any leading or trailing
|
||||
/// spaces or tabs removed.
|
||||
///
|
||||
/// \param instring Input string to modify
|
||||
///
|
||||
/// \return String with leading and trailing spaces removed
|
||||
static std::string trim(const std::string& instring);
|
||||
|
||||
/// \brief Split String into Tokens
|
||||
///
|
||||
/// Splits a string into tokens (the tokens being delimited by one or more
|
||||
/// of the delimiter characters) and returns the tokens in a vector array.
|
||||
/// Note that adjacent delimiters are considered to be a single delimiter.
|
||||
///
|
||||
/// We could use Boost for this, but this (simple) function eliminates one
|
||||
/// dependency in the code.
|
||||
///
|
||||
/// \param text String to be split. Passed by value as the internal copy
|
||||
/// is altered during the processing.
|
||||
/// \param delim Delimiter characters
|
||||
///
|
||||
/// \return Vector of tokens.
|
||||
static std::vector<std::string> tokens(const std::string text,
|
||||
const std::string& delim = std::string(" \t\n"));
|
||||
|
||||
/// \brief Uppercase Character
|
||||
///
|
||||
/// Needed to pass as an argument to transform() in uppercase(), as the
|
||||
/// function std::toupper() takes an "int" as its argument and the template
|
||||
/// expansion mechanism gets confused.
|
||||
///
|
||||
/// \param chr Character to be upper-cased.
|
||||
///
|
||||
/// \return Uppercase version of the argument
|
||||
static char toUpper(char chr) {
|
||||
return static_cast<char>(std::toupper(static_cast<int>(chr)));
|
||||
}
|
||||
|
||||
/// \brief Uppercase String
|
||||
///
|
||||
/// A convenience function to uppercase a string
|
||||
///
|
||||
/// \param text String to be upper-cased.
|
||||
static void uppercase(std::string& text) {
|
||||
std::transform(text.begin(), text.end(), text.begin(),
|
||||
StringUtil::toUpper);
|
||||
}
|
||||
|
||||
/// \brief Lowercase Character
|
||||
///
|
||||
/// Needed to pass as an argument to transform() in lowercase(), as the
|
||||
/// function std::tolower() takes an "int" as its argument and the template
|
||||
/// expansion mechanism gets confused.
|
||||
///
|
||||
/// \param chr Character to be lower-cased.
|
||||
///
|
||||
/// \return Lowercase version of the argument
|
||||
static char toLower(char chr) {
|
||||
return static_cast<char>(std::tolower(static_cast<int>(chr)));
|
||||
}
|
||||
|
||||
/// \brief Lowercase String
|
||||
///
|
||||
/// A convenience function to lowercase a string
|
||||
///
|
||||
/// \param text String to be lower-cased.
|
||||
static void lowercase(std::string& text) {
|
||||
std::transform(text.begin(), text.end(), text.begin(),
|
||||
StringUtil::toLower);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
||||
|
||||
|
||||
|
||||
#endif // __STRINGUTIL_H
|
31
src/lib/log/tests/Makefile.am
Normal file
31
src/lib/log/tests/Makefile.am
Normal file
@@ -0,0 +1,31 @@
|
||||
SUBDIRS = .
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
|
||||
AM_CXXFLAGS = $(B10_CXXFLAGS)
|
||||
|
||||
if USE_STATIC_LINK
|
||||
AM_LDFLAGS = -static
|
||||
endif
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += run_unittests
|
||||
run_unittests_SOURCES = root_logger_name_unittest.cc
|
||||
run_unittests_SOURCES += filename_unittest.cc
|
||||
run_unittests_SOURCES += logger_unittest.cc
|
||||
run_unittests_SOURCES += message_reader_unittest.cc
|
||||
run_unittests_SOURCES += stringutil_unittest.cc
|
||||
run_unittests_SOURCES += xdebuglevel_unittest.cc
|
||||
run_unittests_SOURCES += run_unittests.cc
|
||||
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
run_unittests_LDADD = $(GTEST_LDADD)
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
|
||||
run_unittests_LDADD += -llog4cxx
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = $(TESTS)
|
146
src/lib/log/tests/filename_unittest.cc
Normal file
146
src/lib/log/tests/filename_unittest.cc
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: base64_unittest.cc 2549 2010-07-20 19:09:37Z jinmei $
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log/filename.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::log;
|
||||
using namespace std;
|
||||
|
||||
class FilenameTest : public ::testing::Test {
|
||||
protected:
|
||||
FilenameTest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Check that the name can be changed
|
||||
|
||||
TEST_F(FilenameTest, SetName) {
|
||||
Filename fname("/a/b/c.d");
|
||||
EXPECT_EQ("/a/b/c.d", fname.fullName());
|
||||
|
||||
fname.setName("test.txt");
|
||||
EXPECT_EQ("test.txt", fname.fullName());
|
||||
}
|
||||
|
||||
|
||||
// Check that the components are split correctly. This is a check of the
|
||||
// private member split() method.
|
||||
|
||||
TEST_F(FilenameTest, Components) {
|
||||
|
||||
// Complete name
|
||||
Filename fname("/alpha/beta/gamma.delta");
|
||||
EXPECT_EQ("/alpha/beta/", fname.directory());
|
||||
EXPECT_EQ("gamma", fname.name());
|
||||
EXPECT_EQ(".delta", fname.extension());
|
||||
|
||||
// Directory only
|
||||
fname.setName("/gamma/delta/");
|
||||
EXPECT_EQ("/gamma/delta/", fname.directory());
|
||||
EXPECT_EQ("", fname.name());
|
||||
EXPECT_EQ("", fname.extension());
|
||||
|
||||
// Filename only
|
||||
fname.setName("epsilon");
|
||||
EXPECT_EQ("", fname.directory());
|
||||
EXPECT_EQ("epsilon", fname.name());
|
||||
EXPECT_EQ("", fname.extension());
|
||||
|
||||
// Extension only
|
||||
fname.setName(".zeta");
|
||||
EXPECT_EQ("", fname.directory());
|
||||
EXPECT_EQ("", fname.name());
|
||||
EXPECT_EQ(".zeta", fname.extension());
|
||||
|
||||
// Missing directory
|
||||
fname.setName("eta.theta");
|
||||
EXPECT_EQ("", fname.directory());
|
||||
EXPECT_EQ("eta", fname.name());
|
||||
EXPECT_EQ(".theta", fname.extension());
|
||||
|
||||
// Missing filename
|
||||
fname.setName("/iota/.kappa");
|
||||
EXPECT_EQ("/iota/", fname.directory());
|
||||
EXPECT_EQ("", fname.name());
|
||||
EXPECT_EQ(".kappa", fname.extension());
|
||||
|
||||
// Missing extension
|
||||
fname.setName("lambda/mu/nu");
|
||||
EXPECT_EQ("lambda/mu/", fname.directory());
|
||||
EXPECT_EQ("nu", fname.name());
|
||||
EXPECT_EQ("", fname.extension());
|
||||
|
||||
// Empty string
|
||||
fname.setName("");
|
||||
EXPECT_EQ("", fname.directory());
|
||||
EXPECT_EQ("", fname.name());
|
||||
EXPECT_EQ("", fname.extension());
|
||||
|
||||
// ... and finally check that the decomposition can occur in the presence
|
||||
// of leading and trailing spaces
|
||||
fname.setName(" lambda/mu/nu\t ");
|
||||
EXPECT_EQ("lambda/mu/", fname.directory());
|
||||
EXPECT_EQ("nu", fname.name());
|
||||
EXPECT_EQ("", fname.extension());
|
||||
}
|
||||
|
||||
// Check that the expansion with a default works.
|
||||
|
||||
TEST_F(FilenameTest, ExpandWithDefault) {
|
||||
Filename fname("a.b");
|
||||
|
||||
// These tests also check that the trimming of the default component is
|
||||
// done properly.
|
||||
EXPECT_EQ("/c/d/a.b", fname.expandWithDefault(" /c/d/ "));
|
||||
EXPECT_EQ("/c/d/a.b", fname.expandWithDefault("/c/d/e.f"));
|
||||
EXPECT_EQ("a.b", fname.expandWithDefault("e.f"));
|
||||
|
||||
fname.setName("/a/b/c");
|
||||
EXPECT_EQ("/a/b/c.d", fname.expandWithDefault(".d"));
|
||||
EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("x.d"));
|
||||
EXPECT_EQ("/a/b/c.d", fname.expandWithDefault("/s/t/u.d"));
|
||||
EXPECT_EQ("/a/b/c", fname.expandWithDefault("/s/t/u"));
|
||||
|
||||
fname.setName(".h");
|
||||
EXPECT_EQ("/a/b/c.h", fname.expandWithDefault("/a/b/c.msg"));
|
||||
}
|
||||
|
||||
// Check that we can use this as a default in expanding a filename
|
||||
|
||||
TEST_F(FilenameTest, UseAsDefault) {
|
||||
|
||||
Filename fname("a.b");
|
||||
|
||||
// These tests also check that the trimming of the default component is
|
||||
// done properly.
|
||||
EXPECT_EQ("/c/d/a.b", fname.useAsDefault(" /c/d/ "));
|
||||
EXPECT_EQ("/c/d/e.f", fname.useAsDefault("/c/d/e.f"));
|
||||
EXPECT_EQ("e.f", fname.useAsDefault("e.f"));
|
||||
|
||||
fname.setName("/a/b/c");
|
||||
EXPECT_EQ("/a/b/c.d", fname.useAsDefault(".d"));
|
||||
EXPECT_EQ("/a/b/x.d", fname.useAsDefault("x.d"));
|
||||
EXPECT_EQ("/s/t/u.d", fname.useAsDefault("/s/t/u.d"));
|
||||
EXPECT_EQ("/s/t/u", fname.useAsDefault("/s/t/u"));
|
||||
EXPECT_EQ("/a/b/c", fname.useAsDefault(""));
|
||||
}
|
383
src/lib/log/tests/logger_unittest.cc
Normal file
383
src/lib/log/tests/logger_unittest.cc
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: $
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log/root_logger_name.h>
|
||||
#include <log/logger.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::log;
|
||||
|
||||
namespace isc {
|
||||
namespace log {
|
||||
|
||||
/// \brief Test Logger
|
||||
///
|
||||
/// This logger is a subclass of the logger class under test, but makes
|
||||
/// protected methods public (for testing)
|
||||
|
||||
class TestLogger : public Logger {
|
||||
public:
|
||||
/// \brief constructor
|
||||
TestLogger(const std::string& name) : Logger(name)
|
||||
{}
|
||||
|
||||
/// \brief Logger Equality
|
||||
bool operator==(const TestLogger& other) {
|
||||
return Logger::operator==(other);
|
||||
}
|
||||
|
||||
/// \brief Logger is Null
|
||||
bool isInitialized() const {
|
||||
return Logger::isInitialized();
|
||||
}
|
||||
|
||||
/// \brief Conversion Between log4cxx Number and BIND-10 Severity
|
||||
Severity convertLevel(int value) {
|
||||
return Logger::convertLevel(value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace isc
|
||||
|
||||
|
||||
class LoggerTest : public ::testing::Test {
|
||||
protected:
|
||||
LoggerTest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Checks that the logger is named correctly.
|
||||
|
||||
TEST_F(LoggerTest, Name) {
|
||||
|
||||
// Create a logger
|
||||
RootLoggerName::setName("test1");
|
||||
Logger logger("alpha");
|
||||
|
||||
// ... and check the name
|
||||
EXPECT_EQ(std::string("test1.alpha"), logger.getName());
|
||||
}
|
||||
|
||||
// This test attempts to get two instances of a logger with the same name
|
||||
// and checks that they are in fact the same logger.
|
||||
|
||||
TEST_F(LoggerTest, GetLogger) {
|
||||
|
||||
// Set the root logger name (not strictly needed, but this will be the
|
||||
// case in the program(.
|
||||
RootLoggerName::setName("test2");
|
||||
|
||||
const std::string name1 = "alpha";
|
||||
const std::string name2 = "beta";
|
||||
|
||||
// Instantiate two loggers that should be the same
|
||||
TestLogger logger1(name1);
|
||||
TestLogger logger2(name1);
|
||||
|
||||
// And check they are equal and non-null
|
||||
EXPECT_TRUE(logger1.isInitialized());
|
||||
EXPECT_TRUE(logger2.isInitialized());
|
||||
EXPECT_TRUE(logger1 == logger2);
|
||||
|
||||
// Instantiate another logger with another name and check that it
|
||||
// is different to the previously instantiated ones.
|
||||
TestLogger logger3(name2);
|
||||
EXPECT_TRUE(logger3.isInitialized());
|
||||
EXPECT_FALSE(logger1 == logger3);
|
||||
}
|
||||
|
||||
// Test the number to severity conversion function
|
||||
|
||||
TEST_F(LoggerTest, ConvertLevel) {
|
||||
|
||||
// Create a logger
|
||||
RootLoggerName::setName("test3");
|
||||
TestLogger logger("alpha");
|
||||
|
||||
// Basic 1:1
|
||||
EXPECT_EQ(Logger::DEBUG, logger.convertLevel(log4cxx::Level::DEBUG_INT));
|
||||
EXPECT_EQ(Logger::INFO, logger.convertLevel(log4cxx::Level::INFO_INT));
|
||||
EXPECT_EQ(Logger::WARN, logger.convertLevel(log4cxx::Level::WARN_INT));
|
||||
EXPECT_EQ(Logger::WARNING, logger.convertLevel(log4cxx::Level::WARN_INT));
|
||||
EXPECT_EQ(Logger::ERROR, logger.convertLevel(log4cxx::Level::ERROR_INT));
|
||||
EXPECT_EQ(Logger::FATAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
|
||||
EXPECT_EQ(Logger::CRITICAL, logger.convertLevel(log4cxx::Level::FATAL_INT));
|
||||
EXPECT_EQ(Logger::NONE, logger.convertLevel(log4cxx::Level::OFF_INT));
|
||||
|
||||
// Now some debug levels
|
||||
EXPECT_EQ(Logger::DEBUG,
|
||||
logger.convertLevel(log4cxx::Level::DEBUG_INT - 1));
|
||||
EXPECT_EQ(Logger::DEBUG,
|
||||
logger.convertLevel(log4cxx::Level::DEBUG_INT - MAX_DEBUG_LEVEL));
|
||||
EXPECT_EQ(Logger::DEBUG,
|
||||
logger.convertLevel(log4cxx::Level::DEBUG_INT - 2 * MAX_DEBUG_LEVEL));
|
||||
}
|
||||
|
||||
// Check that the logger levels are get set properly.
|
||||
|
||||
TEST_F(LoggerTest, Severity) {
|
||||
|
||||
// Create a logger
|
||||
RootLoggerName::setName("test3");
|
||||
Logger logger("alpha");
|
||||
|
||||
// Now check the levels
|
||||
logger.setSeverity(Logger::NONE);
|
||||
EXPECT_EQ(Logger::NONE, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::CRITICAL);
|
||||
EXPECT_EQ(Logger::CRITICAL, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::ERROR);
|
||||
EXPECT_EQ(Logger::ERROR, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::WARNING);
|
||||
EXPECT_EQ(Logger::WARNING, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::INFO);
|
||||
EXPECT_EQ(Logger::INFO, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG);
|
||||
EXPECT_EQ(Logger::DEBUG, logger.getSeverity());
|
||||
|
||||
logger.setSeverity(Logger::DEFAULT);
|
||||
EXPECT_EQ(Logger::DEFAULT, logger.getSeverity());
|
||||
}
|
||||
|
||||
// Check that the debug level is set correctly.
|
||||
|
||||
TEST_F(LoggerTest, DebugLevels) {
|
||||
|
||||
// Create a logger
|
||||
RootLoggerName::setName("test4");
|
||||
Logger logger("alpha");
|
||||
|
||||
// Debug level should be 0 if not at debug severity
|
||||
logger.setSeverity(Logger::NONE, 20);
|
||||
EXPECT_EQ(0, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::INFO, 42);
|
||||
EXPECT_EQ(0, logger.getDebugLevel());
|
||||
|
||||
// Should be the value set if the severity is set to DEBUG though.
|
||||
logger.setSeverity(Logger::DEBUG, 32);
|
||||
EXPECT_EQ(32, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 97);
|
||||
EXPECT_EQ(97, logger.getDebugLevel());
|
||||
|
||||
// Try the limits
|
||||
logger.setSeverity(Logger::DEBUG, -1);
|
||||
EXPECT_EQ(0, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 0);
|
||||
EXPECT_EQ(0, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 1);
|
||||
EXPECT_EQ(1, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 98);
|
||||
EXPECT_EQ(98, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 99);
|
||||
EXPECT_EQ(99, logger.getDebugLevel());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 100);
|
||||
EXPECT_EQ(99, logger.getDebugLevel());
|
||||
}
|
||||
|
||||
// Check that changing the parent and child severity does not affect the
|
||||
// other.
|
||||
|
||||
TEST_F(LoggerTest, SeverityInheritance) {
|
||||
|
||||
// Create to loggers. We cheat here as we know that the underlying
|
||||
// implementation (in this case log4cxx) will set a parent-child
|
||||
// relationship if the loggers are named <parent> and <parent>.<child>.
|
||||
|
||||
RootLoggerName::setName("test5");
|
||||
Logger parent("alpha");
|
||||
Logger child("alpha.beta");
|
||||
|
||||
// By default, newly created loggers should have a level of DEFAULT
|
||||
// (i.e. default to parent)
|
||||
EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
|
||||
EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
|
||||
|
||||
// Set the severity of the child to something other than the default -
|
||||
// check it changes and that of the parent does not.
|
||||
child.setSeverity(Logger::INFO);
|
||||
EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
|
||||
EXPECT_EQ(Logger::INFO, child.getSeverity());
|
||||
|
||||
// Reset the child severity and set that of the parent
|
||||
child.setSeverity(Logger::DEFAULT);
|
||||
EXPECT_EQ(Logger::DEFAULT, parent.getSeverity());
|
||||
EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
|
||||
parent.setSeverity(Logger::WARN);
|
||||
EXPECT_EQ(Logger::WARN, parent.getSeverity());
|
||||
EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
|
||||
}
|
||||
|
||||
// Check that severity is inherited.
|
||||
|
||||
TEST_F(LoggerTest, EffectiveSeverityInheritance) {
|
||||
|
||||
// Create to loggers. We cheat here as we know that the underlying
|
||||
// implementation (in this case log4cxx) will set a parent-child
|
||||
// relationship if the loggers are named <parent> and <parent>.<child>.
|
||||
|
||||
RootLoggerName::setName("test6");
|
||||
Logger parent("test6");
|
||||
Logger child("test6.beta");
|
||||
|
||||
// By default, newly created loggers should have a level of DEFAULT
|
||||
// (i.e. default to parent) and the root should have a default severity
|
||||
// of INFO. However, the latter is only enforced when created by the
|
||||
// RootLogger class, so explicitly set it for the parent for now.
|
||||
parent.setSeverity(Logger::INFO);
|
||||
EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
|
||||
|
||||
EXPECT_EQ(Logger::DEFAULT, child.getSeverity());
|
||||
EXPECT_EQ(Logger::INFO, child.getEffectiveSeverity());
|
||||
|
||||
// Set the severity of the child to something other than the default -
|
||||
// check it changes and that of the parent does not.
|
||||
child.setSeverity(Logger::FATAL);
|
||||
EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
|
||||
EXPECT_EQ(Logger::FATAL, child.getEffectiveSeverity());
|
||||
|
||||
// Reset the child severity and check again.
|
||||
child.setSeverity(Logger::DEFAULT);
|
||||
EXPECT_EQ(Logger::INFO, parent.getEffectiveSeverity());
|
||||
EXPECT_EQ(Logger::INFO, child.getEffectiveSeverity());
|
||||
|
||||
// Change the parwnt's severity and check it is reflects in the child.
|
||||
parent.setSeverity(Logger::WARN);
|
||||
EXPECT_EQ(Logger::WARN, parent.getEffectiveSeverity());
|
||||
EXPECT_EQ(Logger::WARN, child.getEffectiveSeverity());
|
||||
}
|
||||
|
||||
// Test the isXxxxEnabled methods.
|
||||
|
||||
TEST_F(LoggerTest, IsXxxEnabled) {
|
||||
|
||||
RootLoggerName::setName("test7");
|
||||
Logger logger("test7");
|
||||
|
||||
logger.setSeverity(Logger::INFO);
|
||||
EXPECT_FALSE(logger.isDebugEnabled());
|
||||
EXPECT_TRUE(logger.isInfoEnabled());
|
||||
EXPECT_TRUE(logger.isWarnEnabled());
|
||||
EXPECT_TRUE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
logger.setSeverity(Logger::WARN);
|
||||
EXPECT_FALSE(logger.isDebugEnabled());
|
||||
EXPECT_FALSE(logger.isInfoEnabled());
|
||||
EXPECT_TRUE(logger.isWarnEnabled());
|
||||
EXPECT_TRUE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
logger.setSeverity(Logger::ERROR);
|
||||
EXPECT_FALSE(logger.isDebugEnabled());
|
||||
EXPECT_FALSE(logger.isInfoEnabled());
|
||||
EXPECT_FALSE(logger.isWarnEnabled());
|
||||
EXPECT_TRUE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
logger.setSeverity(Logger::FATAL);
|
||||
EXPECT_FALSE(logger.isDebugEnabled());
|
||||
EXPECT_FALSE(logger.isInfoEnabled());
|
||||
EXPECT_FALSE(logger.isWarnEnabled());
|
||||
EXPECT_FALSE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
// Check various debug levels
|
||||
|
||||
logger.setSeverity(Logger::DEBUG);
|
||||
EXPECT_TRUE(logger.isDebugEnabled());
|
||||
EXPECT_TRUE(logger.isInfoEnabled());
|
||||
EXPECT_TRUE(logger.isWarnEnabled());
|
||||
EXPECT_TRUE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, 45);
|
||||
EXPECT_TRUE(logger.isDebugEnabled());
|
||||
EXPECT_TRUE(logger.isInfoEnabled());
|
||||
EXPECT_TRUE(logger.isWarnEnabled());
|
||||
EXPECT_TRUE(logger.isErrorEnabled());
|
||||
EXPECT_TRUE(logger.isFatalEnabled());
|
||||
|
||||
// Create a child logger with no severity set, and check that it reflects
|
||||
// the severity of the parent logger.
|
||||
|
||||
Logger child("test7.child");
|
||||
logger.setSeverity(Logger::FATAL);
|
||||
EXPECT_FALSE(child.isDebugEnabled());
|
||||
EXPECT_FALSE(child.isInfoEnabled());
|
||||
EXPECT_FALSE(child.isWarnEnabled());
|
||||
EXPECT_FALSE(child.isErrorEnabled());
|
||||
EXPECT_TRUE(child.isFatalEnabled());
|
||||
|
||||
logger.setSeverity(Logger::INFO);
|
||||
EXPECT_FALSE(child.isDebugEnabled());
|
||||
EXPECT_TRUE(child.isInfoEnabled());
|
||||
EXPECT_TRUE(child.isWarnEnabled());
|
||||
EXPECT_TRUE(child.isErrorEnabled());
|
||||
EXPECT_TRUE(child.isFatalEnabled());
|
||||
}
|
||||
|
||||
// Within the Debug level there are 100 debug levels. Test that we know
|
||||
// when to issue a debug message.
|
||||
|
||||
TEST_F(LoggerTest, IsDebugEnabledLevel) {
|
||||
|
||||
RootLoggerName::setName("test8");
|
||||
Logger logger("test8");
|
||||
|
||||
int MID_LEVEL = (MIN_DEBUG_LEVEL + MAX_DEBUG_LEVEL) / 2;
|
||||
|
||||
logger.setSeverity(Logger::DEBUG);
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, MIN_DEBUG_LEVEL);
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, MID_LEVEL);
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL - 1));
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MID_LEVEL + 1));
|
||||
EXPECT_FALSE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
|
||||
|
||||
logger.setSeverity(Logger::DEBUG, MAX_DEBUG_LEVEL);
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MIN_DEBUG_LEVEL));
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MID_LEVEL));
|
||||
EXPECT_TRUE(logger.isDebugEnabled(MAX_DEBUG_LEVEL));
|
||||
}
|
116
src/lib/log/tests/message_reader_unittest.cc
Normal file
116
src/lib/log/tests/message_reader_unittest.cc
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: base64_unittest.cc 2549 2010-07-20 19:09:37Z jinmei $
|
||||
|
||||
#include <string>
|
||||
#include <gtest/gtest.h>
|
||||
#include <log/message_reader.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::log;
|
||||
using namespace std;
|
||||
|
||||
class MessageReaderTest : public ::testing::Test {
|
||||
protected:
|
||||
MessageReaderTest() : reader_()
|
||||
{
|
||||
}
|
||||
|
||||
MessageReader reader_; // Default reader object
|
||||
};
|
||||
|
||||
|
||||
// Check for a couple of status messages
|
||||
|
||||
TEST_F(MessageReaderTest, StatusMessage) {
|
||||
string unknown("Unknown message code"); // Default unknown message
|
||||
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::SUCCESS));
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::DUPLPRFX));
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::PRFXEXTRARG));
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::PRFXINVARG));
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::PRFXNOARG));
|
||||
EXPECT_NE(unknown, reader_.errorText(MessageReader::UNRECDIR));
|
||||
}
|
||||
|
||||
// Check for parsing blank lines and comments. These should not add to the map and
|
||||
// each parse should return success.
|
||||
|
||||
TEST_F(MessageReaderTest, BlanksAndComments) {
|
||||
|
||||
// Ensure that the map is empty
|
||||
MessageReader::MessageMap mmap = reader_.getMessageMap();
|
||||
EXPECT_EQ(0, mmap.size());
|
||||
|
||||
MessageReader::MessageDuplicates mduplicates = reader_.getMessageDuplicates();
|
||||
EXPECT_EQ(0, mduplicates.size());
|
||||
|
||||
// Add a number of blank lines and comments and check that (a) they are parsed
|
||||
// successfully ...
|
||||
MessageReader::Status status = reader_.processLine("");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine(" ");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine(" \n ");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine("# This is a comment");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine("\t\t # Another comment");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine(" + A description line");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine("#+ A comment");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
status = reader_.processLine(" +# A description line");
|
||||
EXPECT_EQ(MessageReader::SUCCESS, status);
|
||||
|
||||
// ... and (b) nothing gets added to either the map or the duplicates
|
||||
mmap = reader_.getMessageMap();
|
||||
EXPECT_EQ(0, mmap.size());
|
||||
|
||||
mduplicates = reader_.getMessageDuplicates();
|
||||
EXPECT_EQ(0, mduplicates.size());
|
||||
}
|
||||
|
||||
// Check that it can parse a prefix
|
||||
|
||||
TEST_F(MessageReaderTest, Prefix) {
|
||||
|
||||
// Check that no prefix is present
|
||||
EXPECT_EQ(string(""), reader_.getPrefix());
|
||||
|
||||
// Check that a prefix directive with no argument generates an error.
|
||||
EXPECT_EQ(MessageReader::PRFXNOARG, reader_.processLine("$PREFIX"));
|
||||
|
||||
// Check a prefix with multiple arguments is invalid
|
||||
EXPECT_EQ(MessageReader::PRFXEXTRARG, reader_.processLine("$prefix A B"));
|
||||
|
||||
// Prefixes should be alphanumeric (with underscores) and not start
|
||||
// with a number.
|
||||
EXPECT_EQ(MessageReader::PRFXINVARG, reader_.processLine("$prefix ab[cd"));
|
||||
EXPECT_EQ(MessageReader::PRFXINVARG, reader_.processLine("$prefix 123"));
|
||||
EXPECT_EQ(MessageReader::PRFXINVARG, reader_.processLine("$prefix 1ABC"));
|
||||
|
||||
// A valid prefix should be accepted
|
||||
EXPECT_EQ(MessageReader::SUCCESS, reader_.processLine("$PREFIX dlm__"));
|
||||
EXPECT_EQ(string("DLM__"), reader_.getPrefix());
|
||||
|
||||
// And check that the parser fails on invalid prefixes...
|
||||
EXPECT_EQ(MessageReader::PRFXINVARG, reader_.processLine("$prefix 1ABC"));
|
||||
|
||||
// ... and rejects another valid one
|
||||
EXPECT_EQ(MessageReader::DUPLPRFX, reader_.processLine("$PREFIX ABC"));
|
||||
}
|
||||
|
52
src/lib/log/tests/root_logger_name_unittest.cc
Normal file
52
src/lib/log/tests/root_logger_name_unittest.cc
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: base64_unittest.cc 2549 2010-07-20 19:09:37Z jinmei $
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log/root_logger_name.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::log;
|
||||
|
||||
class RootLoggerNameTest : public ::testing::Test {
|
||||
protected:
|
||||
RootLoggerNameTest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Check of the (only) functionality of the class.
|
||||
|
||||
TEST_F(RootLoggerNameTest, SetGet) {
|
||||
const std::string name1 = "test1";
|
||||
const std::string name2 = "test2";
|
||||
|
||||
// Check that Set/Get works
|
||||
RootLoggerName::setName(name1);
|
||||
EXPECT_EQ(name1, RootLoggerName::getName());
|
||||
|
||||
// We could not test that the root logger name is initialised
|
||||
// correctly (as there is one instance of it and we don't know
|
||||
// when this test will be run) so to check that setName() actually
|
||||
// does change the name, run the test again with a different name.
|
||||
//
|
||||
// (There was always the outside chance that the root logger name
|
||||
// was initialised with name1 and that setName() has no effect.)
|
||||
RootLoggerName::setName(name2);
|
||||
EXPECT_EQ(name2, RootLoggerName::getName());
|
||||
}
|
23
src/lib/log/tests/run_unittests.cc
Normal file
23
src/lib/log/tests/run_unittests.cc
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2009 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.
|
||||
|
||||
// $Id: run_unittests.cc 3020 2010-09-26 03:47:26Z jinmei $
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int
|
||||
main(int argc, char* argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return (RUN_ALL_TESTS());
|
||||
}
|
122
src/lib/log/tests/stringutil_unittest.cc
Normal file
122
src/lib/log/tests/stringutil_unittest.cc
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: base64_unittest.cc 2549 2010-07-20 19:09:37Z jinmei $
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log/stringutil.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::log;
|
||||
using namespace std;
|
||||
|
||||
class StringUtilTest : public ::testing::Test {
|
||||
protected:
|
||||
StringUtilTest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Check for slash replacement
|
||||
|
||||
TEST_F(StringUtilTest, Slash) {
|
||||
|
||||
string instring = "";
|
||||
StringUtil::normalizeSlash(instring);
|
||||
EXPECT_EQ("", instring);
|
||||
|
||||
instring = "C:\\A\\B\\C.D";
|
||||
StringUtil::normalizeSlash(instring);
|
||||
EXPECT_EQ("C:/A/B/C.D", instring);
|
||||
|
||||
instring = "// \\ //";
|
||||
StringUtil::normalizeSlash(instring);
|
||||
EXPECT_EQ("// / //", instring);
|
||||
}
|
||||
|
||||
// Check that leading and trailing space trimming works
|
||||
|
||||
TEST_F(StringUtilTest, Trim) {
|
||||
|
||||
// Empty and full string.
|
||||
EXPECT_EQ("", StringUtil::trim(""));
|
||||
EXPECT_EQ("abcxyz", StringUtil::trim("abcxyz"));
|
||||
|
||||
// Trim right-most blanks
|
||||
EXPECT_EQ("ABC", StringUtil::trim("ABC "));
|
||||
EXPECT_EQ("ABC", StringUtil::trim("ABC\t\t \n\t"));
|
||||
|
||||
// Left-most blank trimming
|
||||
EXPECT_EQ("XYZ", StringUtil::trim(" XYZ"));
|
||||
EXPECT_EQ("XYZ", StringUtil::trim("\t\t \tXYZ"));
|
||||
|
||||
// Right and left, with embedded spaces
|
||||
EXPECT_EQ("MN \t OP", StringUtil::trim("\t\tMN \t OP \t"));
|
||||
}
|
||||
|
||||
// Check tokenization. Note that ASSERT_EQ is used to check the size of the
|
||||
// returned vector; if not as expected, the following references may be invalid
|
||||
// so should not be used.
|
||||
|
||||
TEST_F(StringUtilTest, Tokens) {
|
||||
vector<string> result;
|
||||
|
||||
// Default delimiters
|
||||
result = StringUtil::tokens(" \n "); // Empty string
|
||||
EXPECT_EQ(0, result.size());
|
||||
|
||||
result = StringUtil::tokens("abc"); // Full string
|
||||
ASSERT_EQ(1, result.size());
|
||||
EXPECT_EQ(string("abc"), result[0]);
|
||||
|
||||
result = StringUtil::tokens("\t xyz \n");
|
||||
ASSERT_EQ(1, result.size());
|
||||
EXPECT_EQ(string("xyz"), result[0]);
|
||||
|
||||
result = StringUtil::tokens("abc\ndef\t\tghi ");
|
||||
ASSERT_EQ(3, result.size());
|
||||
EXPECT_EQ(string("abc"), result[0]);
|
||||
EXPECT_EQ(string("def"), result[1]);
|
||||
EXPECT_EQ(string("ghi"), result[2]);
|
||||
|
||||
// Non-default delimiters
|
||||
result = StringUtil::tokens("alpha/beta/ /gamma//delta/epsilon/", "/");
|
||||
ASSERT_EQ(6, result.size());
|
||||
EXPECT_EQ(string("alpha"), result[0]);
|
||||
EXPECT_EQ(string("beta"), result[1]);
|
||||
EXPECT_EQ(string(" "), result[2]);
|
||||
EXPECT_EQ(string("gamma"), result[3]);
|
||||
EXPECT_EQ(string("delta"), result[4]);
|
||||
EXPECT_EQ(string("epsilon"), result[5]);
|
||||
}
|
||||
|
||||
// Changing case
|
||||
|
||||
TEST_F(StringUtilTest, ChangeCase) {
|
||||
string mixed("abcDEFghiJKLmno123[]{=+--+]}");
|
||||
string upper("ABCDEFGHIJKLMNO123[]{=+--+]}");
|
||||
string lower("abcdefghijklmno123[]{=+--+]}");
|
||||
|
||||
string test = mixed;
|
||||
StringUtil::lowercase(test);
|
||||
EXPECT_EQ(lower, test);
|
||||
|
||||
test = mixed;
|
||||
StringUtil::uppercase(test);
|
||||
EXPECT_EQ(upper, test);
|
||||
}
|
205
src/lib/log/tests/xdebuglevel_unittest.cc
Normal file
205
src/lib/log/tests/xdebuglevel_unittest.cc
Normal file
@@ -0,0 +1,205 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id: $
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <log4cxx/level.h>
|
||||
#include <log/xdebuglevel.h>
|
||||
#include <log/dbglevels.h>
|
||||
|
||||
/// \brief XDebugLevel (Debug Extension to Level Class)
|
||||
///
|
||||
/// The class is an extension of the log4cxx Level class; this set of tests
|
||||
/// only test the extensions, they do not test the underlying Level class
|
||||
/// itself.
|
||||
|
||||
using namespace log4cxx;
|
||||
|
||||
class XDebugLevelTest : public ::testing::Test {
|
||||
protected:
|
||||
XDebugLevelTest()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Check a basic assertion about the numeric values of the debug levels
|
||||
|
||||
TEST_F(XDebugLevelTest, NumericValues) {
|
||||
EXPECT_EQ(XDebugLevel::XDEBUG_MIN_LEVEL_INT, Level::DEBUG_INT);
|
||||
EXPECT_EQ(XDebugLevel::XDEBUG_MAX_LEVEL_INT,
|
||||
Level::DEBUG_INT - MAX_DEBUG_LEVEL);
|
||||
|
||||
// ... and check that assumptions used below - that the debug levels
|
||||
// range from 0 to 99 - are valid.
|
||||
EXPECT_EQ(0, MIN_DEBUG_LEVEL);
|
||||
EXPECT_EQ(99, MAX_DEBUG_LEVEL);
|
||||
}
|
||||
|
||||
|
||||
// Checks that the main function for generating logging level objects from
|
||||
// debug levels is working.
|
||||
|
||||
TEST_F(XDebugLevelTest, GetExtendedDebug) {
|
||||
|
||||
// Get a debug level of 0. This should be the same as the main DEBUG
|
||||
// level.
|
||||
LevelPtr debug0 = XDebugLevel::getExtendedDebug(0);
|
||||
EXPECT_EQ(std::string("DEBUG"), debug0->toString());
|
||||
EXPECT_EQ(Level::DEBUG_INT, debug0->toInt());
|
||||
EXPECT_TRUE(*Level::getDebug() == *debug0);
|
||||
|
||||
// Get an arbitrary debug level in the allowed range.
|
||||
LevelPtr debug32 = XDebugLevel::getExtendedDebug(32);
|
||||
EXPECT_EQ(std::string("DEBUG32"), debug32->toString());
|
||||
EXPECT_TRUE((XDebugLevel::XDEBUG_MIN_LEVEL_INT - 32) == debug32->toInt());
|
||||
|
||||
// Check that a value outside the range gives the nearest level.
|
||||
LevelPtr debug_more = XDebugLevel::getExtendedDebug(MAX_DEBUG_LEVEL + 1);
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MAX_DEBUG_LEVEL) == *debug_more);
|
||||
|
||||
LevelPtr debug_less = XDebugLevel::getExtendedDebug(MIN_DEBUG_LEVEL - 1);
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MIN_DEBUG_LEVEL) == *debug_less);
|
||||
}
|
||||
|
||||
|
||||
// Creation of a level from an int - should return the default debug level
|
||||
// if outside the range.
|
||||
|
||||
TEST_F(XDebugLevelTest, FromIntOneArg) {
|
||||
|
||||
// Check that a valid debug level is as expected
|
||||
LevelPtr debug42 = XDebugLevel::toLevel(
|
||||
XDebugLevel::XDEBUG_MIN_LEVEL_INT - 42);
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(42) == *debug42);
|
||||
|
||||
// ... and that an invalid one returns an object of type debug.
|
||||
LevelPtr debug_invalid = XDebugLevel::toLevel(Level::getInfo()->toInt());
|
||||
EXPECT_TRUE(*Level::getDebug() == *debug_invalid);
|
||||
}
|
||||
|
||||
|
||||
// Creation of a level from an int - should return the default level
|
||||
// if outside the range.
|
||||
|
||||
TEST_F(XDebugLevelTest, FromIntTwoArg) {
|
||||
|
||||
// Check that a valid debug level is as expected
|
||||
LevelPtr debug42 = XDebugLevel::toLevel(
|
||||
(XDebugLevel::XDEBUG_MIN_LEVEL_INT - 42), Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(42) == *debug42);
|
||||
|
||||
// ... and that an invalid one returns an object of type debug.
|
||||
LevelPtr debug_invalid = XDebugLevel::toLevel(
|
||||
Level::getInfo()->toInt(), Level::getFatal());
|
||||
EXPECT_TRUE(*Level::getFatal() == *debug_invalid);
|
||||
}
|
||||
|
||||
|
||||
// Creation of a level from a string - should return the default debug level
|
||||
// if outside the range.
|
||||
|
||||
TEST_F(XDebugLevelTest, FromStringOneArg) {
|
||||
|
||||
// Check that a valid debug levels are as expected
|
||||
LevelPtr debug85 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG85"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(85) == *debug85);
|
||||
|
||||
LevelPtr debug92 = XDebugLevel::toLevelLS(LOG4CXX_STR("debug92"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(92) == *debug92);
|
||||
|
||||
LevelPtr debug27 = XDebugLevel::toLevelLS(LOG4CXX_STR("Debug27"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(27) == *debug27);
|
||||
|
||||
LevelPtr debug0 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug0);
|
||||
|
||||
// ... and that an invalid one returns an object of type debug (which is
|
||||
// the equivalent of a debug level 0 object).
|
||||
LevelPtr debug_invalid1 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBU"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug_invalid1);
|
||||
|
||||
LevelPtr debug_invalid2 = XDebugLevel::toLevelLS(LOG4CXX_STR("EBU"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug_invalid2);
|
||||
|
||||
LevelPtr debug_invalid3 = XDebugLevel::toLevelLS(LOG4CXX_STR(""));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug_invalid3);
|
||||
|
||||
LevelPtr debug_invalid4 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUGTEN"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug_invalid4);
|
||||
|
||||
LevelPtr debug_invalid5 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG105"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MAX_DEBUG_LEVEL) ==
|
||||
*debug_invalid5);
|
||||
|
||||
LevelPtr debug_invalid6 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG-7"));
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MIN_DEBUG_LEVEL) ==
|
||||
*debug_invalid6);
|
||||
}
|
||||
|
||||
|
||||
// Creation of a level from a string - should return the default level
|
||||
// if outside the range.
|
||||
|
||||
TEST_F(XDebugLevelTest, FromStringTwoArg) {
|
||||
|
||||
// Check that a valid debug levels are as expected
|
||||
LevelPtr debug85 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG85"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(85) == *debug85);
|
||||
|
||||
LevelPtr debug92 = XDebugLevel::toLevelLS(LOG4CXX_STR("debug92"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(92) == *debug92);
|
||||
|
||||
LevelPtr debug27 = XDebugLevel::toLevelLS(LOG4CXX_STR("Debug27"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(27) == *debug27);
|
||||
|
||||
LevelPtr debug0 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(0) == *debug0);
|
||||
|
||||
// ... and that an invalid one returns an object of type debug (which is
|
||||
// the equivalent of a debug level 0 object).
|
||||
LevelPtr debug_invalid1 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBU"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*Level::getFatal() == *debug_invalid1);
|
||||
|
||||
LevelPtr debug_invalid2 = XDebugLevel::toLevelLS(LOG4CXX_STR("EBU"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*Level::getFatal() == *debug_invalid2);
|
||||
|
||||
LevelPtr debug_invalid3 = XDebugLevel::toLevelLS(LOG4CXX_STR(""),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*Level::getFatal() == *debug_invalid3);
|
||||
|
||||
LevelPtr debug_invalid4 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUGTEN"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*Level::getFatal() == *debug_invalid4);
|
||||
|
||||
LevelPtr debug_invalid5 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG105"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MAX_DEBUG_LEVEL) ==
|
||||
*debug_invalid5);
|
||||
|
||||
LevelPtr debug_invalid6 = XDebugLevel::toLevelLS(LOG4CXX_STR("DEBUG-7"),
|
||||
Level::getFatal());
|
||||
EXPECT_TRUE(*XDebugLevel::getExtendedDebug(MIN_DEBUG_LEVEL) ==
|
||||
*debug_invalid6);
|
||||
}
|
145
src/lib/log/xdebuglevel.cc
Normal file
145
src/lib/log/xdebuglevel.cc
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <xdebuglevel.h>
|
||||
#include <dbglevels.h>
|
||||
#include <log4cxx/helpers/stringhelper.h>
|
||||
|
||||
using namespace log4cxx;
|
||||
using namespace log4cxx::helpers;
|
||||
|
||||
// Storage for the logging level objects corresponding to each debug level
|
||||
|
||||
bool XDebugLevel::dbglevels_unset_ = true;
|
||||
LevelPtr XDebugLevel::dbglevels_[NUM_DEBUG_LEVEL];
|
||||
|
||||
// Register the class
|
||||
|
||||
IMPLEMENT_LOG4CXX_LEVEL(XDebugLevel)
|
||||
|
||||
|
||||
// Create Extended Debug Level Objects
|
||||
|
||||
LevelPtr XDebugLevel::getExtendedDebug(int level) {
|
||||
|
||||
// Initialize the logging levels corresponding to the possible range of
|
||||
// debug if we have not already done so
|
||||
if (dbglevels_unset_) {
|
||||
|
||||
// Asserting that the minimum debug level is zero - so corresponds
|
||||
// to DEBUG_INT - means that the lowest level is set to main DEBUG
|
||||
// level. This means that the existing logging level object can be
|
||||
// used.
|
||||
assert(MIN_DEBUG_LEVEL == 0);
|
||||
dbglevels_[0] = Level::getDebug();
|
||||
|
||||
// Create the logging level objects for the rest of the debug levels.
|
||||
// They are given names of the form DEBUG<debug level> (e.g. DEBUG42).
|
||||
// They will all correspond to a syslog level of DEBUG.
|
||||
for (int i = 1; i < NUM_DEBUG_LEVEL; ++i) {
|
||||
std::string name = std::string("DEBUG") +
|
||||
boost::lexical_cast<std::string>(i);
|
||||
dbglevels_[i] = new XDebugLevel(
|
||||
(XDebugLevel::XDEBUG_MIN_LEVEL_INT - i),
|
||||
LOG4CXX_STR(name.c_str()), LOG_DEBUG);
|
||||
}
|
||||
dbglevels_unset_ = false;
|
||||
}
|
||||
|
||||
// Now get the logging level object asked for. Coerce the debug level to
|
||||
// lie in the acceptable range.
|
||||
int actual = std::max(MIN_DEBUG_LEVEL, std::min(MAX_DEBUG_LEVEL, level));
|
||||
|
||||
// ... and return a pointer to the appropriate logging level object
|
||||
return dbglevels_[actual - MIN_DEBUG_LEVEL];
|
||||
}
|
||||
|
||||
// Convert an integer (an absolute logging level number, not a debug level) to a
|
||||
// logging level object. If it lies outside the valid range, an object
|
||||
// corresponding to the minimum debug value is returned.
|
||||
|
||||
LevelPtr XDebugLevel::toLevel(int val) {
|
||||
return toLevel(val, getExtendedDebug(MIN_DEBUG_LEVEL));
|
||||
}
|
||||
|
||||
LevelPtr XDebugLevel::toLevel(int val, const LevelPtr& defaultLevel) {
|
||||
|
||||
// Note the reversal of the notion of MIN and MAX - see the header file for
|
||||
// details.
|
||||
if ((val >= XDEBUG_MAX_LEVEL_INT) && (val <= XDEBUG_MIN_LEVEL_INT)) {
|
||||
return getExtendedDebug(XDEBUG_MIN_LEVEL_INT - val);
|
||||
}
|
||||
else {
|
||||
return defaultLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert string passed to a logging level or return default level.
|
||||
|
||||
LevelPtr XDebugLevel::toLevelLS(const LogString& sArg) {
|
||||
return toLevelLS(sArg, getExtendedDebug(0));
|
||||
}
|
||||
|
||||
LevelPtr XDebugLevel::toLevelLS(const LogString& sArg,
|
||||
const LevelPtr& defaultLevel)
|
||||
{
|
||||
std::string name = sArg; // Get to known type
|
||||
size_t length = name.size(); // Length of the string
|
||||
|
||||
if (length < 5) {
|
||||
|
||||
// String can't possibly start DEBUG so we don't know what it is.
|
||||
return defaultLevel;
|
||||
}
|
||||
else {
|
||||
if (strncasecmp(name.c_str(), "DEBUG", 5) == 0) {
|
||||
|
||||
// String starts "DEBUG" (or "debug" or any case mixture). The
|
||||
// rest of the string -if any - should be a number.
|
||||
if (length == 5) {
|
||||
|
||||
// It is plain "DEBUG". Take this as level 0.
|
||||
return getExtendedDebug(0);
|
||||
}
|
||||
else {
|
||||
|
||||
// Try converting the remainder to an integer. The "5" is
|
||||
// the length of the string "DEBUG". Note that if the number
|
||||
// is outside the rangeof debug levels, it is coerced to the
|
||||
// nearest limit. Thus a level of DEBUG509 will end up as
|
||||
// if DEBUG99 has been specified.
|
||||
try {
|
||||
int level = boost::lexical_cast<int>(name.substr(5));
|
||||
return getExtendedDebug(level);
|
||||
}
|
||||
catch (boost::bad_lexical_cast&) {
|
||||
return defaultLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// Unknown string - return default
|
||||
return defaultLevel;
|
||||
}
|
||||
}
|
||||
}
|
164
src/lib/log/xdebuglevel.h
Normal file
164
src/lib/log/xdebuglevel.h
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2010 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.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __XDEBUGLEVEL_H
|
||||
#define __XDEBUGLEVEL_H
|
||||
|
||||
#include <syslog.h>
|
||||
#include <log4cxx/level.h>
|
||||
|
||||
#include <dbglevels.h>
|
||||
|
||||
namespace log4cxx {
|
||||
|
||||
/// \brief Debug Extension to Level Class
|
||||
///
|
||||
/// Based on the example given in the log4cxx distribution, this extends the
|
||||
/// log4cxx Level class to allow 100 debug levels.
|
||||
///
|
||||
/// First some terminology, as the use of the term "level" gets confusing. The
|
||||
/// code and comments here use the term "level" in two contexts:
|
||||
///
|
||||
/// Logging level: The category of messages to log. By default log4cxx defines
|
||||
/// the following logging levels: OFF, FATAL, ERROR, WARNING, INFO, DEBUG,
|
||||
/// TRACE, ALL. Within the context of BIND-10, OFF, TRACE and ALL are not used
|
||||
/// and the idea of DEBUG has been extended, as will be seen below.
|
||||
///
|
||||
/// Debug level: This is a number that ranges from 0 to 99 and is used by the
|
||||
/// application to control the detail of debug output. A value of 0 gives the
|
||||
/// highest-level debug output; a value of 99 gives the most verbose and most
|
||||
/// detailed. Debug messages (or whatever debug level) are only ever output
|
||||
/// when the logging level is set to DEBUG.
|
||||
///
|
||||
///
|
||||
/// With log4cxx, the various logging levels have a numeric value associated
|
||||
/// with them, such that FATAL > ERROR > WARNING etc. This suggests that the
|
||||
/// idea of debug levels can be incorporated into the existing logging level
|
||||
/// scheme by assigning them appropriate numeric values, i.e.
|
||||
///
|
||||
/// WARNING > INFO > DEBUG(0) > DEBUG(2) > ... > DEBUG(99)
|
||||
///
|
||||
/// Setting a numeric level of DEBUG enables the basic messages; setting lower
|
||||
/// numeric levels will enable progressively more messages. The lowest debug
|
||||
/// level (0) is chosen such that setting the general DEBUG logging level will
|
||||
/// automatically select that debug level.
|
||||
///
|
||||
/// This sub-class is needed because the log4cxx::Level class does not allow
|
||||
/// the setting of the numeric value of the current level to something other
|
||||
/// than the values enumerated in the class. It creates a set of log4cxx
|
||||
/// logging levels to correspond to the various debug levels. These levels have
|
||||
/// names in the range DEBUG1 to DEBUG99 (the existing Level DEBUG is used for
|
||||
/// a debug level of 0), although they are not used in BIND-10: instead the
|
||||
/// BIND-10 Logger class treats the logging levels and debug levels separately
|
||||
/// and combines them to choose the underlying log4cxx logging level.
|
||||
|
||||
|
||||
/// \brief Debug-Extended Level
|
||||
|
||||
class XDebugLevel : public Level {
|
||||
DECLARE_LOG4CXX_LEVEL(XDebugLevel)
|
||||
|
||||
/// Array of pointers to logging level objects, one for each debug level.
|
||||
/// The pointer corresponding to a debug level of 0 points to the DEBUG
|
||||
/// logging level object.
|
||||
static LevelPtr dbglevels_[NUM_DEBUG_LEVEL];
|
||||
static bool dbglevels_unset_;
|
||||
|
||||
public:
|
||||
|
||||
// Minimum and maximum debug levels. Note that XDEBUG_MIN_LEVEL_INT is the
|
||||
// number corresponding to the minimum debug level - and is actually larger
|
||||
// that XDEBUG_MAX_LEVEL_INT, the number corresponding to the maximum debug
|
||||
// level.
|
||||
enum {
|
||||
XDEBUG_MIN_LEVEL_INT = Level::DEBUG_INT - MIN_DEBUG_LEVEL,
|
||||
XDEBUG_MAX_LEVEL_INT = Level::DEBUG_INT - MAX_DEBUG_LEVEL
|
||||
};
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// \param level Numeric value of the logging level.
|
||||
/// \param name Name given to this logging level.
|
||||
/// \param syslogEquivalent The category to be used by syslog when it logs
|
||||
/// an event associated with the specified logging level.
|
||||
XDebugLevel(int level, const LogString& name, int syslogEquivalent) :
|
||||
Level(level, name, syslogEquivalent)
|
||||
{}
|
||||
|
||||
/// \brief Create Logging Level Object
|
||||
///
|
||||
/// Creates a logging level object corresponding to one of the debug levels.
|
||||
///
|
||||
/// \param dbglevel The debug level, which ranges from MIN_DEBUG_LEVEL to
|
||||
/// MAX_DEBUG_LEVEL. It is coerced to that range if it lies outside it.
|
||||
///
|
||||
/// \return Pointer to the desired logging level object.
|
||||
static LevelPtr getExtendedDebug(int dbglevel);
|
||||
|
||||
/// \brief Convert Integer to a Logging Level
|
||||
///
|
||||
/// Returns a logging level object corresponding to the given value (which
|
||||
/// is an absolute value of a logging level - it is not a debug level).
|
||||
/// If the number is invalid, an object of logging level DEBUG (the
|
||||
/// minimum debug logging level) is returned.
|
||||
///
|
||||
/// \param val Number to convert to a logging level. This is an absolute
|
||||
/// logging level number, not a debug level.
|
||||
///
|
||||
/// \return Pointer to the desired logging level object.
|
||||
static LevelPtr toLevel(int val);
|
||||
|
||||
/// \brief Convert Integer to a Level
|
||||
///
|
||||
/// Returns a logging level object corresponding to the given value (which
|
||||
/// is an absolute value of a logging level - it is not a debug level).
|
||||
/// If the number is invalid, the given default is returned.
|
||||
///
|
||||
/// \param val Number to convert to a logging level. This is an absolute
|
||||
/// logging level number, not a debug level.
|
||||
/// \param defaultLevel Logging level to return if value is not recognised.
|
||||
///
|
||||
/// \return Pointer to the desired logging level object.
|
||||
static LevelPtr toLevel(int val, const LevelPtr& defaultLevel);
|
||||
|
||||
/// \param Convert String to Logging Level
|
||||
///
|
||||
/// Returns a logging level object corresponding to the given name. If the
|
||||
/// name is invalid, an object of logging level DEBUG (the minimum debug
|
||||
/// logging level) is returned.
|
||||
///
|
||||
/// \param sArg Name of the logging level.
|
||||
///
|
||||
/// \return Pointer to the desired logging level object.
|
||||
static LevelPtr toLevelLS(const LogString& sArg);
|
||||
|
||||
/// \param Convert String to Logging Level
|
||||
///
|
||||
/// Returns a logging level object corresponding to the given name. If the
|
||||
/// name is invalid, the given default is returned.
|
||||
///
|
||||
/// \param sArg name of the level.
|
||||
/// \param defaultLevel Logging level to return if name does not exist.
|
||||
///
|
||||
/// \return Pointer to the desired logging level object.
|
||||
static LevelPtr toLevelLS(const LogString& sArg,
|
||||
const LevelPtr& defaultLevel);
|
||||
};
|
||||
|
||||
} // namespace log4cxx
|
||||
|
||||
|
||||
#endif // __XDEBUGLEVEL_H
|
Reference in New Issue
Block a user