|
@@ -28,6 +28,7 @@
|
|
|
|
|
|
#include <iostream>
|
|
|
#include <string>
|
|
|
+#include <vector>
|
|
|
|
|
|
#include <util/strutil.h>
|
|
|
|
|
@@ -49,23 +50,54 @@ using namespace std;
|
|
|
|
|
|
void usage() {
|
|
|
cout <<
|
|
|
-"logger_support_test [-h] [-c stream] [-d dbglevel] [-f file]\n"
|
|
|
-" [-s severity] [localfile]\n"
|
|
|
+"logger_support_test [-h | [logger_spec] [[logger_spec]...]]\n"
|
|
|
"\n"
|
|
|
-" -h Print this message and exit\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 serverity 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"
|
|
|
-" -c stream Send output to the console. 'stream' is one of 'stdout'\n"
|
|
|
-" of 'stderr'. The '-c' switch is incompatible with '-f'\n"
|
|
|
-" and '-l'\n"
|
|
|
-" -f file Send output to specified file, appending to existing file\n"
|
|
|
-" if one exists. Incompatible with -c and -l switches.\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"
|
|
|
-"If none of -c, -f or -l is given, by default, output is sent to stdout\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";
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -73,37 +105,57 @@ void usage() {
|
|
|
// messages. Looking at the output determines whether the program worked.
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
- const string ROOT_NAME = "alpha";
|
|
|
+ const string 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 l_found = false; // Set true if "-l" found
|
|
|
-
|
|
|
+ bool y_found = false; // Set true if "-y" found
|
|
|
int option; // For getopt() processing
|
|
|
-
|
|
|
- LoggerSpecification spec(ROOT_NAME); // Logger specification
|
|
|
- OutputOption outopt; // Logger output option
|
|
|
-
|
|
|
- // Initialize loggers (to set the root name and initialize logging);
|
|
|
- LoggerManager::init(ROOT_NAME);
|
|
|
-
|
|
|
- // Parse options
|
|
|
- while ((option = getopt(argc, argv, "hc:d:f:s:")) != -1) {
|
|
|
+ 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
|
|
|
+ vector<OutputOption> options; // Output options for logger
|
|
|
+ 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 thge 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 BIND 10 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 completey 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':
|
|
|
- if (f_found || l_found) {
|
|
|
- cerr << "Cannot specify -c with -f or -l\n";
|
|
|
- return (1);
|
|
|
+ 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;
|
|
|
+ c_found = f_found = y_found = false;
|
|
|
}
|
|
|
|
|
|
+ // Set the output option for this switch.
|
|
|
c_found = true;
|
|
|
- outopt.destination = OutputOption::DEST_CONSOLE;
|
|
|
-
|
|
|
+ cur_opt.destination = OutputOption::DEST_CONSOLE;
|
|
|
if (strcmp(optarg, "stdout") == 0) {
|
|
|
- outopt.stream = OutputOption::STR_STDOUT;
|
|
|
+ cur_opt.stream = OutputOption::STR_STDOUT;
|
|
|
|
|
|
} else if (strcmp(optarg, "stderr") == 0) {
|
|
|
- outopt.stream = OutputOption::STR_STDERR;
|
|
|
+ cur_opt.stream = OutputOption::STR_STDERR;
|
|
|
|
|
|
} else {
|
|
|
cerr << "Unrecognised console option: " << optarg << "\n";
|
|
@@ -111,66 +163,143 @@ int main(int argc, char** argv) {
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
- case 'd':
|
|
|
- spec.setDbglevel(boost::lexical_cast<int>(optarg));
|
|
|
+ case 'd': // Debug level
|
|
|
+ cur_spec.setDbglevel(boost::lexical_cast<int>(optarg));
|
|
|
break;
|
|
|
|
|
|
- case 'f':
|
|
|
- if (c_found || l_found) {
|
|
|
- cerr << "Cannot specify -f with -c or -l\n";
|
|
|
- return (1);
|
|
|
+ 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 = f_found = y_found = false;
|
|
|
}
|
|
|
|
|
|
+ // Set the output option for this switch.
|
|
|
f_found = true;
|
|
|
-
|
|
|
- outopt.destination = OutputOption::DEST_FILE;
|
|
|
- outopt.filename = optarg;
|
|
|
+ cur_opt.destination = OutputOption::DEST_FILE;
|
|
|
+ cur_opt.filename = optarg;
|
|
|
break;
|
|
|
|
|
|
- case 'h':
|
|
|
+ case 'h': // Help
|
|
|
usage();
|
|
|
return (0);
|
|
|
|
|
|
- case 's':
|
|
|
- {
|
|
|
- string severity(optarg);
|
|
|
- isc::util::str::uppercase(severity);
|
|
|
- spec.setSeverity(getSeverity(severity));
|
|
|
+ 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.maxsize = boost::lexical_cast<unsigned int>(optarg);
|
|
|
+ } catch (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 = y_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 (boost::bad_lexical_cast&) {
|
|
|
+ std::cerr << "File size (-z) argument must be a positive "
|
|
|
+ "integer\n";
|
|
|
+ return (1);
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
+
|
|
|
default:
|
|
|
std::cerr << "Unrecognised option: " <<
|
|
|
static_cast<char>(option) << "\n";
|
|
|
return (1);
|
|
|
}
|
|
|
+
|
|
|
+ // Have found at least one command-line switch, so note the fact.
|
|
|
+ sw_found = true;
|
|
|
}
|
|
|
|
|
|
- // Update the logging parameters. If no output options
|
|
|
- // were set, the defaults will be used.
|
|
|
- spec.addOutputOption(outopt);
|
|
|
+ // Add the current (unfinished specification) to the list.
|
|
|
+ cur_spec.addOutputOption(cur_opt);
|
|
|
+ loggers.push_back(cur_spec);
|
|
|
|
|
|
- // Set the logging options for the root logger.
|
|
|
- LoggerManager manager;
|
|
|
- manager.process(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.
|
|
|
+ isc::log::Logger logger_ex(ROOT_NAME);
|
|
|
+ isc::log::Logger logger_alpha("alpha");
|
|
|
+ isc::log::Logger logger_beta("beta");
|
|
|
|
|
|
- // Log a few messages
|
|
|
- isc::log::Logger logger_dlm("dlm");
|
|
|
- isc::log::Logger logger_ex("example");
|
|
|
LOG_FATAL(logger_ex, MSG_WRITERR).arg("test1").arg("42");
|
|
|
LOG_ERROR(logger_ex, MSG_RDLOCMES).arg("dummy/file");
|
|
|
- LOG_WARN(logger_dlm, MSG_READERR).arg("a.txt").arg("dummy reason");
|
|
|
- LOG_INFO(logger_dlm, MSG_OPENIN).arg("example.msg").arg("dummy reason");
|
|
|
- LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("dummy/0");
|
|
|
- LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("dummy/24");
|
|
|
- LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("dummy/25");
|
|
|
- LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("dummy/26");
|
|
|
+ LOG_WARN(logger_ex, MSG_BADSTREAM).arg("example");
|
|
|
+ LOG_WARN(logger_alpha, MSG_READERR).arg("a.txt").arg("dummy reason");
|
|
|
+ LOG_INFO(logger_alpha, MSG_OPENIN).arg("example.msg").arg("dummy reason");
|
|
|
+ LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("example/0");
|
|
|
+ LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("example/24");
|
|
|
+ LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("example/25");
|
|
|
+ LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("example/26");
|
|
|
+ LOG_FATAL(logger_beta, MSG_BADSEVERITY).arg("beta_fatal");
|
|
|
+ LOG_ERROR(logger_beta, MSG_BADDESTINATION).arg("beta_error");
|
|
|
+ LOG_WARN(logger_beta, MSG_BADSTREAM).arg("beta_warn");
|
|
|
+ LOG_INFO(logger_beta, MSG_READERR).arg("beta").arg("info");
|
|
|
+ LOG_DEBUG(logger_beta, 25, MSG_BADSEVERITY).arg("beta/25");
|
|
|
+ LOG_DEBUG(logger_beta, 26, MSG_BADSEVERITY).arg("beta/26");
|
|
|
|
|
|
return (0);
|
|
|
}
|