Log4j not recreate log file after deleting it - java

My app deployed on Tomcat uses log4j to write a log file. If I delete that file, then the app does not recreate it. I also tried to recreate it manually, but it remains always empty. Is there any way to delete the log file (not from the app), create a new one in the same path with the same name, and that it can be written by the application?

Is there any way to delete the log file (not from the app), create a new one in the same path with the same name, and that it can be written by the application?
Nope. You need to get the application itself to restart logging.
The problem is that the log4j appender still has a handle for the deleted file, and will continue to write to it ... unaware that it has been deleted.
A better approach would be to have the application itself take care of "rotating" the logfile. Look at the classes that implement the log4j Appender interface for some ideas.

Related

Server log rotation

I have an application running in Wildfly 8.2.1. In addition to the server.log file in the log directory, my application creates and uses other log files too (also in the log directory). They all end in .log. This is dynamic and programmatic using org.apache.log4j.FileAppender, since the names, contents, and number of files differs from one client to the next.
What I'd like is for Wildfly to automatically rotate these log files too in addition to its own (i.e. server.log). I see in standalone.xml there is a periodic-rotating-file-handler tag with a file subtag that has a path attribute. From reading the Wildfly logging documentation, it seems like I can't use wild cards here? So, path="*.log"? Is this true? If so, how can I achieve the end goal of Wildfly automatically rotating my log files instead of doing it myself?
If you'd like to rotate log files you'd need to use a rotating file handler. The periodic-rotating-file-handler will only rotate it's own file not other files associated with other file handlers.
Since you seem to be creating a log4j file appender have a look at the org.apache.log4j.RollingFileAppender.

Can I update log4j 1.2 xml configuration file programmatically?

I know it is possible to reload log4j's xml configuration while the application is running, but the searching I've done only shows how to do this when the XML config file is edited manually via a text editor.
I want to be able to dynamically change the level of the root logger in my application via a web page and persist that change to the log4j XML configuration, so I won't have to change the log level again if I restart the application. Is it possible to do this, or can the log4j XML file only be updated manually?
I am using log4j 1.2 in my application.
Many thanks in advance!
for any chump who finds themselves stuck dealing with this, it is possible to write out the data as properties using
org.apache.log4j.config.PropertyPrinter;
You can acheive this by PropertyConfigurator configure and watch.
Read the configuration file configFilename if it exists. Moreover, a thread will be created that will periodically check if configFilename has been created or modified. The period is determined by the delay argument. If a change or file creation is detected, then configFilename is read to configure log4j.

Can I close and reopen log files with logback at runtime?

I'm new to logback. I quite fascinated by it but I'm not sure if it suits my use-case.
I would like to have a logger that I can stop and start. While it is stopped I would like to remove the log file from the filesystem. When logging is restarted the file should be re-created.
Is logback capable of this? While the logging is paused, should I avoid calling a Logger in my classes, or can logback handle this?
I use a slf4j.Logger currently. In the manual I saw that Appender objects implement the LifeCycle interface, which implies that they implement start(), stop() and isStarted().
I thought this means they can be stopped so I can move the file, but later on it goes:
If the appender could not be started or if it has been stopped, a
warning message will be issued through logback's internal status
management system. After several attempts, in order to avoid flooding
the internal status system with copies of the same warning message,
the doAppend() method will stop issuing these warnings.
Does it mean that I can stop it, then remove the file, then restart?
I would like to have a logger that I can stop and start. While it is stopped I would like to remove the log file from the filesystem. When logging is restarted the file should be re-created.
I'm not sure how to accomplish this programmatically but you can accomplish this via JMX if you've added jmxConfigurator to the logback.xml config file.
<configuration>
<jmxConfigurator />
...
This exposes the ch.qos.logback.classic.jmx.JMXConfigurator bean which has an operation entitled reloadDefaultConfiguration. When I press that at runtime, the logfiles are reopened. See Jconsole image below. This means that a jmx client (such as the one in my SimpleJMX library for example) would be able to do that from the command line.
If you are trying to it programmatically from inside of the same application then you should be able to get ahold of the mbean and trigger the call yourself. Something like seems to work for me:
ManagementFactory.getPlatformMBeanServer().invoke(new ObjectName(
"ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator"),
"reloadDefaultConfiguration", null, null);
What I would do is rename the logfile(s) to a different name(s) and then issue the reload configuration command. Then the renamed files can be archived or removed after the new files are created.
Hope this helps.

How can I log that a log file is newly created?

I've been given the requirement that the first line of my log files must begin with a specific header. This header should specify that this current file is newly created. Even when log files are automatically rotated.
It seems odd but it is in the specification for the project.
Environment info:
App Server: Glassfish V2
Logging: SL4J
I think you're going to have to subclass the relevant appender and add your own code to do this.
The log file is not written by slf4j. It is written by the logging system behind the facade. The solution will depend on what that logging system is.
Unless that logging system has an existing log file appender that does this, you will need to write a custom appender (using the appropriate API, etc) that writes the header each time it opens a new log file.

Logging Java web applications?

I am planning to implement logging into a web application that I am currently working on but I am struggling with some of the details. What is the best way to go about logging a Java web application?
Specifically;
Where does the configuration file go in .war package file?
Where do people log to, relative or absolute path flat file, or a database?
Does Log4J logging go directly into the application server log file automatically or is that something you have to set up? In this case I am using Tomcat, but I often use Jrun.
Any other gotchas I should be aware of for web application logging?
Currently I am using Log4J but I imagine that the best practices would apply universally to all logging implementations.
EDIT:
One addition to the questions up top.
Where do you initilize the log
configuration?
In a traditional app, I do this at the entry point;
DOMConfigurator.configureAndWatch("log4j.xml");
What would the web application equivalent be?
I would recommend you to use SLF4J. This is simple logging facade which supports most of popular logging systems (Log4j, commons-logging, Java Logging API and Logback).
Using it, you will able to replace your underline logging system to any other, by simple CLASSPATH update.
The other benefit of SLF4J are parameterized calls, which reduces ugly logging code.
Actually, they recommends to use SLF4J with Logback.
Logback is a successor of Log4J. And it was designed by the same author.
Where does the configuration file go in .war package file?
Root of the classpath.
Where do people log to, relative or absolute path flat file, or a database?
Depends on the need. It's always better to use relative paths. Databases are good if you implement another application which will fetch logs from it and send them using email/sms
Does Log4J logging go directly into the application server log file automatically or is that something you have to set up? In this case I am using Tomcat, but I often use Jrun.
If you use Console appender, yes, it's going to be logged in your servlet container log file.
Any other gotchas I should be aware of for web application logging?
If you are logging from different threads use logback, it's thread-safe and it exposes parameterized log messages.
Logging to a DB adds another failure point. We had a situation where the prod servers logged to a DB and someone ran an expensive query on that DB that slowed it so much that the prod servers got very, very slow. Logging to a file can cause issues if you run out of space but it seems less likely to slow down the whole app.
I place my configuration on the default package: src/
and log to files using the ${catalina.home} system property:
log4j.appender.???.file=${catalina.home}/logs/system.log
It might be a good idea to place the config file somewhere where an admin can modify it without rebuilding your web app (e.g., so they can turn on detailed logging without waking you up in the middle of the night).
Unfortunately, there's no "official" way for locating externalized resources from a web app (correct me if I'm wrong). The most common way of doing it I've seen is to look through the directories in the classpath.
The excellent paper How to Do Application Logging Right has a bunch of gotchas.
I believe that your other questions have been answered by other people on this page.
I also recommend that you use SLF4J.
One last thing: having speakable representations of objects can save some time.
I recommend to call log API (log4j) via slf4j. Even if you use log4j, web container or depending modules may use different log API such as Java.util.logging or Jakarta commons logging. Slf4j provides bridge modules that redirect them to slf4j API. As a result, all log messages are written by log4j in that case.
put the log4j in the container (server) and create proper appenders per application
relative to server path, but that depends on your needs
we use appenders which log to different files, depends on your needs, e.g. one file for hibernate info/statistics, one for application only, etc.
don't log to much, it slows the application down
Personally I put the log4j.properties in the WEB-INF directory and use an init servlet with the following code :
public class InitServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
private static final String LOG4J_FILE = "WEB-INF/log4j.properties";
public InitServlet() {
super();
}
#Override
public void init() throws ServletException {
super.init();
PropertyConfigurator.configure(getServletContext().getRealPath(LOG4J_FILE));
LogFactory.getLog(InitServlet.class).info("LOG 4J configured");
}
}
Where does the configuration file go in .war package file?
At the root of the classpath but... Don't put the configuration file in the war package. You don't want to repackage and redeploy the application if you change the logging configuration, do you ? A better practice would be to put the configuration file somewhere in the classpath outside the war.
Where do people log to, relative or absolute path flat file, or a database?
I usually log to the file system on a separate partition (log files can grow very fast and should never block the application or the operating system if they become too big). I use most of time an absolute path based on the following model: /var/projects/<PROJECT_NAME>/<PRODUCT>/<CLUSTER_NAME>/logs/<INSTANCE_NAME>.log where <PROJECT_NAME> is the project name, <PRODUCT> can be Apache, Tomcat, Weblogic,..., <CLUSTER_NAME> the name of the cluster and <INSTANCE_NAME> the name of the instance inside the cluster. Logging to the file system is faster than in a database. The drawback is that logs aren't centralized if you are using several instances and physical machines. But merging can easily be done with a script.
Does Log4J logging go directly into the application server log file automatically or is that something you have to set up? In this case I am using Tomcat, but I often use Jrun.
Application server logs are application server logs, not application logs. Don't write to them but set up a logger tool (e.g. log4j) and write to application logs (understand dedicated).
Any other gotchas I should be aware of for web application logging?
If you are using log4j, don't forget to use the isDebugEnabled() before to log:
if(logger.isDebugEnabled()) {
logger.debug("Bla Bla Bla");
}
Where does the configuration file go in .war package file?
Usually, I do not place any logging configuration into the application, rather leaving that to the appserver admins to configure logging server-wide. In the rare cases I want the log4j configuration deployed with a webapp, WEB-INF is the usual path.
Where do people log to, relative or absolute path flat file, or a database?
Again, depends on appserver settings. One common log file for a appserver and rotating on a daily basis is the usual setup. If there are any app-specific needs, the admin may configure a separate logfile for an app (distinguished by package / class names).
Does Log4J logging go directly into the application server log file automatically or is that something you have to set up? In this case I am using Tomcat, but I often use Jrun.
See above. For tomcat used for development purposes, I'd just look for its logging (log4j) configuration and add app-specific specific there.
Any other gotchas I should be aware of for web application logging?
Performance. Limit the ,log level to a minimum (i.e. WARN or ERROR) once you go live. Use
if (log.isDebugEnabled()) { log.debug("..."); } and alike constructs in your code.
Note that if you just need a bit of logging, the servlet standard specifies that you can get the ServletContext and use the log methods there. That is the generic servlet equivalent of System.out.println.

Categories