documentation.txt 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. This directory holds the first release of the logging system.
  2. The steps in using the system are:
  3. 1. Create a message file. Ideally it should have a file type of ".msg".
  4. 2. Run it through the message compiler to produce the .h and .cc files.
  5. 3. Include the .h file in your source code to define message symbols. Also
  6. include the file logger.h to create loggers and to log error messages.
  7. The ".cc" file needs to be linked into the program - static initialization
  8. will add the symbols to the global dictionary.
  9. Outstanding
  10. ===========
  11. * Ability to configure system according to configuration database.
  12. * Writing of suitable appenders and formatters.
  13. * Overrididing message at run-time with a localised file.
  14. * Update the build procedure to create .cc and .h files from the .msg file
  15. during the build process. (Requires that the message compiler is built first.)
  16. Message Storage
  17. ===============
  18. Each message is identified by a string identifier, e.g. "INVFILNAM", which is
  19. associated with some text (e.g. "%s is an invalid file name"). These are stored
  20. in a single std::map, in a class called the Dictionary.
  21. The message identifier (along with parameters) is passed through the logging
  22. system to an appender, which uses the identifier to look up the message in
  23. the dictionary. The message is then formatted and written out.
  24. Message Files
  25. =============
  26. 1) File Contents and Format
  27. A message file is a file containing message definitions. Typically there will
  28. be one message file for each component that declares message symbols.
  29. A example file could be:
  30. -- BEGIN --
  31. # Example message file
  32. # $ID:$
  33. $PREFIX TEST_
  34. TEST1 message %s is much too large
  35. + This message is a test for the general message code
  36. UNKNOWN unknown message
  37. + Issued when the message is unknown.
  38. -- END --
  39. Point to note:
  40. * Leading and trailing space are trimmed from the line.
  41. * Blank lines are ignored
  42. * Lines starting with "#" are comments are are ignored.
  43. * Lines starting $ are directives. At present, the only directive recognised
  44. is $PREFIX, which has one argument: the string used to prefix symbols. If
  45. there is no facility directive, there is no prefix to the symbols. (Prefixes
  46. are explained below.)
  47. * Lines starting + indicate an explanation for the preceding message. These
  48. are processed by a separate program and used to generate an error messages
  49. manual. However they are treated like comments here.
  50. * Message lines. These comprise a symbol name and a message, which may
  51. include one or more instances of the "%s" the C-style substitution string.
  52. (The logging system only recognises the "%s" string.)
  53. 2) Message Compiler
  54. The message compiler is a program built in the src/log/compiler directory. It
  55. processes the message file to produce two files:
  56. 1) A C++ header file (called <message-file-name>.h) that holds lines of the
  57. form:
  58. namespace {
  59. isc::log::MessageID PREFIX_IDENTIFIER = "IDENTIFIER";
  60. :
  61. }
  62. The symbols define the keys in the global message dictionary. At present
  63. they are defined as std::strings, but a future implementation could redefine
  64. them as numeric values.
  65. The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
  66. the argument to the directive. So "$PREFIX MSG_" would prefix the identifer
  67. ABC with "MSG_" to give the symbol MSG_ABC. Similarly "$PREFIX E" would
  68. prefix it with "E" to give the symbol EABC.
  69. 2) A C++ source file (called <message-file-name>.cpp) that holds the code to
  70. insert the symbols and messages into the map.
  71. This file declares an array of identifiers/messages in the form:
  72. namespace {
  73. const char* values[] = {
  74. identifier1, text1,
  75. identifier2, text2,
  76. :
  77. NULL
  78. };
  79. }
  80. (A more complex structure to group identifiers and their messages could be
  81. imposed, but as the array is generated by code and will be read by code,
  82. it is not needed.)
  83. It then declares an object that will add information to the global dictionary:
  84. MessageInitializer <message-file-name>_<time>(values);
  85. (Declaring the object as "static" or in the anonymous namespace runs the risk
  86. of it being optimised away when the module is compiled with optimisation. But
  87. giving it a standard name would cause a clash when multiple files are used,
  88. hence an attempt at disambiguation.)
  89. The constructor of the MessageInitializer object retrieves the singleton
  90. global Dictionary object (created using standard methods to avoid the
  91. "static initialization fiasco") and adds each identifier and text to it.
  92. A check is made as each is added; if the identifier already exists, it is
  93. added to "overflow" vector; the vector is printed to the main logging output
  94. when logging is finally enabled (to indicate a programming error).
  95. Using the Logging
  96. =================
  97. To use the current version of the logging:
  98. 1. Build message header file and source file as describe above.
  99. 2. In the code that needs to do logging, declare a logger with a given name,
  100. e.g.
  101. #include <log/logger.h>
  102. :
  103. isc::log::Logger logger("myname"); // "myname" can be anything
  104. 3. Issue logging calls using methods on logger, e.g.
  105. logger.error(DPS_NSTIMEOUT, "isc.org");
  106. (where, in the example above we might have defined the symbol in the message
  107. file with something along the lines of:
  108. $PREFIX DPS_
  109. :
  110. NSTIMEOUT queries to all nameservers for %s have timed out
  111. As noted above, presently the only logging is to the console using the default
  112. log4cxx format (which is somewhat awkward to read).
  113. Notes
  114. =====
  115. The message compiler is written in C++ (instead of Python) because it contains
  116. a component that reads the message file. This component is used in both the
  117. message compiler and the server; in the server it is used when the server
  118. starts up (or when triggered by a command) to read in a message file to
  119. overwrite the internal dictionary. Writing it in C++ means there is only
  120. one piece of code that does this functionality.