logger_example.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. /// \brief Example Program
  15. ///
  16. /// Simple example program showing how to use the logger. The various
  17. /// command-line options let most aspects of the logger be exercised, so
  18. /// making this a useful tool for testing.
  19. ///
  20. /// See the usage() method for details of use.
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. #include <string.h>
  24. #include <boost/lexical_cast.hpp>
  25. #include <iostream>
  26. #include <string>
  27. #include <vector>
  28. #include <util/strutil.h>
  29. #include <log/logger.h>
  30. #include <log/logger_level.h>
  31. #include <log/logger_manager.h>
  32. #include <log/logger_name.h>
  33. #include <log/logger_specification.h>
  34. #include <log/macros.h>
  35. // Include a set of message definitions.
  36. #include <log/messagedef.h>
  37. using namespace isc::log;
  38. using namespace std;
  39. // Print usage information
  40. void usage() {
  41. cout <<
  42. "logger_support_test [-h | [logger_spec] [[logger_spec]...]]\n"
  43. "\n"
  44. " -h Print this message and exit\n"
  45. "\n"
  46. "The rest of the command line comprises the set of logger specifications.\n"
  47. "Each specification is of the form:\n"
  48. "\n"
  49. " -l logger [-s severity] [-d dbglevel] output_spec] [[output_spec] ...\n"
  50. "\n"
  51. "where:\n"
  52. "\n"
  53. " -l logger Give the name of the logger to which the following\n"
  54. " output specifications will apply.\n"
  55. "\n"
  56. "Each logger is followed by the indication of the serverity it is logging\n"
  57. "and, if applicable, its debug level:\n"
  58. "\n"
  59. " -d dbglevel Debug level. Only interpreted if the severity is 'debug'\n"
  60. " this is a number between 0 and 99.\n"
  61. " -s severity Set the severity of messages output. 'severity' is one\n"
  62. " of 'debug', 'info', 'warn', 'error', 'fatal', the default\n"
  63. " being 'info'.\n"
  64. "\n"
  65. "The output specifications - there may be more than one per logger - detail\n"
  66. "the output streams attached to the logger. These are of the form:\n"
  67. "\n"
  68. " -c stream | -f file [-m maxver] [-z maxsize] | -y facility\n"
  69. "\n"
  70. "These are:\n"
  71. "\n"
  72. " -c stream Send output to the console. 'stream' is one of 'stdout'\n"
  73. " of 'stderr'.\n"
  74. " -f file Send output to specified file, appending to existing file\n"
  75. " if one exists.\n"
  76. " -y facility Send output to the syslog file with the given facility\n"
  77. " name (e.g. local1, cron etc.)\n"
  78. "\n"
  79. "The following can be specified for the file logger:\n"
  80. "\n"
  81. " -m maxver If file rolling is selected (by the maximum file size being\n"
  82. " non-zero), the maximum number of versions to keep (defaults\n"
  83. " to 0)\n"
  84. " -z maxsize Maximum size of the file before the file is closed and a\n"
  85. " new one opened. The default of 0 means no maximum size.\n"
  86. "\n"
  87. "If none of -c, -f or -y is given, by default, output is sent to stdout. If no\n"
  88. "logger is specified, the default is the program's root logger ('example').\n";
  89. }
  90. // The program sets the attributes on the root logger and logs a set of
  91. // messages. Looking at the output determines whether the program worked.
  92. int main(int argc, char** argv) {
  93. const string ROOT_NAME = "example";
  94. bool sw_found = false; // Set true if switch found
  95. bool c_found = false; // Set true if "-c" found
  96. bool f_found = false; // Set true if "-f" found
  97. bool y_found = false; // Set true if "-y" found
  98. int option; // For getopt() processing
  99. OutputOption def_opt; // Default output option - used
  100. // for initialization
  101. LoggerSpecification cur_spec(ROOT_NAME);// Current specification
  102. OutputOption cur_opt; // Current output option
  103. vector<LoggerSpecification> loggers; // Set of logger specifications
  104. vector<OutputOption> options; // Output options for logger
  105. std::string severity; // Severity set for logger
  106. // Initialize logging system - set the root logger name.
  107. LoggerManager manager;
  108. manager.init(ROOT_NAME);
  109. // In the parsing loop that follows, the construction of the logging
  110. // specification is always "one behind". In other words, the parsing of
  111. // command-line options updates thge current logging specification/output
  112. // options. When the flag indicating a new logger or output specification
  113. // is encountered, the previous one is added to the list.
  114. //
  115. // One complication is that there is deemed to be a default active when
  116. // the parsing starts (console output for the BIND 10 root logger). This
  117. // is included in the logging specifications UNLESS the first switch on
  118. // the command line is a "-l" flag starting a new logger. To track this,
  119. // the "sw_found" flag is set when a switch is completey processed. The
  120. // processing of "-l" will only add information for a previous logger to
  121. // the list if this flag is set.
  122. while ((option = getopt(argc, argv, "hc:d:f:l:m:s:y:z:")) != -1) {
  123. switch (option) {
  124. case 'c': // Console output
  125. // New output spec. If one was currently active, add it to the
  126. // list and reset the current output option to the defaults.
  127. if (c_found || f_found || y_found) {
  128. cur_spec.addOutputOption(cur_opt);
  129. cur_opt = def_opt;
  130. c_found = f_found = y_found = false;
  131. }
  132. // Set the output option for this switch.
  133. c_found = true;
  134. cur_opt.destination = OutputOption::DEST_CONSOLE;
  135. if (strcmp(optarg, "stdout") == 0) {
  136. cur_opt.stream = OutputOption::STR_STDOUT;
  137. } else if (strcmp(optarg, "stderr") == 0) {
  138. cur_opt.stream = OutputOption::STR_STDERR;
  139. } else {
  140. cerr << "Unrecognised console option: " << optarg << "\n";
  141. return (1);
  142. }
  143. break;
  144. case 'd': // Debug level
  145. cur_spec.setDbglevel(boost::lexical_cast<int>(optarg));
  146. break;
  147. case 'f': // File output specification
  148. // New output spec. If one was currently active, add it to the
  149. // list and reset the current output option to the defaults.
  150. if (c_found || f_found || y_found) {
  151. cur_spec.addOutputOption(cur_opt);
  152. cur_opt = def_opt;
  153. c_found = f_found = y_found = false;
  154. }
  155. // Set the output option for this switch.
  156. f_found = true;
  157. cur_opt.destination = OutputOption::DEST_FILE;
  158. cur_opt.filename = optarg;
  159. break;
  160. case 'h': // Help
  161. usage();
  162. return (0);
  163. case 'l': // Logger
  164. // If a current specification is active, add the last output option
  165. // to it, add it to the list and reset. A specification is active
  166. // if at least one switch has been previously found.
  167. if (sw_found) {
  168. cur_spec.addOutputOption(cur_opt);
  169. loggers.push_back(cur_spec);
  170. cur_spec.reset();
  171. }
  172. // Set the logger name
  173. cur_spec.setName(std::string(optarg));
  174. // Reset the output option to the default.
  175. cur_opt = def_opt;
  176. // Indicate nothing is found to prevent the console option (the
  177. // default output option) being added to the output list if an
  178. // output option is found.
  179. c_found = f_found = y_found = false;
  180. break;
  181. case 'm': // Maximum file version
  182. if (!f_found) {
  183. std::cerr << "Attempt to set maximum version (-m) "
  184. "outside of file output specification\n";
  185. return (1);
  186. }
  187. try {
  188. cur_opt.maxsize = boost::lexical_cast<unsigned int>(optarg);
  189. } catch (boost::bad_lexical_cast&) {
  190. std::cerr << "Maximum version (-m) argument must be a positive "
  191. "integer\n";
  192. return (1);
  193. }
  194. break;
  195. case 's': // Severity
  196. severity = optarg;
  197. isc::util::str::uppercase(severity);
  198. cur_spec.setSeverity(getSeverity(severity));
  199. break;
  200. case 'y': // Syslog output
  201. // New output spec. If one was currently active, add it to the
  202. // list and reset the current output option to the defaults.
  203. if (c_found || f_found || y_found) {
  204. cur_spec.addOutputOption(cur_opt);
  205. cur_opt = def_opt;
  206. c_found = f_found = y_found = false;
  207. }
  208. y_found = true;
  209. cur_opt.destination = OutputOption::DEST_SYSLOG;
  210. cur_opt.facility = optarg;
  211. break;
  212. case 'z': // Maximum size
  213. if (! f_found) {
  214. std::cerr << "Attempt to set file size (-z) "
  215. "outside of file output specification\n";
  216. return (1);
  217. }
  218. try {
  219. cur_opt.maxsize = boost::lexical_cast<size_t>(optarg);
  220. } catch (boost::bad_lexical_cast&) {
  221. std::cerr << "File size (-z) argument must be a positive "
  222. "integer\n";
  223. return (1);
  224. }
  225. break;
  226. default:
  227. std::cerr << "Unrecognised option: " <<
  228. static_cast<char>(option) << "\n";
  229. return (1);
  230. }
  231. // Have found at least one command-line switch, so note the fact.
  232. sw_found = true;
  233. }
  234. // Add the current (unfinished specification) to the list.
  235. cur_spec.addOutputOption(cur_opt);
  236. loggers.push_back(cur_spec);
  237. // Set the logging options.
  238. manager.process(loggers.begin(), loggers.end());
  239. // Set the local file
  240. if (optind < argc) {
  241. LoggerManager::readLocalMessageFile(argv[optind]);
  242. }
  243. // Log a few messages to different loggers.
  244. isc::log::Logger logger_ex(ROOT_NAME);
  245. isc::log::Logger logger_alpha("alpha");
  246. isc::log::Logger logger_beta("beta");
  247. LOG_FATAL(logger_ex, MSG_WRITERR).arg("test1").arg("42");
  248. LOG_ERROR(logger_ex, MSG_RDLOCMES).arg("dummy/file");
  249. LOG_WARN(logger_ex, MSG_BADSTREAM).arg("example");
  250. LOG_WARN(logger_alpha, MSG_READERR).arg("a.txt").arg("dummy reason");
  251. LOG_INFO(logger_alpha, MSG_OPENIN).arg("example.msg").arg("dummy reason");
  252. LOG_DEBUG(logger_ex, 0, MSG_RDLOCMES).arg("example/0");
  253. LOG_DEBUG(logger_ex, 24, MSG_RDLOCMES).arg("example/24");
  254. LOG_DEBUG(logger_ex, 25, MSG_RDLOCMES).arg("example/25");
  255. LOG_DEBUG(logger_ex, 26, MSG_RDLOCMES).arg("example/26");
  256. LOG_FATAL(logger_beta, MSG_BADSEVERITY).arg("beta_fatal");
  257. LOG_ERROR(logger_beta, MSG_BADDESTINATION).arg("beta_error");
  258. LOG_WARN(logger_beta, MSG_BADSTREAM).arg("beta_warn");
  259. LOG_INFO(logger_beta, MSG_READERR).arg("beta").arg("info");
  260. LOG_DEBUG(logger_beta, 25, MSG_BADSEVERITY).arg("beta/25");
  261. LOG_DEBUG(logger_beta, 26, MSG_BADSEVERITY).arg("beta/26");
  262. return (0);
  263. }