Logging from my Java EE Application - log4j

I have a big Problem with my Logging. I have a the following strucure of my project:
MyApplication
ear
ejb
com.test.util (src/main/java)
Resources.java (Produce the Logger Instance)
Some Classe which use the Logger with #Inject
log4j.xml (src/main/resources)
web
Here's my Resources.java:
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Resources {
#Produces
#PersistenceContext
private EntityManager em;
#Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
And here is my log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN"
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<!-- <appender-ref ref="CONSOLE"/> -->
<appender-ref ref="FILE" />
</appender>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d: %-5p [%8c] - %m%n" />
</layout>
</appender>
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="${jboss.server.home.dir}/log/emember.log" />
<param name="MaxFileSize" value="10000KB" />
<param name="MaxBackupIndex" value="5" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-d: %-5p [%8c] - %m%n" />
</layout>
</appender>
<category name="org.hibernate.type">
<priority value="trace" />
</category>
<category name="org.hibernate.SQL">
<priority value="debug" />
</category>
<category name="org.hibernate.type.descriptor.sql.BasicBinder">
<priority value="trace" />
</category>
<category name="ch.test">
<priority value="debug" />
</category>
<root>
<priority value="INFO" />
<appender-ref ref="ASYNC" />
</root>
</log4j:configuration>
Whe i use my Unit-Test it work's fine, but when i deplay the ear-File then it doesn't use my log4j.xml. I use a JBoss AS 7 Application Server. And yes i've read all the tutorials with this title, but it doesn't work for me.
Can someone help me with this Problem?

You want to bootstrap SLF4j to be picked up by your EAR application as early as possible. Given you are using JBoss AS 7 as a Java EE 6 implementation, you can use EJB 3.1 singletons as follows:
#Singleton
#Startup
public class BootstrapLogging {
#PostConstruct
public void doUponConstruction() {
URL url = getClass().getClassLoader().getResource("log4j.xml");
DOMConfigurator.configure(url);
}
}
Another Qualifier to guarantee type safety to avoid possible ambiguity with JBoss Logger bean:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SLF4jLogger {
}
Finally, you can inject the Logger using the following snippet:
#Inject #SLF4jLogger
private Logger LOG;
Please add a comment, in case you have a further inquiry. I will reply as soon as I can.

Is there a special reason you want to deploy your log4j.xml? This makes it hard to configure the logging at runtime. I would configure the logging in standalone.xml. If you do this to get application-specific logging, I would configure logging-profiles (>7.1/EAP6.1)

This might work if you exclude the servers logging dependencies and include in your deployment. You would need log4j, slf4j-api and the bindings for slf4j to log4j. I can't recall exactly how the slf4j static bindings work which if it doesn't work would be where the issue likely is.
For the exclusions in your jboss-deployment-structure.xml you'd need to exclude the modules org.slf4j, org.apache.log4j and possible org.apache.commons.logging.
IMO though logging should be configured on the server and not within a deployment. When configured within a deployment you lose things like runtime changes to the logging configuration. Say you want to enable debug logging for a specific category. If you use the server logging it will like work with a command/operation of some sort. If you use a configuration within your deployment you'd likely have to redeploy your application.

Related

Log4Net does not log from a class library

I am working on .NET Framework 4.0 using C# in Windows 7, and trying to log from a class library but it's not working. I'm running my application without errors, but also nothing happens to my log file, neither to my console.
So, here is my code:
This is my App.config file:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<add key="log4net.config" value="config.log4net"/>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{ABSOLUTE} [%thread] %level %logger - %message%newlineExtra Info: %property{testProperty}%newline%exception"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG"/>
<levelMax value="FATAL"/>
</filter>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="MyLogFile.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="5"/>
<maximumFileSize value="10MB"/>
<staticLogFileName value="true"/>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="debug"/>
</filter>
<filter type="log4net.Filter.StringMatchFilter">
<stringToMatch value="error"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline%exception"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>
<logger name="MyApplication">
<level value="DEBUG"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingFileAppender"/>
</logger>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
This is what I put into my AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
This what is at the file i'm trying to log:
private static readonly ILog log = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
log.Debug("Testing");
When i run my program nothing happens. Someone knows why?
Similar to this answer, both the app.config, log4net configuration and the AssemblyInfo.cs configurator needs to be placed in the host application.
Lets say I have project Console as a console project that I will run, and Library as a Library project. Console will need to have an app.config file with the above log4net configuration, and the AssemblyInfo.cs will need the XmlConfigurator code inside of it. Library does not need either of these, and will work by using the LogManager call.
Console > This is the project that you will run.
Properties
AssemblyInfo.cs > Place [assembly: log4net.Config.XmlConfigurator(Watch = true)] here.
app.config > Place log4net XML configuration here.
Program.cs > Start of application.
Library
Properties
AssemblyInfo.cs > Leave this file alone.
Foo.cs > Create the private readonly property.
SomeMethod() > log.Debug("Test");
Incase anyone is still looking at this and to add to the previous answers, you need to have instantiated a logger in your host application before you can log from the class library.
If you look at the log4net documentation for assembly attributes it says this:
"Therefore if you use configuration attributes you must invoke log4net
to allow it to read the attributes. A simple call to LogManager.GetLogger will cause the attributes on the calling assembly
to be read and processed. Therefore it is imperative to make a logging call as early as possible during the application start-up, and
certainly before any external assemblies have been loaded and invoked."
When the assembly attributes are defined in a class library - i.e. an external assembly - it gets tricky. Can you use log4net.Config.XmlConfigurator.Configure(path) instead?

configuration log4j axis1 No appenders could be find for logger

I try to deploy web service using axis1 and use in my web service class log4j logger as
private static final Logger logger = Logger.getLogger(MobileService.class
.getName());
logger.debug("Count nodes" + nodes.getLength());
My class has default package. And I use next log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="HTML-APPENDER" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${catalina.home}/webapps/axis/WEB-INF/classes/log.html" />
<param name="DatePattern" value="'.'yyyy-MM-dd-HH'.html'" />
<layout class="org.apache.log4j.HTMLLayout" />
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="ALL"/>
<param name="LevelMax" value="INFO"/>
</filter>
</appender>
</log4j:configuration>
Also I add in class path for deploying my app next
set CATALINA_HOME=C:\Program Files (x86)\Apache Software Foundation\Tomcat 7.0
set PATH_TO_LOG4J=C:\Program Files (x86)\Apache Software Foundation\Tomcat 7.0\webapps\axis\WEB-INF\classes\log4j.xml
java -Dlog4j.info -Dlog4j.configuration="file:C:\Program Files (x86)\Apache Software Foundation\Tomcat 7.0\webapps\axis\WEB-INF\classes\log4j.xml" -cp "%CATALINA_HOME%\webapps\axis\WEB-INF\lib\axis.jar;%CATALINA_HOME%\webapps\axis\WEB-INF\lib\jaxrpc.jar;%CATALINA_HOME%\webapps\axis\WEB-INF\lib\commons-logging-1.0.4.jar;%CATALINA_HOME%\webapps\axis\WEB-INF\lib\wsdl4j-1.5.1.jar;%CATALINA_HOME%\webapps\axis\WEB-INF\lib\commons-discovery-0.2.jar;%CATALINA_HOME%\webapps\axis\WEB-INF\lib\saaj.jar;%CATALINA_HOME%\common\lib\activation.jar;%CATALINA_HOME%\common\lib\mail.jar;%CATALINA_HOME%\webapps\axis\log4j-1.2.8.jar" org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService MobileService.wsdd
pause
But even -Dlog4j.info -Dlog4j.configuration= doesn't help me. I get error no appenders could be found for logger (org.apache.axis.i18n.projectresourcebundle).
Can you help me?
I think, you forgot to configure a logger. To configure the root logger, for example, place the following lines to the end of your log4j.xml file (before </log4j:configuration>):
<root>
<priority value ="debug" />
<appender-ref ref="HTML-APPENDER" />
</root>

log4net doesn't watch my app.config

I configured my log4net to watch on changes made to the app.config file.
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
When I run my app and change things in the config file, these changes only take effect when I restart my app. Why could this be?
Is there also a way to tell log4net to watch on changes in the app.config? Like:
<appender name="FileAppender" type="log4net.Appender.FileAppender" >
<watch value="true" />
</appender>
------------- EDIT -------------
I tried now to use a separate config-file: log4net.config.
It looks like this:
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="c:\log.txt" />
<appendToFile value="true" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p %c (line %L) -- %m%n" />
</layout>
</appender>
<root>
<appender-ref ref="FileAppender" />
</root>
</log4net>
In my assemblyInfo.cs I wrote the following:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
The class that logs to the file looks like this:
ILog myLogger = LogManager.GetLogger(typeof(Form1));
myLogger.Debug("test");
This works like the old version. logfile entries are made, but when I change my log4net.config during runtime, these changes are not applied.... "Watch=true" should enable that feature, right?
HA!, I was just encountering the same problem, running unit tests that require logging.
Adding this line fixed it:
log4net.Config.XmlConfigurator.Configure();
My App.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
I also do have this:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
According to log4net documentation, the Watch feature does not work for application configuration files (app.config, web.config):
Because the System.Configuration API does not support reloading of the config file
the configuration settings cannot be watched using the
log4net.Config.XmlConfigurator.ConfigureAndWatch methods.
So if you need the log4net configuration to be re-configurable, you will need to place it in a separate XML file and your application needs to have sufficient permissions to read the file:
The file to read the configuration from can be specified using any of the log4net.Config.XmlConfigurator methods that accept a System.IO.FileInfo object. Because the file system can be monitored for file change notifications the ConfigureAndWatch methods can be used to monitor the configuration file for modifications and automatically reconfigure log4net.
Even though I'm terribly late to the party - here's, what helped me: a simple call to log4net.LogManager.GetLogger("DUMMY"); at the very beginning of my program. I put it in the very first line of program.cs's Main() method. No need to assign the logger to any object, merely a polite request to log4net to read the assembly's attributes as stated here.
Using attributes can be a clearer method for defining where the application's configuration will be loaded from. However it is worth noting that attributes are purely passive. They are information only. Therefore if you use configuration attributes you must invoke log4net to allow it to read the attributes. A simple call to LogManager.GetLogger will cause the attributes on the calling assembly to be read and processed. Therefore it is imperative to make a logging call as early as possible during the application start-up, and certainly before any external assemblies have been loaded and invoked.

log4j basic configuration

I used log4j to log some steps in my application. To be quick and dirty, I used:
org.apache.log4j.BasicConfigurator.configure();
This output my logs in the Eclipse console.
I want to know if and how to set the level threshold higher than DEBUG? In other word, I do not want to display DEBUG level message, just ERR, WARN, INFO.
Thank you.
EDIT:
May I use this following?
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
[...]
Logger logger = Logger.getLogger(this.class);
logger.setLevel(Level.INFO);
I think the simplest way would be:
Logger.getRootLogger().setLevel(Level.INFO);
org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.INFO);
Assuming you are calling BasicConfigurator.configure() before any loggers are called:
You can use either of these config files to change it without recompiling:
log4j.properties
log4j.rootLogger=INFO
log4j.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<root>
<priority value="INFO"/>
</root>
</log4j:configuration>
One of these must be on command line.
1) Find your appender, you sould have something like this in your log4j.xml configuration file.
<appender name="DEBUG" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="C:/logs/rmDebug.log"/>
<param name="Append" value="true"/>
<param name="MaxFileSize" value="1500KB"/>
<param name="MaxBackupIndex" value="2"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="**FOOBAR** %d{dd.MM.yyyy HH:mm:ss} %c %m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="DEBUG" />
<param name="LevelMax" value="FATAL" />
</filter>
</appender>
You see levelMin and LevelMax value ? levelMin is where you begin to log, and levelMax, where you stop to log. ( with this specific appender ). You can have several appender.
Then for assign this appender to a class or package. You can do something like that :
<category name="com.foobar.automation.doremiResourceManager" additivity="true">
<appender-ref ref="DEBUG"/>
</category>
If you are not configuring inside the properties file, use this:
Logger root = Logger.getRootLogger();
root.setLevel(Level.INFO);
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
What BasicConfigurator.configure() do is adding root logger to a ConsoleAppender and set the appender layout to a PatternLayout with the pattern "%r [%t] %-5p %c - %m%n". So you need to set the root logger's level. If you only set the level of the logger of this class, the level of root logger is unchanged, then all the other loggers(except this class's) may still use root logger's level, so you will still see the unwanted logs.
See http://logging.apache.org/log4j/1.2/manual.html.

How do you get log4j to roll files based on date and size?

So log4j comes with two existing log rollers: RollingFileAppender, and DailyRollingFileAppender. Has anyone heard of an appender that does both of what the former do?
I need an appender that will roll log files based on filesize, but also append the current date to it.
I've been thinking about creating my own appender, but if there is already one that has been created, why not save the time and use that one?
Looks like you want a mix of the http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/DailyRollingFileAppender.html and the http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/RollingFileAppender.html.
You'll have to code by yourself. The good news is: you'll just have "merge" those classes functionality, no "low level" new code required.
I know this post is a bit late but you could try out the TimeAndSizeRollingAppender. It's freely available under the Apache 2.0 license, download it from www.simonsite.org.uk.
The Log4J Extras from the "companions" project provide an array of policies for rolling, including what you're looking for.
APIDoc: http://logging.apache.org/log4j/extras/apidocs/index.html
Homepage: http://logging.apache.org/log4j/extras/
Using Log4j
As #JavaJigs said, Log4j's extras can be used.
First of all, if you're using Maven, add it as dependency keeping in mind to use the same log4j version, just to avoid any kind of conflict.
<!-- you should already have something like this -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- add this one, please note the version is the same than log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>apache-log4j-extras</artifactId>
<version>1.2.17</version>
</dependency>
Then, set up an appender to use both kinds of rollings. This is a quick and dirty example that rolls every minute and / or when the size of the log files exceeds 1000 bytes.
<appender name="rollout5" class="org.apache.log4j.rolling.RollingFileAppender">
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="ActiveFileName" value="log4j-current.log" />
<param name="FileNamePattern" value="log4j-%d{HH-mm}.%i.log.gz" />
</rollingPolicy>
<triggeringPolicy class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy">
<param name="MaxFileSize" value="1000" />
</triggeringPolicy>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n" />
</layout>
</appender>
Add the appender to the logger as you usually do.
If you run the application you should obtain something like that...
log4j-current.log
log4j-18-13.1480266729211.log.gz
log4j-18-12.1480266729095.log.gz
log4j-18-12.1480266729123.log.gz
Obviously the numbers of files and their names depend on how your application logs.
As you can see, the %i placeholder gets replaced with a sort of random yet ever increasing number. I was not able to find a way to have it replaced with number starting from 0 though. Nevertheless, such files listed in alphabetic order should match their historical order.
Other ideas
I know you mentioned explicitly log4j. But, if you can, why not to evaluate moving to log4j2? In this log4j2 piece of doc there are a couple of examples that seem to suit your needs.
Too late to reply. But hopefully this will help someone.
Add log4j dependency to your pom.xml file
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Grab a copy of this FileAppender implementation. Thanks to the author of this file.
http://haobangshou.googlecode.com/svn/trunk/hbs/APPLICATION/server/common/src/com/hbs/common/appender/TimeSizeRollingFileAppender.java
Place this log4j.xml file in your resources folder
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} %m%n"/>
</layout>
</appender>
<appender name="debug" class="com.myproject.log.TimeSizeRollingFileAppender">
<param name="File" value="log/debug.log"/>
<param name="MaxBackupIndex" value="300"/>
<param name="Encoding" value="GB2312"/>
<!--CHANGE THIS TO A LARGER SIZE EG : 20MB. USE 1MB TO TEST IF THE SETTING WORKS.-->
<param name="MaxFileSize" value="1MB"/>
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} %p [%c] - [%m]%n"/>
</layout>
</appender>
<!--CHANGE name TO ROOT PACKAGE NAME OF YOUR PROJECT THAT YOU WANT TO LOG.-->
<logger name="com.myproject" additivity="false">
<level value="debug"/>
<appender-ref ref="consoleAppender"/>
<appender-ref ref="debug"/>
</logger>
<logger name="org.springframework" additivity="false">
<level value="debug"/>
<appender-ref ref="consoleAppender"/>
<appender-ref ref="debug"/>
</logger>
<logger name="org.hibernate" additivity="false">
<level value="debug"/>
<appender-ref ref="consoleAppender"/>
<appender-ref ref="debug"/>
</logger>
<root>
<priority value="INFO"></priority>
<appender-ref ref="consoleAppender"/>
<appender-ref ref="debug"/>
</root>
To do a quick test:
import org.apache.log4j.Logger;
public class Main {
static public void main(String[] args) {
Logger log = Logger.getLogger(Main.class);
for(int i = 0; i < 10000; i ++)
log.info("Testing log");
}
}
Done!!
We use the class you see here. It works as you described and extends FileAppender.

Resources