Close log files - java

This project has been handed down to me, so I do not know much about it. There is a method where log (java.util.logging.Logger) is used and it creates two log files:
First file: fileName.log
Second file: fileName.log.lck
In Linux when I do lsof, I see these two files as open. How do I close these two files?
The reason why I want to close these files is this method is run multiple times a day and after couple of weeks the number of open files reaches a limit (around 1000), at which point our system stops working. When we restart our process ("Job Controller" which does the logging) the number of log files open goes to 0 and it works again.
This is what's been done to do logging
private static Logger log = Logger.getLogger(MyClass.class.getPackage().getName());
try{
log.logp(Level.SEVERE, "com.MyClass", "run", "It failed");
}
This is what I tried to do to close the files in the finally block but it didn't work
finally{
Handler[] handler = log.getHandlers();
for(Handler h: handler){
h.close();
}
}

I simply use:
LogManager.getLogManager().reset();
this will cancel all your log settings (log file path, file name pattern, formatter...) but it will stop using the logger close the lock file and release logger to

First solution
If you do not want to modify your code use: How to send java.util.logging to log4j?
java.util.logging.Logger to Logback using SLF4J?
I use log4j or logback. Both have Rolling File Appender (old files are removed) or Date/Time File appender.
Second solution
For logging the best usage is rolling file.
String filePattern = " fileName%.log";
int limit = 1000 * 1000; // 1 Mb
int numLogFiles = 3;
FileHandler fh = new FileHandler(filePattern, limit, numLogFiles);
// Add to logger
Logger logger = Logger.getLogger(MyClass.class.getPackage().getName());
logger.addHandler(fh);
I do not know if you can add globally file handler.

Related

FileHandler generate extra logs files when original log is locked

I need generate one log file by each application installed and running on websphere application server 9.
I use JUL for generate log's file. My solution was create a especific Class thas inherits from FileHandler and set logs properties by a config file.
This is my code:
//Read config file
LogManager.getLogManager().readConfiguration(LoggerJUL.class.getResourceAsStream("/Logger.properties"));
//Add handler to logger
Logger.getLogger(clazz)).addHandler(new PersonalFileHandler());
PersonalFileHandler extends FileHandler, and properties are set by configure method on FileHandler class on runtime.
In this way i achieve make one log file by application running over Websphere, without overwriting the destination of the server log.
Although I achieve part of the objective, extra files are generated if the original log file is locked, same like this: testLogs.log.0, testLogs.log.1, testLogs.log.0.1, etc.
I read many suggestions and solutions, but i can't stop this isue.
Any suggestions ?
handlers = com.mucam.xxxx.PersonalFileHandler
# Set the default formatter to be the simple formatter
com.mucam.xxxx.PersonalFileHandler.formatter = java.util.logging.SimpleFormatter
# Write the log files to some file pattern
com.mucam.xxxx.PersonalFileHandler.pattern = C:/Users/pmendez/Documents/Log/testLogs.log
# Limit log file size to 5 Kb
com.mucam.xxxx.PersonalFileHandler.limit = 5000
# Keep 10 log files
com.mucam.xxxx.PersonalFileHandler.count = 10
#Customize the SimpleFormatter output format
java.util.logging.SimpleFormatter.format = %d{ISO8601} [%t] %-5p %c %x - %m%n
#Append to existing file
com.mucam.xxxx.PersonalFileHandler.append = true
Although I achieve part of the objective, extra files are generated if the original log file is locked, same like this: testLogs.log.0, testLogs.log.1, testLogs.log.0.1, etc. I read many suggestions and solutions, but i can't stop this isue. Any suggestions ?
Since your count is set to 10 you need to specify the %g pattern to log the generation.
com.mucam.xxxx.PersonalFileHandler.pattern = C:/Users/pmendez/Documents/Log/testLogs%g.log
The pattern is absolute path so if you create multiple filehandlers it will resolve conflicts by appending unique number to the end. This is specified by the %u pattern. So if you want to move where the integer is placed in the file name you specify the %u token in the pattern.
This also means that you are creating multiple instances of your custom file handler and they are not being closed. If you want to control the number of files you either need to control the number of PersonalFileHandler you create and or share a reference to singleton PersonalFileHandler. Otherwise you need to make sure that if you explicitly create a PersonalFileHandler that you are explicit closing that PersonalFileHandler before you create a second new PersonalFileHandler.
Loggers are subject to garbage collection. The line:
Logger.getLogger(clazz).addHandler(new PersonalFileHandler());
Is subject to garbage collection unless the code elsewhere as already pinned that logger in memory. This can cause log files to be created, locked, and empty.

Log4j properties | Create new log file with timestamp for every run [duplicate]

This question already has answers here:
One logfile per run with log4j
(4 answers)
Closed 5 years ago.
I'm quite new to log4j and have managed to create the logs for my code.
But what I need is, a new file to be created for each run, rather than appending the logs to the same file.
Below are the properties I'm setting (found somewhere on google).
Please suggest changes, so that new file will be created with the timestamp after each run.
// Here we have defined root logger
log4j.rootLogger=INFO,R,HTML
// Here we define the appender
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.HTML=org.apache.log4j.FileAppender
// Here we define log file location
log4j.appender.R.File=./Logs/LastRunLog.log
log4j.appender.HTML.File=./Logs/LastRunLog.html
// Here we define the layout and pattern
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d - %c -%p - %m%n
log4j.appender.HTML.layout=org.apache.log4j.HTMLLayout
log4j.appender.HTML.layout.Title=Application log
log4j.appender.HTML.layout.LocationInfo=true
You can use a system property to set the log4j file names with it's value and give that property an unique value for each run.
Something like this on your starter class (timeInMillis and a random to avoid name clashes):
static {
long millis = System.currentTimeMillis();
System.setProperty("log4jFileName", millis+"-"+Math.round(Math.random()*1000));
}
And then you refer to the system property on log4j conf properties:
log4j.appender.R.File=./Logs/${log4jFileName}.log
log4j.appender.HTML.File=./Logs/${log4jFileName}.log
Hope it helps!
You need to write (or find) a custom appender which will create the file with a timestamp in the name.
The 3 defaults implementation for file logging in log4j are :
FileAppender : One file logging, without size limit.
RollingFileAppender : Multiple files and rolling file when current file hits the size limit
DailyRollingFileAppender : A file per day
The simpliest way is to extend FileAppender and overwrite the setFile and getFile methods.
i think this answer would be helpful for you click here
i have ran code as the page said, and i got a new log file each time i start my application.
result like that :
and all code in my Test.java is :`
private static final Logger log = Logger.getLogger(Test.class);
public static void main(String[] args) {
log.info("Hello World");
}
`

Java Logger not rotating log files

I'm using Tomcat 8.0.21 on RHEL 7. In my Java code I'm logging to a text file with java.util.logging.Logger.
There is always only one log file. If I restart Tomcat the logging starts again from that moment and all previous logs are gone.
I added %g to file name as instructed here but it only adds 0 to file name and no rotation occurs.
Here is my code to create the FileHandler. strFilePath value is for example "/tmp/mylog.log". LogFormatter is my own class.
// Need to set format with own formatter class to get plain text to one line (default format is XML).
FileHandler file_handler = new FileHandler(strFilePath);
file_handler.setFormatter(new LogFormatter());
logger.addHandler(file_handler);
On my Windows 7 laptop logs rotate fine using the same code and Tomcat version.
How can I enable Java Logger log file rotation on my RHEL server?
Edit: I guess I could just add timestamp to file name when constructing FileHandler. I'm going to try that.
The FileHandler only rotates when the limit is exceeded (or unable to lock the file). If you want to rotate files by time then you have to code for that. If you want to just trigger a rotation then just create a throw away file handler with a limit of zero bytes before you open your actual file handler.
new FileHandler(pattern, 0, 1, false).close();
This is not a perfect solution but I think I won't lose old logs when I construct the FileHandler this way:
FileHandler file_handler = new FileHandler(strFilePath.replace("<timestamp>", new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss").format(new Date())));
I have "<timestamp>" string in the file name and that gets replaced here. I think a new log file is only created when I restart Tomcat so the log files might get big. But this is the best I've come up so far.

One Log file for a Java project

I wanted to keep track of a Java project main activity logs for debugging in one log file. I used the following approach to open the existed file, and append the new content, but it seems to add another file adding 1,2,3 in front of the name every time I run my program. Although the logfile.log keeps updated, and stored the desired content. But, I couldn't figure out why the other logfile.log.2, logfile.log.3 ... files created
LoggerFile lf = new LoggerFile();
final FileHandler fh = new FileHandler(System.getProperty("user.dir")+"/logfile.log", 1024 * 1024, 1, true);
Logger logger = lf.initialize(fh);
logger.info("log file message ... ");
fh.close();
Here is how the LoggerFile looks like:
public class LoggerFile {
public LoggerFile() {
}
public Logger initialize(FileHandler fh) throws SecurityException, IOException{
Logger logger = Logger.getLogger("MyLog");//Logger.getLogger(UpdateExposureScores.class.getName());
logger.addHandler(fh);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
return logger;
}
}
What seems to be wrong in the above code that it writes the log in several files? Thanks in advance.
I assume you are using java.util.logging. From the j.u.l.FileHandler documentation:
Normally the "%u" unique field is set to 0. However, if the FileHandler tries to open the filename and finds the file is currently in use by another process it will increment the unique number field and try again. This will be repeated until FileHandler finds a file name that is not currently in use. If there is a conflict and no "%u" field has been specified, it will be added at the end of the filename after a dot. (This will be after any automatically added generation number.)
Opening multiple file handlers within the same process also has the same effect. Add lines to log the result of java.lang.management.ManagementFactory.getRuntimeMXBean().getName() and java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime() so you can identify the JVMs that are creating the log files. You are either creating too many filehandlers pointing to the same location or you are starting multiple instances of your app.
You might want to look at the LogManager documentation which will explain alternate ways to configure your log settings.

Renaming a Log4J log file during the program run

We're recently switched over to Log4J from JUL (java.util.Logging) because I wanted to add additional log files for different logging levels.
We have the option in the program to optionally append a value and a date/time stamp to the log file name at the (for all intents and purposes) end of the program's execution.
Because JUL seemed to open and close the file as needed to write to the file, it wasn't locked and we could simply use .renameTo() to change the filename.
Now, using Log4J, that file is left open and is locked, preventing us from renaming the file(s).
I can't decide the name of the file before I configure the logging because the property file containing the options for renaming is some time after the logging is needed (this is why we renamed it at the end of the program).
Do you have any suggestions as to how this can be achieved?
Would Logback and/or SLF4J help or hinder this?
I have sort of worked around the issue by using a system parameter in the log4j properties file, setting the property and then reloading the property file.
This allows me to change the name of the log file to something else at the end of the run, and then rename the old files.
It's inelegant, and very much of a kludge, so I would like to avoid this as it also leaves these temporary files around after the run.
One surefire approach would be to implement your own log4j Appender, perhaps based on the FileAppender ( http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/FileAppender.html ). Add your own specialized API to request the file be renamed.
I haven't tried this yet, but the tact I would take would be to use the underlying API setFile(...): http://www.jdocs.com/log4j/1.2.13/org/apache/log4j/FileAppender.html#M-setFile%28String,boolean,boolean,int%29
For example:
public class RenamingFileAppender extends FileAppender {
...
/** fix concurrency issue in stock implementation **/
public synchronized void setFile(String file) {
super.setFile(file);
}
public synchronized void renameFile(String newName) {
// whole method is synchronized to avoid losing log messages
// implementation can be smarter in having a short term queue
// for any messages that arrive while file is being renamed
File currentFile = new File(this.fileName);
File newFile = new File(newName);
// do checks to ensure current file exists, can be renamed etc.
...
// create a temp file to use while current log gets renamed
File tempFile = File.createTempFile("renaming-appender", ".log");
tempFile.deleteOnExit();
// tell underlying impl to use temporary file, so current file is flushed and closed
super.setFile(tempFile.getAbsolutePath(), false, this.bufferedIO, this.bufferSize);
// rename the recently closed file
currentFile.renameTo(newFile);
// now go back to the original log contents under the new name. Note append=true
super.setFile(newFile.getAbsolutePath(), true, this.bufferedIO, this.bufferSize);
}
Consider using a shutdown hooks, and renaming the file there...
http://onjava.com/pub/a/onjava/2003/03/26/shutdownhook.html
http://www.developerfeed.com/threads/tutorial/understanding-java-shutdown-hook
http://download.oracle.com/javase/1.4.2/docs/guide/lang/hook-design.html

Categories