Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

different loggers used with libraries

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:

  1. We want to be able to change debug level for only one of the classes at a time (or all of them, using root)
  2. When all kind of foo print to log, we need to see which entity called it, A, B or C.
  3. As there are many foo we want to be able to change the debug level separately for each foo
  4. A foo should be treated as a common library, it can not depend directly on A,B or C.
  5. A,B and C might use the same instance of 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.
  6. A could use B (or C), but we dont have to see it in the log...

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?

like image 986
user1708860 Avatar asked Dec 29 '13 22:12

user1708860


People also ask

What are the types of logger?

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.

What are logging libraries?

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.

What are different logging frameworks?

To make the job of logging easier, Java provides various frameworks − log4J, java. util. logging (JUL), tiny log, logback, etc.

Should libraries have logging?

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.


2 Answers

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.

like image 51
Yongwei Wu Avatar answered Oct 10 '22 00:10

Yongwei Wu


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

like image 1
Mark Leighton Fisher Avatar answered Oct 10 '22 02:10

Mark Leighton Fisher