Log4j mapping all loggers to a single logger - log4j

Our middleware team assignes logger names to each application and that is how they know where to direct our socket appenders to.
I would like to use the standard Logger.getLogger(Clazz.class) paradigm but that does not work with the above constraint. Also we can't log library statements out to our socket appender which would come in handy a lot.
Is there a fairly painless way to map everything from all loggers to this middleware assigned logger?
I think our middleware group messed up in how the configured the enterprise logging system. It looks like there is a setApplication property on the SocketAppender that should be used instead. Regardless, this is what we have to deal with...

You'd like to redirect your "regular" loggers' output to the "middleware logger" directly, i.e. without setting the middleware logger's appender on all the "regular" loggers, right?
If this is the case, try writing your own appender:
class MiddlewareRedirectingAppender extends AppenderSkeleton {
private Logger middlewareLogger = Logger.getLogger("your 'middleware' logger name");
public void doAppend(LoggingEvent event) {
// implement whatever filtering, etc. you want
middlewareLogger.log(...);
}
}
Attach this appender to your "regular" loggers, or just to the root logger (depending on how your "middleware" logger behaves).
Disclaimer: this is just a loose idea, I haven't tested it.

Related

Can I check this in ArchUnit

I have a a proverbial Log4J logger.
Logger logger = new Logger(MyClass.class);
Can I check that the correct filed is pass to the Logger?
Not with Log4j 1 by itself. With Log4j 2 you could just do:
Logger logger = new LogManager.getLogger();
Or you could use Lombok and just use #Log4j (or #Log4j2) at the beginning of your class.
You can't: ArchUnit does not analzye method call parameter values, see also #596.

How to abbreviete logger name?

Is there a way to abbreviate logger name in target's layout? I want to shorten long logger names, eg. instead of com.logback.Foobar I would like to have c.l.Fobar.
This is very often in Java world. For example logback has such abbreviator.
This is not built in NLog, however you could easily add it.
For example:
//Register ${abbr-loggername}
LayoutRenderer.Register("abbr-loggername", (logEvent) => todo.Abbr(logEvent.LoggerName));
See https://github.com/nlog/nlog/wiki/How-to-write-a-custom-layout-renderer
You need for this the LoggerName property in the LogEventInfo object (see API docs)

switching FileAppenders on the fly

I've got a legacy logging class. Its got a static Logger reference (named logger) and a bunch of static methods.
Each method takes a String input and writes it to System.out.println and to logger if logger is not null.
Its got a constructor that initializes logger. But this constructor only has package scope and I'm pretty sure its not being called anywhere. Therefore logger is always null and the class essentially only ever executes System.out.println
I want to change this so it can be used in a multi threaded application where each thread writes to its own unique FileAppender.
And that's where I'm stuck.
Basically, what I want to do is have this static class associated with a bunch of different log4j FileAppenders. Each FileAppender can be created by the Thread, and the file name can be derived from unique information known to the Thread.
What I can't figure out how to do is magically use Log4j to communicate that Thread's unique FileAppender to this legacy logging class.
Ideas? Hints? Suggestions?
Mark
It is possible to change the target log file name dynamically using a RoutingAppender and the ThreadContext map.
This can all be done with configuration (no need for custom code where threads create FileAppenders). In the RoutingAppender configuration you can specify a ThreadContext key you want to use to switch the target FileAppender. For example, you can use the string "ROUTINGKEY". Each thread puts a unique value in the ThreadContext map for key "ROUTINGKEY", and this value is used to select the Appender that the log event is routed to. You can even set it up to dynamically create log files that have the ROUTINGKEY value in the file name, so not all target log files need to be known in advance.
The FAQ page has a good example: http://logging.apache.org/log4j/2.x/faq.html#separate_log_files

How to configure log4j for package level logging?

I want to log in to multiple log files(flume and console). How to set log4j as package level?ie com.mypackage.myclass into flume and other packages into console..
First of all you need to configure log4j to have two named loggers, one that sends to the Console appender, and one that sends to Flume. You can then write use a proxy class for making your logging calls that routes the log4j calls to the different loggers depending on the package the caller is in. You can do this by accessing the stack of the current thread, like so:
public class Logger
{
public static org.apache.log4j.Logger getLogger()
{
// this will get the calling frame, 0=Thread, 1=this, 2=caller
StackTraceElement stackElement = Thread.currentThread().getStackTrace()[2];
if(stackElement.getClassName().startsWith("the.package.that.goes.to.flume"))
{
return org.apache.log4j.Logger.getLogger("Flume");
}
else
{
return org.apache.log4j.Logger.getLogger("Console");
}
}
}
}
The code above is assuming you have named your two loggers 'Flume' and 'Console'.
When ever you make a logging call in your app, use Logger.getLogger() rather than going to log4j directly.
Check this blog post
http://veerasundar.com/blog/2009/07/log4j-tutorial-adding-log4j-logging-to-your-project/
It has a complete PDF for download on how to add log4j to project.
You need to define categories for different packages.Everything is explained in above PDF.
Hope it helps.

Proper way to declare log4j

I'd like to receive a clarification on the following:
Every class that has something to say in my program , creates its own logger like this
public final static Logger logger = Logger.getLogger(ClassName.class);
I was thinking ....
Why is it public? Why is it customary to make it public?
- Logger is never reused from outside the class it was created
Can there be a generic logger used throughout the program instead of having each class maintain its own?
- Seems like ClassName is used as part of logging only to indicate WHAT class said what. Perhaps it is possible to pass a reference to the class name to the logger instead.
Please help me clarify
The only reason to make it public is if you want it to be reused outside of the class.
You can have a single logger instance per you application, but you lose granularity of the messages available for configuring package or class level logging facilities.

Resources