How to get logs from current thread only in log4j - java

I want to intercept logs from the specific thread in my application for the certain period of time. I'm using log4j.
The code below does that, but I'm getting logs from others threads too.
WriterAppender appender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"), consoleWriter);
appender.setName("STR_APPENDER");
appender.setThreshold(org.apache.log4j.Level.INFO);
Logger.getRootLogger().addAppender(appender);
//Some Logic here (I'm using other classes and jars here and I want to get this logs as well)
Logger.getRootLogger().removeAppender("STR_APPENDER");
I'm aware that Logger.getRootLogger() is not a good solution here, but I don't have any other idea.

You can use MDC.put.
eg
MDC.put("threadName",Thread.currentThread().getName());
Using that you can put thread name.
Using Log4j appender you can print the thread name [%X{threadName} in logs

Related

Logging with specific label in log file for every user

I have web application in Java (JSP + Servlets) and logging with log4j 1.2.17.
When user login on site he take ID. I wanna see all his actions in log file with ID prefix like this:
01.05.2015 11:12:30 INFO [Roy] - login correct
But i don't want to pass ID in every calling method to logging events in that method.
I want to save ID somewhere and take it when need.
What you probably want is a Mapped Diagnostic Context. This effectively gives you a stack of ThreadLocal to put data elements into that you can log later.
In java...
MDC.put('LOGIN_ID', 'Roy');
In your log pattern:
"%d %p [%X{LOGIN_ID}] %m

How can I use log level FINE without summoning an infinite stream of platform debug logging?

I'd like to use java util logging in my applet, at log level FINE and below.
I've put a logging.properties file in my applet's jar which says
handlers= java.util.logging.ConsoleHandler
.level= FINE
java.util.logging.ConsoleHandler.level = FINE
and in my applet class, I feed it to the log manager using
logManager.readConfiguration(getClass().getResourceAsStream("logging.properties"));
This successfully causes my debug logging to appear in the applet's console window, however as I should've expected, the java platform also begins to log its FINE level messages to the console.
Worse, the act of logging a message to the Java console, of itself, causes more AWT logging(!) This generates an infinite loop of messages in my console along the lines of
20:31:55 java.awt.mixing.Component FINE: this = javax.swing.JTextArea[...]
20:31:55 java.awt.mixing.Container FINE: this = javax.swing.JViewport[...]
I thought this should be easy to fix by adding
java.level=INFO
javax.level=INFO
sun.level=INFO
to my logging.properties file.
However, this does not work. The platform logging keeps spewing out, no matter what I write in the properties file.
I've dived into the source code. The LogManager appears to be keeping two different LoggingContexts. One for the user, one system context. My logging.properties file only affects the Loggers in the user LoggingContext, and therefore cannot influence the platform logging's settings.
The LogManager does share the rootLogger between the user LoggingContext and the system LoggingContext. And when I set its level to FINE, I get the infinite stream of awt blurb as a side effect.
So my question is: How can I get my user context's Loggers to log at level FINE by default but keep the system loggers at INFO level?
I had tried to do the same thing, but in a web start application. I needed to have java.util.logging set to FINEST in order to find some problems in the application. It didn't matter what I did, the Swing logging just kept on spewing.
Your question, and investigation that you had done helped me solving the problem, albeit in a very ugly way, but I only needed it temporarily. I grabbed the system loggers using reflection:
public static void tryToChangeSystemLogContextLoggers() {
try {
Field systemContextField = LogManager.class.getDeclaredField("systemContext");
systemContextField.setAccessible(true);
Object systemContext = systemContextField.get(LogManager.getLogManager());
Method demandLoggerMethod = systemContext.getClass().getDeclaredMethod("demandLogger", String.class, String.class);
demandLoggerMethod.setAccessible(true);
java.util.logging.Logger logger = (java.util.logging.Logger)demandLoggerMethod.invoke(systemContext, "java.awt", null);
logger.setLevel(java.util.logging.Level.WARNING);
logger.setUseParentHandlers(false);
logger = (java.util.logging.Logger)demandLoggerMethod.invoke(systemContext, "sun.awt", null);
logger.setLevel(java.util.logging.Level.WARNING);
logger.setUseParentHandlers(false);
logger = (java.util.logging.Logger)demandLoggerMethod.invoke(systemContext, "javax.swing", null);
logger.setLevel(java.util.logging.Level.WARNING);
logger.setUseParentHandlers(false);
} catch (Exception e) {
//Well, I tried
}
}
The code is fragile, and might not work in all java version.

My own Logging Handler for GAE/J (using appengine.api.log?)

I need to write my own logging handler on GAE/J. I have Android code that I'm trying to adapt such that it can be shared between GAE/J and Android. The GAE code I'm trying to write would allow the log statements in my existing code to work on GAE.
The docs say that I can just print to system.out and system.err, and it works, but badly. My logging shows up in the log viewer with too much extraneous text:
2013-03-08 19:37:11.355 [s~satethbreft22/1.365820955097965155].: [my_log_msg]
So, I started looking at the GAE log API. This looked hopeful initially: I can construct an AppLogLine and set the log records for a RequestLogs object.
However, there is no way to get the RequestLogs instance for the current request - the docs say so explicitly here:
Note: Currently, App Engine doesn't support the use of the request ID to directly look up the related logs.
I guess I could invent a new requestID and add log lines to that, but it is starting to look like this is just not meant to be?
Has anyone used this API to create their own log records, or otherwise managed to do their own logging to the log console.
Also, where can I find the source for GAE's java.util.logging? Is this public? I would like to see how that works if I can.
If what I'm trying to do is impossible then I will need to consider other options, e.g. writing my log output to a FusionTable.
I ended up just layering my logging code on top of GAE's java.util.logging. This feels non-optimal since it increases the complexity and overhead of my logging, but I guess this is what any 3rd logging framework for GAE must do (unless it is OK with the extra cruft that gets added when you just print to stdout).
Here is the crux of my code:
public int println(int priority, String msg) {
Throwable t = new Throwable();
StackTraceElement[] stackTrace = t.getStackTrace();
// Optional: translate from Android log levels to GAE log levels.
final Level[] levels = { Level.FINEST, Level.FINER, Level.FINE, Level.CONFIG,Level.INFO, Level.WARNING, Level.SEVERE, Level.SEVERE };
Level level = levels[priority];
LogRecord lr = new LogRecord(level, msg);
if (stackTrace.length > 2) { // should always be true
lr.setSourceClassName(stackTrace[2].getClassName());
lr.setSourceMethodName(stackTrace[2].getMethodName());
}
log.log(lr);
return 0;
}
Note that I use a stack depth of 2, but that # will depend on the 'depth' of your logging code.
I hope that Google will eventually support getting the current com.google.appengine.api.log.RequestLogs instance and inserting our own AppLogLine instances into it. (The API's are actually there to do that, but they explicitly don't support it, as above.)

Log4j not printing name before message

I have a log4j logger that I instantiate like this:
logger = Logger.getLogger("EQUIP(" + id + ")");
Doing so, when I call logger.info("message"), I should get an output like this (with some date formatting):
13/11/12 15:08:27 INFO: EQUIP(1): message
But I'm only getting:
13/11/12 15:08:27 INFO: message
I'm also printing logger.getName() to the console for debugging and it gives me back the correct "EQUIP(1)" name. This behaviour is happening in some cases in my program, where I have several loggers like this, but mostly in this specific class. I want to know if I'm doing something wrong, if this name should be only the class/package name, or if it can be anything (it works well in 80+% of my loggers). I need to print the ID of each equipment because I have several of them working simultaneous, and tracking them without this would be next to impossible.
How should I fix this, preferably without resourcing to changing all my log calls to include this prefix?
The output format depends on the pattern you've configured for the appender. If the pattern string includes %c then you'll get the logger name included, if it doesn't then you won't.
An alternative approach might be to use the mapped diagnostic context, which is designed to disambiguate between log output from different threads writing to the same logger.

How to rotate log files based on time rather than size in Log4j?

I use Log4j with the RollingFileAppender to create a log rotation based on size.
How can I configure it to log to each file for a certain amount of time before rotating?
For example, so that each log file contains one hour of logs, rotating at the top of each hour?
I configure Log4j programatically in Java using a Properties object (as opposed to a log4j.properties file)
You probably want to use a DailyRollingFileAppender. To roll them hourly, for example, you'd use a DatePattern of '.'yyyy-MM-dd-HH. For a log4j.properties file:
log4j.appender.myAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.myAppender.DatePattern='.'yyyy-MM-dd-HH
...
Or for your programmatic configuration:
DailyRollingFileAppender appender = new DailyRollingFileAppender();
appender.setDatePattern("'.'yyyy-MM-dd-HH");
Logger root = Logger.getRootLogger();
root.addAppender(appender);
Unfortunately, using a DailyRollingFileAppender means that you can't limit the file size - this could be problematic if you have tons of logs in the given rolled period.
Additionally,
log4j.appender.myAppender=org.apache.log4j.DailyRollingFileAppender
**log4j.appender.myAppender.DatePattern='.'yyyy-MM-dd-HH**
The following list shows all the date patterns which have defined by log4j,
Minutely '.'yyyy-MM-dd-HH-mm application.log.2013-02-28-13-54
Hourly '.'yyyy-MM-dd-HH application.log.2013-02-28-13
Half-daily '.'yyyy-MM-dd-a application.log.2013-02-28-AM app.log.2013-02-28-PM
Daily '.'yyyy-MM-dd application.log.2013-02-28
Weekly '.'yyyy-ww application.log.2013-07 app.log.2013-08
Monthly '.'yyyy-MM application.log.2013-01 app.log.2013-02
The other thing to be careful of with any rolling file appender is to make sure only one JVM access a particular log file at a time. This is because log4j caches the log file size for performance reasons, and your 'rolling' will get wonky if multiple JVMs access the same files.
Use a DailyRollingFileAppender.
In particular, setting its 'datePattern' property to '.'yyyy-MM-dd-HH would cause file to rotate every hour.
You need to use the DailyRollingFileAppender. Despite its misleading name it can be configured in a to run at configurable time periods up to minutes.

Categories

Resources