I have a logger class (in PHP, but that does not matter) which spits out log messages. The logger is a custom implementation and works well. However, I would like to extend it to provide a event ID with each type of logger message. Such that "User logged in messages" are event ID 1, "Form validation failed" is event ID 2, for example.
The purpose of this event ID is to filter unimportant events when a long list of logs is viewed. I believe it would be quicker to categorize logs by event ID and faster to query than doing substring searches in a database.
I have the following ideas, but welcome viable alternatives. I used PHP in this example, but something that is generic enough that it could be applied to most languages such as PHP/Java/C#/etc would be useful.
1) Include an ID implicitly in the log function call:
abstract class EventId {
const LOGIN = 1;
const VALIDATION_FAILURE = 2;
// etc
}
Logger::messageDebug(EventID::LOGIN, $username . " logged in");
Logger::messageWarning(EventID::VALIDATION_FAILURE, "Form failed to validate, etc.");
The advantages of this are simplicity, but I fear it could get a little messy.
2) Pass variable parameters to log messages as separate arguments, then hash the first string
Logger::messageDebug("%s logged in", $username);
Logger::messageWarning("The %s form failed to validate", $form);
The advantages are simplicity, the disadvantages are the event ID depends upon hashing (or some other function) of the first string to differentiate the types of log messages.
3) Backtrace and do some nastyness
function messageDebug($message) {
$trace = obtainTraceOfCallToMessageDebug();
$callToMessageDebug = $trace[0];
$eventId = "";
$eventId .= $eventId->file;
$eventId .= $eventId->line;
$eventId = sha1($eventId);
messageImpl($eventId, $message);
}
This is pretty nasty, but it does have an advantage in that existing log messages do not need to be changed, additionally it is less fragile when writing new log messages. In PHP, obtaining a backtrace is easy and sort of cheap, in other languages you may have to throw an Exception which is super nasty. Anyway, it's an idea.
Looking forward to your opinions. My main requirement is maintainability rather than speed. I am currently looking towards number 1 - keep it simple.
I'd go with the first one with a bit of modification:
Assuming that you called your logger with statements like :
Logger::messageWarning($message)
I'd replace that with
Logger::messageWarning($message, EventId:someconstant)
and defining your EventId class as
abstract class EventId {
const UNSPECIFIED = 1;
const LOGIN = 2;
const VALIDATION_FAILURE = 3;
// etc
}
and you logger function would accept a second parameter, but use a default value of EventId:UNSPECIFIED
for that.
class Logger {
...
function messageWarning($message, $message_type = EventId:UNSPECIFIED) {
...
}
}
This way you don't break existing code, don't do the hack outlined in #3, and can replace your log calls where and when you need by adding the event type.