Strategies to change Logback appender level at production - java

I package my applications as jars and wars. After deployment in production, I like to see on the logs if everything is ok, and once it is, I would like to decrease the level of these logs at runtime, without deploying a new jar/war again.
What is the strategies available to do this with logback? The only I found was to put the logback configuration outside the jar/war, so I could change the level anytime without deploying again. The problem with this is that it will create new arguments to my application, I would like to avoid this, I want to keep it simple.
Is there a better way to accomplish the same?

From my experience, there is no cleaner way than providing an external logback.xml.
Other options include using JMX to adjust the logger level or implementing an endpoint that will change the logger configuration programmatically.

Related

Changing log files location dynamically with SLF4J and independently of logging framework

Is there any way I can use SLF4J to only set my log files location at runtime and independently of logging framework?
Because I already saw other posts that present a solution, but they are for a specific framework, either logbak or log4j.
No. The location of the log file is part of the concrete appenders configuration. SLF4J has no knowledge of what happens with logging events after it hands them off to the binding it uses - and it also shouldn't try to interfere.
Since any application should only use one logging implementation at any time, there should still just be one place to configure the log file location, so I'm having a hard time seeing a problem with that. Does it matter whether you configure that location at the logging facade or the implementation? Or were you actually thinking of providing a root location from which each implementation should relatively define its own file (which might be a useful idea, but still not possible)?

Getting the Log4j settings from a custom properties file

I am working on a huge application which uses its on property file to set the global variables. I want to use the same one for setting the properties of Log4j log file instead of log4j.properties file due to some problems. How do I do this? Is there any way to set the properties of Log4j at run time?
If you just want to rename your log4j.properties file you can do this using a System Variable in your JVM startup (refer link)
-Dlog4j.configuration=test.properties
The Log4j API also allows configuration changes to the Loggers from within an application. Theoretically you could read your own property file and call the appropriate API calls. I'm not sure this approach is recommended - you might end up spending a lot of time getting it working that you could better use developing your application functionality.
Note: I dont know the nature of the huge application, but it if its running in an application server such as JBoss they often have their own dynamic logging configuration

Is there any way I can create a reusable logging project for use in web-applications?

I was wondering if I can create a project in eclipse or for the matter any Java IDE in which I can write my log4j initialization code and save it as a project so I can just import it in any workspace. I know how to configure a servlet in which I initialize the logger in the init() method and load the servlet on startup but that requires an entry in the web-xml which changes depending on the application.
Is there any way I can create a resuable project where there is no requirement for dependency on the DD ?
I know how to configure a servlet in which I initialize the logger in the init() method and load the servlet on startup ...
There is probably a better way.
For instance, the way I do log4j configuration on a servlet (using Tomcat) is to simply put the "log4j.properties" file on the classpath; e.g. in ".../webapps/MyApp/WEB-INF/classes/". Log4j's default strategy for locating the logging properties will find it there ... with no need for you to write any Java code.
Configuring the logging system from Java code is (IMO) a bad idea because it means that you have to change, rebuild and redeploy Java code in order to tweak the logging.
In addition to #Stephen C's answer, some application servers already come with a predefined logging congfiguration. If you're using JBoss, it already has its own log4j configuration in a file called jboss-log4j.xml, which defines a standard configuration, which you can adapt to your needs.
Other than that, I recommend to bundle a configuration with your application like described in the other answer.
Even smarter and more flexible is to use a log wrapper in your application, which will abstract from the underlying logging framework. Take a look at these:
SLF4J (preferred): http://www.slf4j.org/
Commons Logging: http://commons.apache.org/logging/
If you use one of these, you can then configure them to use the logging framework of the server you're deploying to. Many of the popular open-source frameworks use these log wrapper frameworks for similar reasons. Take a look at them, then adopt one as your standard - I strongly recommend SLF4J.
One of the major problems with using a logging framework inside your web application is that you usually end up with wanting to write to a file, and this is not allowed within the servlet API, causing you to become subtly vendor dependent and not work well with multi-computer deployments.
I would strongly suggest that you consider converting your code to use SLJF4 for your actual logging statements as it allows you to
become back end independent.
Use the "{}" placeholders to write simply log.debug("a={}, b={}", a, b) and avoid the possibly expensive generation of the actual logging string if the debug logs were not enabled without having to add a guarding if log.debugging-enabled statement.
These two along was reason enough for me to switch.
A very interesting way to handle logging then is to use the java.util.logging bridge to send all log statements to the Java log system which most web containers handle. Then the web container does all the work for you, and you can use the vendors tooling for investigating log files. Very useful!

Log4j Properties in a Custom Place

I'm using Apache Commons Logging and SLF4J with log4j, but I also want to use the log4j.properties in a custom place like conf/log4.properties. Here is the problem:
If i use
PropertyConfigurator.configure("conf/log4j.properties");
then my app is tied to log4j and defeats the purpose of having ACL and SLF4J.
What is the best way to configure it without the app ever knowing what the logging implementation is?
I think the easiest thing to do is specify the location of the file using the log4j.configuration system property. Adopting the example in the Log4J manual:
java -Dlog4j.configuration=conf/log4j.properties -classpath ...
I believe that Log4J will find a file named "log4j.properties" anywhere on the classpath, but may be hallucinating. Worth trying, however.
As you state, by invoking PropertiesConfigurator, you are tying your application to log4j. However, the extend of this tie is quite limited. You could very easily remove the line invoking PropertiesConfigurator and recompile your code. After that is done, assuming you are using the SLF4J API for logging, you could repalce log4j with another logging framework, say logback-classic or j.u.l. just by replacing jar files. Thus, SLF4J still serves its purpose to a large extend. I would not throw the baby out with the bath water.
You can specify config file location with VM argument
-Dlog4j.configuration="file:/C:/workspace3/local/log4j.properties"

Strategies for logging to application logs from library code?

Where I work we use Log4j for web application logging. The log4j.jar is at the application level, not the container level. We're using a daily rolling file appender. Our log4j.properties files define appenders based on the app package name, so only classes in our application's package and below get logged to our app's log file.
In my application, I'm extending our framework with some supporting classes. These classes are not in the application's package, as they are not exclusive to my application and will eventually be made into a jar library for use with other applications. Because of this, my logging statements are not picked up by my application's appender, and are thus not logged to my application's log files.
I want to allow the classes in my jar to log to the log file of the application using the classes. However, if I create an appender in my application's log4j properties file based on my classnames, I suspect that when multiple applications are using my jar, because of the identical class names in the log4j.properties files, only one application log file will receive my jar's logging statements, and that it will receive ALL the logging statements from EVERY application using that jar. I think this is the case, since we're using a static Logger.getLogger() call to retrieve the logger.
I first want to know if my fears are valid, if this is really what would happen when multiple web applications in the same or different containers are using my jar simultaneously.
I'd also like to know if there are "boundaries" on which this behavior changes. For example, does this problem exist regardless of whether log4j.jar is a container-level jar or an app-level jar, or if each container is running in a separate JVM?
Lastly, if this IS the case, I'd like to know what strategies I should use to overcome the problem.
Thanks in advance!
If log4j.jar is only in the web-app then the logs will stay separate so each web-app should have its own log4j.jar and log4j.properties so that all logs stay separate.
The problem is that the preffered pattern for log4j is to use static *Configurator methods, which don't go very well with application containers.
This article solved this problem for me when i came across it ...

Categories