diff options
Diffstat (limited to 'src/lib/log/tests/logger_example.cc')
-rw-r--r-- | src/lib/log/tests/logger_example.cc | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/lib/log/tests/logger_example.cc b/src/lib/log/tests/logger_example.cc new file mode 100644 index 0000000..ff3d512 --- /dev/null +++ b/src/lib/log/tests/logger_example.cc @@ -0,0 +1,306 @@ +// Copyright (C) 2011-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// \brief Example Program +/// +/// Simple example program showing how to use the logger. The various +/// command-line options let most aspects of the logger be exercised, so +/// making this a useful tool for testing. +/// +/// See the usage() method for details of use. + +#include <config.h> + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <boost/lexical_cast.hpp> + +#include <iostream> +#include <string> +#include <vector> + +#include <util/strutil.h> + +#include <log/logger.h> +#include <log/logger_level.h> +#include <log/logger_manager.h> +#include <log/logger_name.h> +#include <log/logger_specification.h> +#include <log/macros.h> + +// Include a set of message definitions. +#include <log/log_messages.h> +#include <log/interprocess/interprocess_sync_null.h> + +using namespace isc::log; +using namespace std; +using isc::log::interprocess::InterprocessSyncNull; + +// Print usage information + +void usage() { + cout << +"logger_support_test [-h | [logger_spec] [[logger_spec]...]]\n" +"\n" +" -h Print this message and exit\n" +"\n" +"The rest of the command line comprises the set of logger specifications.\n" +"Each specification is of the form:\n" +"\n" +" -l logger [-s severity] [-d dbglevel] output_spec] [[output_spec] ...\n" +"\n" +"where:\n" +"\n" +" -l logger Give the name of the logger to which the following\n" +" output specifications will apply.\n" +"\n" +"Each logger is followed by the indication of the severity it is logging\n" +"and, if applicable, its debug level:\n" +"\n" +" -d dbglevel Debug level. Only interpreted if the severity is 'debug'\n" +" this is a number between 0 and 99.\n" +" -s severity Set the severity of messages output. 'severity' is one\n" +" of 'debug', 'info', 'warn', 'error', 'fatal', the default\n" +" being 'info'.\n" +"\n" +"The output specifications - there may be more than one per logger - detail\n" +"the output streams attached to the logger. These are of the form:\n" +"\n" +" -c stream | -f file [-m maxver] [-z maxsize] | -y facility\n" +"\n" +"These are:\n" +"\n" +" -c stream Send output to the console. 'stream' is one of 'stdout'\n" +" of 'stderr'.\n" +" -f file Send output to specified file, appending to existing file\n" +" if one exists.\n" +" -y facility Send output to the syslog file with the given facility\n" +" name (e.g. local1, cron etc.)\n" +"\n" +"The following can be specified for the file logger:\n" +"\n" +" -m maxver If file rolling is selected (by the maximum file size being\n" +" non-zero), the maximum number of versions to keep (defaults\n" +" to 0)\n" +" -z maxsize Maximum size of the file before the file is closed and a\n" +" new one opened. The default of 0 means no maximum size.\n" +"\n" +"If none of -c, -f or -y is given, by default, output is sent to stdout. If no\n" +"logger is specified, the default is the program's root logger ('example').\n"; + +} + + +// The program sets the attributes on the root logger and logs a set of +// messages. Looking at the output determines whether the program worked. + +int main(int argc, char** argv) { + const char* ROOT_NAME = "example"; + + bool sw_found = false; // Set true if switch found + bool c_found = false; // Set true if "-c" found + bool f_found = false; // Set true if "-f" found + bool y_found = false; // Set true if "-y" found + int option; // For getopt() processing + OutputOption def_opt; // Default output option - used + // for initialization + LoggerSpecification cur_spec(ROOT_NAME);// Current specification + OutputOption cur_opt; // Current output option + vector<LoggerSpecification> loggers; // Set of logger specifications + std::string severity; // Severity set for logger + + // Initialize logging system - set the root logger name. + LoggerManager manager; + manager.init(ROOT_NAME); + + // In the parsing loop that follows, the construction of the logging + // specification is always "one behind". In other words, the parsing of + // command-line options updates the current logging specification/output + // options. When the flag indicating a new logger or output specification + // is encountered, the previous one is added to the list. + // + // One complication is that there is deemed to be a default active when + // the parsing starts (console output for the Kea root logger). This + // is included in the logging specifications UNLESS the first switch on + // the command line is a "-l" flag starting a new logger. To track this, + // the "sw_found" flag is set when a switch is completely processed. The + // processing of "-l" will only add information for a previous logger to + // the list if this flag is set. + while ((option = getopt(argc, argv, "hc:d:f:l:m:s:y:z:")) != -1) { + switch (option) { + case 'c': // Console output + // New output spec. If one was currently active, add it to the + // list and reset the current output option to the defaults. + if (c_found || f_found || y_found) { + cur_spec.addOutputOption(cur_opt); + cur_opt = def_opt; + f_found = y_found = false; + } + + // Set the output option for this switch. + c_found = true; + cur_opt.destination = OutputOption::DEST_CONSOLE; + if (strcmp(optarg, "stdout") == 0) { + cur_opt.stream = OutputOption::STR_STDOUT; + + } else if (strcmp(optarg, "stderr") == 0) { + cur_opt.stream = OutputOption::STR_STDERR; + + } else { + cerr << "Unrecognized console option: " << optarg << "\n"; + return (1); + } + break; + + case 'd': // Debug level + cur_spec.setDbglevel(boost::lexical_cast<int>(optarg)); + break; + + case 'f': // File output specification + // New output spec. If one was currently active, add it to the + // list and reset the current output option to the defaults. + if (c_found || f_found || y_found) { + cur_spec.addOutputOption(cur_opt); + cur_opt = def_opt; + c_found = y_found = false; + } + + // Set the output option for this switch. + f_found = true; + cur_opt.destination = OutputOption::DEST_FILE; + cur_opt.filename = optarg; + break; + + case 'h': // Help + usage(); + return (0); + + case 'l': // Logger + // If a current specification is active, add the last output option + // to it, add it to the list and reset. A specification is active + // if at least one switch has been previously found. + if (sw_found) { + cur_spec.addOutputOption(cur_opt); + loggers.push_back(cur_spec); + cur_spec.reset(); + } + + // Set the logger name + cur_spec.setName(std::string(optarg)); + + // Reset the output option to the default. + cur_opt = def_opt; + + // Indicate nothing is found to prevent the console option (the + // default output option) being added to the output list if an + // output option is found. + c_found = f_found = y_found = false; + break; + + case 'm': // Maximum file version + if (!f_found) { + std::cerr << "Attempt to set maximum version (-m) " + "outside of file output specification\n"; + return (1); + } + try { + cur_opt.maxver = boost::lexical_cast<unsigned int>(optarg); + } catch (const boost::bad_lexical_cast&) { + std::cerr << "Maximum version (-m) argument must be a positive " + "integer\n"; + return (1); + } + break; + + case 's': // Severity + severity = optarg; + isc::util::str::uppercase(severity); + cur_spec.setSeverity(getSeverity(severity)); + break; + + case 'y': // Syslog output + // New output spec. If one was currently active, add it to the + // list and reset the current output option to the defaults. + if (c_found || f_found || y_found) { + cur_spec.addOutputOption(cur_opt); + cur_opt = def_opt; + c_found = f_found = false; + } + y_found = true; + cur_opt.destination = OutputOption::DEST_SYSLOG; + cur_opt.facility = optarg; + break; + + case 'z': // Maximum size + if (! f_found) { + std::cerr << "Attempt to set file size (-z) " + "outside of file output specification\n"; + return (1); + } + try { + cur_opt.maxsize = boost::lexical_cast<size_t>(optarg); + } catch (const boost::bad_lexical_cast&) { + std::cerr << "File size (-z) argument must be a positive " + "integer\n"; + return (1); + } + break; + + + default: + std::cerr << "Unrecognized option: " << + static_cast<char>(option) << "\n"; + return (1); + } + + // Have found at least one command-line switch, so note the fact. + sw_found = true; + } + + // Add the current (unfinished specification) to the list. + cur_spec.addOutputOption(cur_opt); + loggers.push_back(cur_spec); + + // Set the logging options. + manager.process(loggers.begin(), loggers.end()); + + // Set the local file + if (optind < argc) { + LoggerManager::readLocalMessageFile(argv[optind]); + } + + // Log a few messages to different loggers. Here, we switch to using + // null interprocess sync objects for the loggers below as the + // logger example can be used as a standalone program (which may not + // have write access to a local state directory to create + // lockfiles). + isc::log::Logger logger_ex(ROOT_NAME); + logger_ex.setInterprocessSync(new InterprocessSyncNull("logger")); + isc::log::Logger logger_alpha("alpha"); + logger_alpha.setInterprocessSync(new InterprocessSyncNull("logger")); + isc::log::Logger logger_beta("beta"); + logger_beta.setInterprocessSync(new InterprocessSyncNull("logger")); + + LOG_FATAL(logger_ex, LOG_WRITE_ERROR).arg("test1").arg("42"); + LOG_ERROR(logger_ex, LOG_READING_LOCAL_FILE).arg("dummy/file"); + LOG_WARN(logger_ex, LOG_BAD_STREAM).arg("example"); + LOG_WARN(logger_alpha, LOG_READ_ERROR).arg("a.txt").arg("dummy reason"); + LOG_INFO(logger_alpha, LOG_INPUT_OPEN_FAIL).arg("example.msg").arg("dummy reason"); + LOG_DEBUG(logger_ex, 0, LOG_READING_LOCAL_FILE).arg("example/0"); + LOG_DEBUG(logger_ex, 24, LOG_READING_LOCAL_FILE).arg("example/24"); + LOG_DEBUG(logger_ex, 25, LOG_READING_LOCAL_FILE).arg("example/25"); + LOG_DEBUG(logger_ex, 26, LOG_READING_LOCAL_FILE).arg("example/26"); + LOG_FATAL(logger_beta, LOG_BAD_SEVERITY).arg("beta_fatal"); + LOG_ERROR(logger_beta, LOG_BAD_DESTINATION).arg("beta_error"); + LOG_WARN(logger_beta, LOG_BAD_STREAM).arg("beta_warn"); + LOG_INFO(logger_beta, LOG_READ_ERROR).arg("beta").arg("info"); + LOG_DEBUG(logger_beta, 25, LOG_BAD_SEVERITY).arg("beta/25"); + LOG_DEBUG(logger_beta, 26, LOG_BAD_SEVERITY).arg("beta/26"); + + return (0); +} |