switching FileAppenders on the fly - log4j

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

Related

ILogger.BeginScope(): persisting scope between calls to other methods

I need to log custom dimensions to Application Insights for which I'm using ILogger.BeginScope(). That works perfectly. That is:
using (logger.BeginScope(new Dictionary<string, object> { "key": "value" }))
{
logger.LogInformation("message");
}
My issue is that I need to call other methods in other classes, and I'm injecting the ILogger into all my classes. So how can I persist the logging scope among all my classes?
I could surely do ILogger.BeginScope() in all my classes, but I would need to pass the custom properties to classes that don't really need that information. Is there a pattern I could use?
If you call BeginScope multiple times in multiple classes within the same execution path, you will get one aggregated scope. There is no need to manually pass the properties. ILogger is injected as a singleton by default (see source code).
See also Since ILogger<T> is a singleton, how different threads can use BeginScope() without affecting others?
A call to BeginScope will put a new item onto that stack, and the adjoining Dispose will pop it off of that stack.
When the logger is invoked via LogInformation or otherwise, the data of the current stack object will be copied to write it to the console or whatever output that logger instance is configured to do.
LoggerExternalScopeProvider.cs#L14

Spring Integration: tail-inbound-channel-adapter: (1)How can I pass dynamic file name and (2)Programmatically trigger the poller

I have a requirement to tail a file so I am using tail-inbound-channel-adapter.
There are couple of challenges.
File name and the file path changes for every batch run. I was looking for some regex support like this attribute (filename-regex) found in inbound-channel-adapter. I only see an attribute called file in tail-inbound-channel-adapter which expects a static file name (as shown below). How do I pass in the dynamic file name to tail-inbound-channel-adapter.
<int-file:tail-inbound-channel-adapter channel="fileChannel" file="xyz" delay="999999999999999" end="false" reopen="true" file-delay="999999999999999" />
The other challange is that I dont want this poller to start polling right away when the application comes up. Instead it should start polling when the file is ready for tailing. How do I control that?
As shown above, I tried assigning some big delay in the config file and then tried to modify the delay value during the runtime. But that did not help.
Any other alternative ways for my requirements. Thanks for your valuable input.
The adapter implements SmartLifecycle.
Set auto-startup="false". Get a reference to the adapter (e.g. #AutoWired or context.getBean("foo", FileTailingMessageProducerSupport.class)), assuming the adapter has id="foo".
To start the adapter use foo.start().
To change the file, foo.stop(); foo.setFile(newFile); foo.start();.

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.

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.

How to log Process id using Log4cxx or log4j

I am using log4cxx my project and i can able to log current thread id using [%t] marker, how to log process id in it or log4j?.
I am using ConversionPattern & xml based configuration file.
Thanks,
Based on the above answers, I'm going to do this in log4j as follows:
import java.lang.management.*;
import org.apache.log4j.MDC;
private String getPID() {
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
return rt.getName();
}
private void configLog4j() {
// call this from somewhere before you start logging
MDC.put("PID", getPID());
}
Then in my log4j.properties:
log4j.appender.FILE.layout.ConversionPattern=%d %X{PID} [%t] %p %c{1} %x - %m%n
This will actually yield a PID that consists of the ID number and the hostname, at least on my implementation of Java, and from what I read that could be implementation specific. You could go further and split out just the PID.
I've grepped through log4j's and log4cxx's documentation and nowhere did I find anything about logging process id.
So, to be short: no, you can't log process id, at least not directly.
Since you're using C++, you can get your program's PID. Here is how to do it in Linux (Ubuntu in this link). Here is how do do it in Windows.
Get that PID at your program start, use an MDC and put your PID in it.
I don't think there's a better way.
Doing this in log4j would be even trickier, since I know of no way for a running program to get it's PID using standard Java classes.
This doesnt exist in any of the log4xxx, but with a litle effort you can make it yourself. Actually it's a very simple task if you don't mind a little coding. This is basically what I did few times - override actual appender, or it's layout, make sure your class sticks the process ID into event properties map. Then use this property by name as if it was an MDC property. Using MDC directly like suggested above is not the best choice because they are thread bound and you will have to make sure every thread puts the PID when it starts. But if you can't or don't want to override the appender or layout, then this would probably be the only option.
The answer by #skiphoppy works very well for Log4j1.x, but I thought it could be updated to show how it works in the new Log4j2.
(NOTE: I tried to submit this as an edit of the posting above as it is only a minor revision of the answer code, but I'm posting it as a separate answer since my revision was rejected.)
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import org.apache.logging.log4j.ThreadContext;
private String getPID() {
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
return rt.getName();
}
private void configLog4j() {
// Here is the Log4j2 way
ThreadContext.put("PID", rtmx.getName());
}
As skiphoppy's answer states, it outputs a little more than just the process ID. For instance, on my machine (Fedora 20):
16237#localhost.localdomain
You can extract just the process id with the following code, placed in your XML configuration file: %replace{%X{PID}}{[A-Za-z#\.]*}{}
Given the output above for the process id:
16237#localhost.localdomain
the regex will produce
16237
There is no feature in Log4J to achieve this, however you could pass the process id in and use that.
This blog post shows one way to go about it: http://blackbeanbag.net/wp/2009/01/14/log-file-management-in-coherence-using-log4j/
Basically, pass in the process id as a system property and then use that in the Log4j pattern.
Apparently, this is due to the JVM not providing an easy method to access the process id. From JDK1.5+, this may work.
(Archived from dead link http://www.theresearchkitchen.com/archives/100 )

Resources