Overview
At the moment there is a community requirement to prefix all the log messages with additional information like timestamp, line number, severity level, etc.
Here's an example
2019-03-19 11:23:57.776 <ZWEAGW1:threadInformation> userID INFO (locationInformation) ZWEA001I Message text
The existing logging facility has the ability to use a custom formatter but the caller cannot pass the context information to it (e.g. the line number). The purpose of this ticket is to discuss how we could re-factor/extend the code in logging.c
to meet the new requirements while keeping backward compatibility.
Details
The current logging function has the following signature:
void zowelog(LoggingContext *context, uint64 compID, int level, char *formatString, ...);
One possible solution would be making this a macro and changing the original zowelog
to have file name and line number arguments. The issues are: making this a macro may break existing code, the formatter (or log handler) will also have to change.
Possible fix 1
- Define a new function, let's say
zowelog2
void zowelog2(LoggingContext *context, uint64 compID, int level, void *userData, char *formatString, ...);
- Define a new handler type
typedef void (*LogHandler2)(struct LoggingContext_tag *context,
LoggingComponent *component,
void *componentData, // IF: set in existing logConfigureDestination or logConfigureDestination2
void *userData, // IF: set in the new function logConfigureDestination3
char *formatString,
va_list argList);
LoggingDestination
will need to have a new field - handler2
typedef struct LoggingDestination_tag{
char eyecatcher[8]; /* RSLOGDST */
int id;
int state;
char *name;
void *data; /* used by destination to hold internal state */
LogHandler handler;
DataDumper dumper;
LogHandler2 handler2;
} LoggingDestination;
zowelog2
will have the same implementation as zowelog
except for the handler call
if (destination->handler2) {
destination->handler2(context, component, destination->data, userData, formatString, argPointer);
} else {
destination->handler(context, component, destination->data, formatString, argPointer);
}
- Add a wrapper macro for zowelog2 which will actually pass
__FILE__
and __LINE__
#define zowelogx(context, compID, level, formatString, ...) \
do { \
struct { \
char *fileName; \
int lineNnumber; \
} fileAndLine = {__FILE__, __LINE__}; \
zowelog2(context, compID, &fileAndLine, formatString, ##__VA_ARGS__); \
} while (0)
Drawbacks of fix 1:
zowelogx
will have to do some work before actually testing whether we need to log (hopefully the compiler can optimize the fileAndLine
initialization
- If the code with the old version of the loggin facility calls a shared library that uses the new one, the new code will try to check
handler2
which doesn't exist in the old LoggingDestination
in the caller code. We may possible carve out some bytes out of the LoggingDestination->eyecatcher
field and create a flag or version field which could be tested by the new version.