How to abbreviete logger name? - nlog

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)

Related

MapUtils with Logger

I am using MapUtils.verbosePrint(System.out, "", map) to dump the contents of a map in Java. They (management) do not like us using System.out.println().
We are using log4j. They made the logger into a variable "l" so we can say something like l.debug("This is going to the logfile in debug mode).
I would like to get the output buffer(s) from l so I could pass it into verbosePrint() instead of System.out. I looked at all the methods and members of the logger and did things like getAppenders() and tried all those elements but I could not find anything that helped.
Has anyone else done this? I know the logger may write to > 1 output.
You can use Log4j IOStreams to create PrintStreams that will send everything to a logger. This is mostly useful to log debug output from legacy APIs like JDBC or Java Mail that do not have a proper logging system. I wouldn't advise it in other cases, since your messages might be merged or split into several log messages.
I would rather use one of these approaches:
simply log the map using Logger#debug(Object). This will lazily create an ObjectMessage (only if debug is enabled), which is usually formatted using the map's toString() method. Some layouts might format it differently (like the JSON Template Layout).
eagerly create a MapMessage or StringMapMessage:
if (l.isDebugEnabled()) {
l.debug(new MapMessage(map));
}
This gives you more formatting options. For example the layout pattern %m{JSON} will format your message as JSON.
if your are set on the format provided by MapUtils#verbosePrint, you can extend ObjectMessage and overwrite its getFormattedMessage() and formatTo() methods.
public String getFormattedMessage() {
final ByteArrayOutputStream os = new ByteArrayOutputStream();
MapUtils.verbosePrint(new PrintStream(os), "", );
return new String(os.toByteArray());
}

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

Avoiding of printing full package name of method in log4j

I have an API that uses log4j for logging. When I have used the API in my project, though log statements related to project printed with ontl method name, but log statements coming from API is printed full package name format.
In log4j.properties file I am using "%c" (lowercase).
How I can force all project log statements get printed only method name.
Lets say;
I have two classes Main.java and AlarmCategoryImpl.java
AlarmCategroryImpl.java is located on API class, Main.java is defined in my project class.
static Logger logger = Logger.getLogger(AlarmCategoryImpl.class);
static Logger logger = Logger.getLogger(Main.class);
and its log4j output.
2012-12-01/18:13:22.220/EET [INFO][Main->main] starting...
2012-12-01/18:13:22.447/EET [INFO][com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl->copyStructureRecursive] Copying AlarmCategoryImpl
%c means "category name", which is synonymous to "logger name". That means that %c will be expanded to the logger's name.
The logger name is not necessarily the fully-qualified class name. The logger name is the string that is passed in to Logger.getLogger(). Therefore, if you have a class named x.y.z.MyClass, and it has this:
private static final Logger logger = Logger.getLogger("hello");
Then log statements will be generated with hello expanded instead of %c.
That means that the classes in your API are using getLogger(), passing the class name as a parameter. That causes %c to be expanded to the fully-qualified class name when the logs print.
I'm guessing that your non-API classes (in other words, your own project's classes) don't pass-in any value to Logger.getLogger(), or perhaps they use the root logger. To be sure, paste here the line of your code that retrieves the Logger instance.
EDIT as per comment:
Well, is it possible that your Main class is inside the default package? (that is, it is not associated with any package)? If yes, then I don't see any problem.
[INFO][Main->main]: INFO is the level, Main is the class, main is the method.
[INFO][com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl->copyStructureRecursive]: INFO is the level, com.monitor.base.alarmmanagement.alarmconfigurationImpl.AlarmCategoryImpl is the class, copyStructureRecursive is the method.

Log4j mapping all loggers to a single logger

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.

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