My problem concerns logging of library classes (classes that are used inside libraries),
We are currently using log4cxx
but the log4j
library implements the same concepts.
Say i have a process that have several entities, A,B and C. Each of them use many different classes and functions, clearly separated in the code.
A,B and C use many library classes, functions, objects, resources and sometimes even globals (legacy code, nothing i can do about it...) - let us call them all foo
Logging A,B and C turned out to be a performance issue, the log gets blasted when we set the log level to debug. After viewing our system we came to these conclusions:
foo
print to log, we need to see which entity called it, A, B or C.foo
we want to be able to change the debug level separately for each foo
foo
should be treated as a common library, it can not depend directly on A,B or C.foo
(for example, the same instance of our resource handling class is used A,B and C), in the log we would like to see which class used foo
.This is what we came up with so far -
A, B and C will have separate loggers. A global variable(kept in a different library with all of our logging helpers and wrappers) will always keep the current log reporting. Every time an entity starts handling it's logic, it sets the global variable to the proper logger. When a foo
wants to report to the log, it reports through the global variable and adding it's name (and context) to the log message.
Problem is, it feels like there must be something that does this already, the solution does not feel clean, holding a global variable like that...
Are we doing something wrong here? Is there a better solution to this?
Logging Handlers or Appender ConsoleHandler: It writes all the formatted log messages to the console. FileHandler: It writes the log message either to a single file or a group of rotating log files in the XML format. SocketHandler: It writes the log message to the remote TCP ports.
A logging library (or logging framework) is code that you embed into your application to create and manage log events. Logging libraries provide APIs for creating, structuring, formatting, and transmitting log events in a consistent way. Like agents, they're used to send events from your application to a destination.
To make the job of logging easier, Java provides various frameworks − log4J, java. util. logging (JUL), tiny log, logback, etc.
Yes, you should log from your library code. It not only helps you develop, but the people who use the library will find it useful. Remember that you can always set the logging levels to only show the log statements you need - and they can do the same.
I do not know of an existing solution. I would probably come up with a logger with an interface like the following (whether it is a standalone implementation or just a wrapper on your existing one):
class Logger {
public:
enum Level {
...
};
static Logger* Instance();
void Log(Level level, const char* module, const char* msg);
void AddModuleFilter(const char* context, const char* module, Level level);
void SetThreadLocalContext(const char* context);
...
};
The main deviation from common log libraries are the context-sensitive module filter. We may have setups like the following to set different levels according to who makes the call (the context):
// foo calls by entity A have the DEBUG log level
Logger::Instance()->AddModuleFilter("A", "foo", Logger::DEBUG);
// foo calls by entity B have the WARNING log level
Logger::Instance()->AddModuleFilter("B", "foo", Logger::WARNING);
Then, the call flow will be like:
// In entity A
Logger::Instance()->SetThreadLocalContext("A");
// Call function foo
Logger::Instance()->Log(log_level, "foo", log_msg);
Not sure whether such an interface meets your purpose. Anyway, I always regard interface first a good approach. Once you have a clear interface, implementing it should be an easy job.
If the separate library is itself a class, you can use a class-level variable in the library to hold the logger instance reference. I don't often program in C++ or Java, but I think a class-level variable is 'static' in C++ and Java.
It is still a global variable underneath, but at least it's class-scoped global variable (like a class variable named debugLog.log
where debugLog
is the class name).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With