123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- 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.
|