log4j2 Loki Appender on Databricks pyspark - apache-spark

I'm trying to send logs from my Databricks cluster to a Loki instance using this appender.
I added an init script (see below) which modifies the log4j2.xml files for driver and executor.
I added a library in the libraries tab of cluster configuration. Added as a maven library. I can see in logs that it was successfully downloaded and installed.
Did echo "" >> log4j2.xml and waited 30 seconds for it to reread the config. Same error.
init script
for f in /databricks/spark/dbconf/log4j/executor/log4j2.xml /databricks/spark/dbconf/log4j/driver/log4j2.xml; do
sed -i 's/<Configuration /<Configuration monitorInterval="30" /' "$f"
sed -i 's/packages="com.databricks.logging"/packages="pl.tkowalcz.tjahzi.log4j2, com.databricks.logging"/' "$f"
sed -i 's~<Appenders>~<Appenders>\n <Loki name="Loki" bufferSizeMegabytes="64">\n <host>loki.atops.abc.com</host>\n <port>3100</port>\n\n <ThresholdFilter level="ALL"/>\n <PatternLayout>\n <Pattern>%X{tid} [%t] %d{MM-dd HH:mm:ss.SSS} %5p %c{1} - %m%n%exception{full}</Pattern>\n </PatternLayout>\n\n <Header name="X-Scope-OrgID" value="ABC"/>\n <Label name="server" value="Databricks"/>\n <Label name="foo" value="bar"/>\n <Label name="system" value="abc"/>\n <LogLevelLabel>log_level</LogLevelLabel>\n </Loki>\n~' $f
sed -i 's/\(<Root.*\)/\1\n <AppenderRef ref="Loki"\/>/' "$f"
done
In stdout of the cluster I see following errors (which I suppose means the jar is somehow not in classpath, or it's looking for wrong class somehow):
ERROR Error processing element Loki ([Appenders: null]): CLASS_NOT_FOUND
ERROR Unable to locate appender "Loki" for logger config "root"
Also tried to add class name to Appender spec:
<Loki name="Loki" class="pl.tkowalcz.tjahzi.log4j2.LokiAppender" bufferSizeMegabytes="64">
instead of
<Loki name="Loki" bufferSizeMegabytes="64">
Same error.
find /databricks -name '*log4j2-appender-nodep*' -type f finds nothing.
I also tried downloading the jar file put it in dbfs and then install as a JAR library (instead of MAVEN library):
$ databricks fs cp local/log4j2-appender-nodep-0.9.23.jar dbfs:/Shared/log4j2-appender-nodep-0.9.23.jar
$ databricks libraries install --cluster-id 1-2-345 --jar "dbfs:/Shared/log4j2-appender-nodep-0.9.23.jar"
Same error.
I'm able to post from teh cluster to Loki intance using curl, I can see this log in Grafana GUI:
ds=$(date +%s%N) && \
echo $ds && \
curl -v -H "Content-Type: application/json" -XPOST -s "http://loki.atops.abc.com:3100/loki/api/v1/push" --data-raw '{"streams": [{ "stream": { "foo": "bar2", "system": "abc" }, "values": [ [ "'$ds'", "'$ds': testing, testing" ] ] }]}'
This is what the conf file contents after init script: cat /databricks/spark/dbconf/log4j/driver/log4j2.xml
<?xml version="1.0" encoding="UTF-8"?><Configuration monitorInterval="30" status="INFO" packages="pl.tkowalcz.tjahzi.log4j2, com.databricks.logging" shutdownHook="disable">
<Appenders>
<Loki name="Loki" bufferSizeMegabytes="64">
<host>loki.atops.abc.com</host>
<port>3100</port>
<ThresholdFilter level="ALL"/>
<PatternLayout>
<Pattern>%X{tid} [%t] %d{MM-dd HH:mm:ss.SSS} %5p %c{1} - %m%n%exception{full}</Pattern>
</PatternLayout>
<Header name="X-Scope-OrgID" value="ABC"/>
<Label name="server" value="Databricks"/>
<Label name="foo" value="bar"/>
<Label name="system" value="abc"/>
<LogLevelLabel>log_level</LogLevelLabel>
</Loki>
<RollingFile name="publicFile.rolling" fileName="logs/log4j-active.log" filePattern="logs/log4j-%d{yyyy-MM-dd-HH}.log.gz" immediateFlush="true" bufferedIO="false" bufferSize="8192" createOnDemand="true">
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
<PatternLayout pattern="%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n%ex"/>
</RollingFile>
---snip---
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Loki"/>
<AppenderRef ref="publicFile.rolling.rewrite"/>
</Root>
<Logger name="privateLog" level="INFO" additivity="false">
<AppenderRef ref="privateFile.rolling.rewrite"/>
</Logger>
---snip---
</Loggers>
</Configuration>

Most probably this happens because log4j is initialized when cluster starts, but libraries that you specify in the Libraries UI - they are installed after cluster starts, so your loki library isn't available during start.
The solution would be to install loki library from the same init script that you use for log4j configuration - just copy library & its dependencies to the /databricks/jars/ folder (for example from DBFS that will be available to script as /dbfs/...).
E.g. if you have uploaded your jar file to /dbfs/Shared/custom_jars/log4j2-appender-nodep-0.9.23.jar then add following to the init script:
#!/bin/bash
cp /dbfs/Shared/custom_jars/log4j2-appender-nodep-0.9.23.jar /databricks/jars/
# other code to update log4j2.xml etc...

Related

Logback logs not sending to Application Insights when Spring Boot app deployed to Azure App Service

I've followed several tutorials online detailing how to send my Spring Boot application logs via logback to Azure Application Insights. When I run my code locally using the same command line as Azure App Service uses to start my app, I can see logs in Application Insights. However, when I deploy my app to Azure App Service, no logs are sent to Application Insights. So, my setup seems to be correct (logback.xml, library versions, etc.), but something is not quite right in Azure.
What am I missing?
Gradle:
implementation group: 'com.microsoft.azure', name: 'applicationinsights-spring-boot-starter', version: '2.6.1'
implementation group: 'com.microsoft.azure', name: 'applicationinsights-logging-logback', version: '2.6.1'
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<appender name="aiAppender" class="com.microsoft.applicationinsights.logback.ApplicationInsightsAppender">
<instrumentationKey>actual-key-value</instrumentationKey>
</appender>
<logger name="com.foobar" level="DEBUG"/>
<logger name="com.microsoft.applicationinsights" level="INFO"/>
<root level="INFO">
<appender-ref ref="aiAppender" />
</root>
</configuration>
command line
java -Dlogging.config=/home/site/wwwroot/logback-spring.xml -Dlogging.file=/home/LogFiles/bootlogback.log -jar /home/site/wwwroot/foobar-service-0.0.1-SNAPSHOT.jar"
(the deployment pulls out the logback-spring.xml from the jar and places it in the dir next to the jar file)
Again, running it locally with a similar command line (different directories to match my workstation), the logs are sent to Application Insights.

log4net not creating log file upon installation

I have searched far and wide for my solution (including relevant stackoverflow questions) but have yet to find an answer that fixes my issue. I have been using log4net successfully in a work project and when I run the program in visual studio I get my log file. If I install the program using the msi installer (wix) then I do NOT get a log file. I'll first list things I've tried, followed by an edited version of my code.
Also, anywhere I say "appname" I did not actually put appname, just keeping project name out of post.
I'm placing the log file in ${USERPROFILE}\AppData\Local[appname] directory, permissions are not an issue.
Since the config file that is present in the installed version is appname.exe.config instead of app.config, I changed the Assemblyinfo.cs assembly statement to appname.exe.config. This however did not solve my issue, it still only works while running through visual studio, an installed version does not.
I have modified product.wxs to deliver log4net.dll and log4net.xml to the install directory. (forgot to do this, app would not start so came back and added it in) still no change.
We have 5 projects within a single solution using log4net. all of the assemblyinfo.cs files have the following:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "appname.exe.config", Watch = true)]
I was using [assembly: log4net.Config.XmlConfigurator(ConfigFile = "app.config", Watch = true)] but changed this to the modified config file name that is placed in the install dir and the bin.
Inside of app.config(excuse any possible typos, my dev machine is airgapped and I cannot copy paste the code):
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<root>
<level value="ALL"/>
<appender-ref ref="MyAppender"/>
</root>
<appender name="MyAppender" type="log4net.Appender.FileAppender">
<file value="${USERPROFILE}\AppData\Local\appname\appname.log"/>
<appendToFile value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level - %message%newline"/>
</layout>
</appender>
</log4net>
</configuration>
and in my c# code where I use the logger:
private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
If your configuration is in your app.config, you can just use:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
When you specify a file, log4net expect the log4net element as xml root element. Which is not true for your app.config.
#erike i'm not sure it was mine. So I do not have an link for you.

How to not-abbreviate the source class name in spriing-boot's loggger name?

When I run a spring-boot application, it shows the following log:
2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
The logger name is abbreviated for the following:
org.springframework.boot.context.embedded.FilterRegistrationBean
How can I show the full source class name for it?
Thanks!
By default Spring boot uses Logback logging. You can change the configuration by putting a logback.xml file in your class path. They have a default base.xml which defines the overall configuration and includes their defaults.xml file. Because of where the log pattern is defined you will need to created a file that has a few of the items inside copied. Here is an example of a logback.xml I created:
<configuration>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%C){cyan} %clr(:){faint} %m%n%wex"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
And here is an example of a log message using this configuration:
2015-06-17 09:02:06.511 INFO 18816 --- [ main] org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
You can tweak the pattern further if you want. See this page and the PatternLayout section for possible items to include.
You can also use other logging implementations per their logging documentation and then configure those as necessary.
UPDATE: As of Spring Boot version 1.3.0 (not released yet as of this edit) you can use logging.pattern.console and logging.pattern.file properties to set the pattern for the default Logback configurations. See the sample properties file here in their documentation. NOTE: This link could change as it points to the build SNAPSHOT docs.

How to initialize log4j properly?

After adding log4j to my application I get the following output every time I execute my application:
log4j:WARN No appenders could be found for logger (slideselector.facedata.FaceDataParser).
log4j:WARN Please initialize the log4j system properly.
It seems this means a configuration file is missing.
Where should this config file be located and what is a good start content?
I'm using plain java for developing a desktop application. So no webserver etc...
Log4j by default looks for a file called log4j.properties or log4j.xml on the classpath.
You can control which file it uses to initialize itself by setting system properties as described here (Look for the "Default Initialization Procedure" section).
For example:
java -Dlog4j.configuration=customName ....
Will cause log4j to look for a file called customName on the classpath.
If you are having problems I find it helpful to turn on the log4j.debug:
-Dlog4j.debug
It will print to System.out lots of helpful information about which file it used to initialize itself, which loggers / appenders got configured and how etc.
The configuration file can be a java properties file or an xml file. Here is a sample of the properties file format taken from the log4j intro documentation page:
log4j.rootLogger=debug, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
While setting up log4j properly is great for "real" projects you might want a quick-and-dirty solution, e.g. if you're just testing a new library.
If so a call to the static method
org.apache.log4j.BasicConfigurator.configure();
will setup basic logging to the console, and the error messages will be gone.
If you just get rid of everything (e.g. if you are in tests)
org.apache.log4j.BasicConfigurator.configure(new NullAppender());
As per Apache Log4j FAQ page:
Why do I see a warning about "No appenders found for logger" and "Please configure log4j properly"?
This occurs when the default configuration files log4j.properties and log4j.xml can not be found and the application performs no explicit configuration. log4j uses Thread.getContextClassLoader().getResource() to locate the default configuration files and does not directly check the file system. Knowing the appropriate location to place log4j.properties or log4j.xml requires understanding the search strategy of the class loader in use. log4j does not provide a default configuration since output to the console or to the file system may be prohibited in some environments.
Basically the warning No appenders could be found for logger means that you're using log4j logging system, but you haven't added any Appenders (such as FileAppender, ConsoleAppender, SocketAppender, SyslogAppender, etc.) into your configuration file or the configuration file is missing.
There are three ways to configure log4j: with a properties file (log4j.properties), with an XML file and through Java code (rootLogger.addAppender(new NullAppender());).
log4j.properties
If you've property file present (e.g. when installing Solr), you need to place this file within your classpath directory.
classpath
Here are some command suggestions in Linux how to determine your classpath value:
$ echo $CLASSPATH
$ ps wuax | grep -i classpath
$ grep -Ri classpath /etc/tomcat? /var/lib/tomcat?/conf /usr/share/tomcat?
or from Java: System.getProperty("java.class.path").
Log4j XML
Below is a basic XML configuration file for log4j in XML format:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="console" />
</root>
</log4j:configuration>
Tomcat
If you're using Tomcat, you may place your log4j.properties into: /usr/share/tomcat?/lib/ or /var/lib/tomcat?/webapps/*/WEB-INF/lib/ folder.
Solr
For the reference, Solr default log4j.properties file looks like:
# Logging level
solr.log=logs/
log4j.rootLogger=INFO, file, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x \u2013 %m%n
#- size rotation with log cleanup.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=4MB
log4j.appender.file.MaxBackupIndex=9
#- File to log to and log format
log4j.appender.file.File=${solr.log}/solr.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS}; %C; %m\n
log4j.logger.org.apache.zookeeper=WARN
log4j.logger.org.apache.hadoop=WARN
# set to INFO to enable infostream log messages
log4j.logger.org.apache.solr.update.LoggingInfoStream=OFF
Why can't log4j find my properties file in a J2EE or WAR application?
The short answer: the log4j classes and the properties file are not within the scope of the same classloader.
Log4j only uses the default Class.forName() mechanism for loading classes. Resources are handled similarly. See the documentation for java.lang.ClassLoader for more details.
So, if you're having problems, try loading the class or resource yourself. If you can't find it, neither will log4j. ;)
See also:
Short introduction to log4j at Apache site
Apache: Logging Services: FAQ at Apache site
Find a log4j.properties or log4j.xml online that has a root appender, and put it on your classpath.
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.rootLogger=debug, stdout
will log to the console. I prefer logging to a file so you can investigate afterwards.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=100KB
log4j.appender.file.maxBackupIndex=5
log4j.appender.file.File=test.log
log4j.appender.file.threshold=debug
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=debug,file
although for verbose logging applications 100KB usually needs to be increased to 1MB or 10MB, especially for debug.
Personally I set up multiple loggers, and set the root logger to warn or error level instead of debug.
You can set the location of your log4j.properties from inside your java app by using:
org.apache.log4j.PropertyConfigurator.configure(file/location/log4j.properties)
More information is available here: https://logging.apache.org/log4j/1.2/manual.html
Another way to do it without putting the property file on the classpath, is to set the property from the java code directly. Here is the sample code.
public class Log4JSample {
public static void main(String[] args) {
Properties properties=new Properties();
properties.setProperty("log4j.rootLogger","TRACE,stdout,MyFile");
properties.setProperty("log4j.rootCategory","TRACE");
properties.setProperty("log4j.appender.stdout", "org.apache.log4j.ConsoleAppender");
properties.setProperty("log4j.appender.stdout.layout", "org.apache.log4j.PatternLayout");
properties.setProperty("log4j.appender.stdout.layout.ConversionPattern","%d{yyyy/MM/dd HH:mm:ss.SSS} [%5p] %t (%F) - %m%n");
properties.setProperty("log4j.appender.MyFile", "org.apache.log4j.RollingFileAppender");
properties.setProperty("log4j.appender.MyFile.File", "my_example.log");
properties.setProperty("log4j.appender.MyFile.MaxFileSize", "100KB");
properties.setProperty("log4j.appender.MyFile.MaxBackupIndex", "1");
properties.setProperty("log4j.appender.MyFile.layout", "org.apache.log4j.PatternLayout");
properties.setProperty("log4j.appender.MyFile.layout.ConversionPattern","%d{yyyy/MM/dd HH:mm:ss.SSS} [%5p] %t (%F) - %m%n");
PropertyConfigurator.configure(properties);
Logger logger = Logger.getLogger("MyFile");
logger.fatal("This is a FATAL message.");
logger.error("This is an ERROR message.");
logger.warn("This is a WARN message.");
logger.info("This is an INFO message.");
logger.debug("This is a DEBUG message.");
logger.trace("This is a TRACE message.");
}
}
import org.apache.log4j.BasicConfigurator;
Call this method
BasicConfigurator.configure();
You can set up the log level by using setLevel().
The levels are useful to easily set the kind of informations you want the program to display.
For example:
Logger.getRootLogger().setLevel(Level.WARN); //will not show debug messages
The set of possible levels are:
TRACE,
DEBUG,
INFO,
WARN,
ERROR and
FATAL
According to Logging Services manual
To enable -Dlog4j.debug, I go to System, Advanced system settings, Environment variables and set system variable _JAVA_OPTIONS to -Dlog4j.debug.
What are you developing in? Are you using Apache Tomcat?
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyyMMdd HH:mm:ss.SSS} [[%5p] %c{1} [%t]] %m%n
I have a properties like this in a Java app of mine.
I've created file log4j.properties in resources folder next to hibernate.cfg.xml file and filled it with text below:
log4j.rootLogger=INFO, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}:%L] %m%n
now I got rid of warnings and errors
Simply, create log4j.properties under src/main/assembly folder. Depending on if you want log messages to be shown in the console or in the file you modify your file. The following is going to show your messages in the console.
# Root logger option
log4j.rootLogger=INFO, stdout
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
My log4j got fixed by below property file:
## direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.rootLogger=debug, stdout
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.maxFileSize=100KB
log4j.appender.file.maxBackupIndex=5
log4j.appender.file.File=./logs/test.log
log4j.appender.file.threshold=debug
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=debug,file
As explained earlier there are 2 approaches
First one is to just add this line to your main method:
BasicConfigurator.configure();
Second approach is to add this standard log4j.properties file to your classpath:
While taking second approach you need to make sure you initialize the file properly.
Eg.
Properties props = new Properties();
props.load(new FileInputStream("log4j property file path"));
props.setProperty("log4j.appender.File.File", "Folder where you want to store log files/" + "File Name");
Make sure you create required folder to store log files.
Try to set debug attribut in log4j:configuration node to true.
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
It prints out information as the configuration file is read and used to configure the log4j environment. You may be got more details to resolve your problem.
Logging API - The Java Logging API facilitates software servicing and maintenance at customer sites by producing log reports suitable for analysis by end users, system administrators, field service engineers, and software development teams. The Logging APIs capture information such as security failures, configuration errors, performance bottlenecks, and/or bugs in the application or platform. The core package includes support for delivering plain text or XML formatted log records to memory, output streams, consoles, files, and sockets. In addition, the logging APIs are capable of interacting with logging services that already exist on the host operating system.
Package java.util.logging « Provides the classes and interfaces of the Java platform's core logging facilities.
Log4j 1.x « log4j is a popular Java-based logging utility. Log4j is an open source project based on the work of many authors. It allows the developer to control which log statements are output to a variety of locations by using Appenders [console, files, DB and email]. It is fully configurable at runtime using external configuration files.
Log4j has three main components:
Loggers - [OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE]
Appenders
Apache Commons Logging: ConsoleAppender, FileAppender, RollingFileAppender, DailyRollingFileAppender, JDBCAppender-Driver, SocketAppender
Log4J Appender for MongoDB: MongoDbAppender - Driver
Layouts - [PatternLayout, EnhancedPatternLayout]
Configuration files can be written in XML or in Java properties (key=value) format.
log4j_External.properties « Java properties (key=value) format
The string between an opening "${" and closing "}" is interpreted as a key. The value of the substituted variable can be defined as a system property or in the configuration file itself.
Set appender specific options. « log4j.appender.appenderName.option=value, For each named appender you can configure its Layout.
log4j.rootLogger=INFO, FILE, FILE_PER_SIZE, FILE_PER_DAY, CONSOLE, MySql
#log.path=./
log.path=E:/Logs
# https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
# {%-5p - [WARN ,INFO ,ERROR], %5p 0- [ WARN, INFO,ERROR]}
log.patternLayout=org.apache.log4j.PatternLayout
log.pattern=%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n
# System.out | System.err
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.err
log4j.appender.CONSOLE.layout=${log.patternLayout}
log4j.appender.CONSOLE.layout.ConversionPattern=${log.pattern}
# File Appender
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=${log.path}/logFile.log
#log4j:ERROR setFile(null,false) call failed. - Defaults setFile(null,true)
#log4j.appender.FILE.Append = false
log4j.appender.FILE.layout=${log.patternLayout}
log4j.appender.FILE.layout.ConversionPattern=${log.pattern}
# BackUP files for every Day.
log4j.appender.FILE_PER_DAY=org.apache.log4j.DailyRollingFileAppender
# [[ Current File ] - logRollingDayFile.log ], { [BackUPs] logRollingDayFile.log_2017-12-10, ... }
log4j.appender.FILE_PER_DAY.File=${log.path}/logRollingDayFile.log
log4j.appender.FILE_PER_DAY.DatePattern='_'yyyy-MM-dd
log4j.appender.FILE_PER_DAY.layout=${log.patternLayout}
log4j.appender.FILE_PER_DAY.layout.ConversionPattern=${log.pattern}
# BackUP files for size rotation with log cleanup.
log4j.appender.FILE_PER_SIZE=org.apache.log4j.RollingFileAppender
# [[ Current File ] - logRollingFile.log ], { [BackUPs] logRollingFile.log.1, logRollingFile.log.2}
log4j.appender.FILE_PER_SIZE.File=${log.path}/logRollingFile.log
log4j.appender.FILE_PER_SIZE.MaxFileSize=100KB
log4j.appender.FILE_PER_SIZE.MaxBackupIndex=2
log4j.appender.FILE_PER_SIZE.layout=${log.patternLayout}
log4j.appender.FILE_PER_SIZE.layout.ConversionPattern=${log.pattern}
# MySql Database - JDBCAppender
log4j.appender.MySql=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.MySql.driver=com.mysql.jdbc.Driver
log4j.appender.MySql.URL=jdbc:mysql://localhost:3306/automationlab
log4j.appender.MySql.user=root
log4j.appender.MySql.password=
log4j.appender.MySql.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.MySql.layout.ConversionPattern=INSERT INTO `logdata` VALUES ('%p', '%d{yyyy-MM-dd HH:mm:ss}', '%C', '%M', '%L', '%m');
#log4j.appender.MySql.sql=INSERT INTO `logdata` VALUES ('%p', '%d{yyyy-MM-dd HH:mm:ss}', '%C', '%M', '%L', '%m');
# Direct log events[Messages] to MongoDB Collection - MongoDbAppender
log.mongoDB.hostname=loalhost
log.mongoDB.userName=Yash777
log.mongoDB.password=Yash#123
log.mongoDB.DB=MyLogDB
log.mongoDB.Collection=Logs
log4j.appender.MongoDB=org.log4mongo.MongoDbAppender
log4j.appender.MongoDB.hostname=${log.mongoDB.hostname}
log4j.appender.MongoDB.userName=${log.mongoDB.userName}
log4j.appender.MongoDB.password=${log.mongoDB.password}
log4j.appender.MongoDB.port=27017
log4j.appender.MongoDB.databaseName=${log.mongoDB.DB}
log4j.appender.MongoDB.collectionName=${log.mongoDB.Collection}
log4j.appender.MongoDB.writeConcern=FSYNCED
MySQL Table structure for table logdata
CREATE TABLE IF NOT EXISTS `logdata` (
`Logger_Level` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`DataTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`ClassName` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`MethodName` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`LineNumber` int(10) NOT NULL,
`Message` text COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
log4j_External.xml « XML log4j:configuration with public DTD file
<?xml version="1.0" encoding="iso-8859-1"?>
<!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 debug="false">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="target" value="System.out" />
<param name="threshold" value="debug" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n" />
</layout>
</appender>
<appender name="FILE" class="org.apache.log4j.FileAppender">
<param name="file" value="E:/Logs/logFile.log" />
<param name="append" value="false" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n" />
</layout>
</appender>
<appender name="FILE_PER_SIZE" class="org.apache.log4j.RollingFileAppender">
<param name="file" value="E:/Logs/logRollingFile.log" />
<param name="immediateFlush" value="true"/>
<param name="maxFileSize" value="100KB" />
<param name="maxBackupIndex" value="2"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n" />
</layout>
</appender>
<appender name="FILE_PER_DAY" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="E:/Logs/logRollingDayFile.log" />
<param name="datePattern" value="'_'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n"/>
</layout>
</appender>
<root>
<priority value="info" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
<appender-ref ref="FILE_PER_SIZE" />
<appender-ref ref="FILE_PER_DAY" />
</root>
</log4j:configuration>
Log4j Configuration from the URL in Java program:
In order to specify a custom configuration with an external file, the used class must implement the Configurator interface.
when default configuration files "log4j.properties", "log4j.xml" are not available
For "log4j.properties" you can fed to the PropertyConfigurator.configure(java.net.URL) method.
For "log4j.xml" DOMConfigurator will be used.
public class LogFiles {
// Define a static logger variable so that it references the Logger instance named "LogFiles".
static final Logger log = Logger.getLogger( LogFiles.class );
#SuppressWarnings("deprecation")
public static void main(String[] args) {
System.out.println("CONFIGURATION_FILE « "+LogManager.DEFAULT_CONFIGURATION_FILE);
System.out.println("DEFAULT_XML_CONFIGURATION_FILE = 'log4j.xml' « Default access modifier");
String fileName = //"";
//"log4j_External.xml";
"log4j_External.properties";
String configurationFile = System.getProperty("user.dir")+"/src/" + fileName;
if( fileName.contains(".xml") ) {
DOMConfigurator.configure( configurationFile );
log.info("Extension *.xml");
} else if ( fileName.contains(".properties") ) {
PropertyConfigurator.configure( configurationFile );
log.info("Extension *.properties");
} else {
DailyRollingFileAppender dailyRollingAppender = new DailyRollingFileAppender();
dailyRollingAppender.setFile("E:/Logs/logRollingDayFile.log");
dailyRollingAppender.setDatePattern("'_'yyyy-MM-dd");
PatternLayout layout = new PatternLayout();
layout.setConversionPattern( "%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS} %C{1}:%12.20M:%L - %m %n" );
dailyRollingAppender.setLayout(layout);
dailyRollingAppender.activateOptions();
Logger rootLogger = Logger.getRootLogger();
rootLogger.setLevel(Level.DEBUG);
rootLogger.addAppender(dailyRollingAppender);
log.info("Configuring from Java Class.");
}
log.info("Console.Message.");
method2();
methodException(0);
}
static void method2() {
log.info("method2 - Console.Message.");
}
static void methodException(int b) {
try {
int a = 10/b;
System.out.println("Result : "+ a);
log.info("Result : "+ a);
} catch (Exception ex) { // ArithmeticException: / by zero
log.error(String.format("\n\tException occurred: %s", stackTraceToString(ex)));
}
}
public static String stackTraceToString(Exception ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
return sw.toString();
}
}
For testing, a quick-dirty way including setting log level:
org.apache.log4j.BasicConfigurator.configure();
org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.WARN);
// set to Level.DEBUG for full, or Level.OFF..
The fix for me was to put "log4j.properties" into the "src" folder.
If we are using apache commons logging wrapper on top of log4j, then we need to have both the jars available in classpath. Also, commons-logging.properties and log4j.properties/xml should be available in classpath.
We can also pass implementation class and log4j.properties name as JAVA_OPTS either using -Dorg.apache.commons.logging.Log=<logging implementation class name> -Dlog4j.configuration=<file:location of log4j.properties/xml file>. Same can be done via setting JAVA_OPTS in case of app/web server.
It will help to externalize properties which can be changed in deployment.
This is an alternative way using .yaml
Logic Structure:
Configuration:
Properties:
Appenders:
Loggers:
Sample:
Configutation:
name: Default
Properties:
Property:
name: log-path
value: "logs"
Appenders:
Console:
name: Console_Appender
target: SYSTEM_OUT
PatternLayout:
pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"
File:
name: File_Appender
fileName: ${log-path}/logfile.log
PatternLayout:
pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"
Loggers:
Root:
level: debug
AppenderRef:
- ref: Console_Appender
Logger:
- name: <package>.<subpackage>.<subsubpackage>.<...>
level: debug
AppenderRef:
- ref: File_Appender
level: error
Ref: LOG4J 2 CONFIGURATION: USING YAML
Maven solution:
I came across all the same issues as above, and for a maven solution I used 2 dependencies. This configuration is only meant for quick testing if you want a simple project to be using a logger, with a standard configuration. I can imagine you want to make a configuration file later on if you need more information and or finetune your own logging levels.
<properties>
<slf4jVersion>1.7.28</slf4jVersion>
</properties>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4jVersion}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>${slf4jVersion}</version>
</dependency>
I just did this and the issue was fixed.
Followed the below blog
https://intellij-support.jetbrains.com/hc/en-us/community/posts/206875685-How-to-fix-log4j-WARN-console-messages-when-running-an-Application-inside-IntelliJ-Idea
But here he says like below
To fix that just enter the following log4j.resources file into main/resources folder of your project
instead of creating log4j.resources, create log4j.properties. Right Click on Resource in IntelliJ -> New -> Resource Bundle - Just name it as log4j
If you are having this error on Intellij IDEA even after adding the log4j.properties or log4j.xml file on your resources test folder, maybe the Intellij IDEA is not aware yet about the existence of the file.
So, after add the file, right click on the file and choose Recompile log4j.xml.

Why is the date appended twice on filenames when using Log4Net?

I was trying to add the date to my log file name and I was able to make it work by following the few suggestions I've found in stackoverflow. Everything works fine but for some reason, the first file always has the date appended twice.
For example, instead of log.2009-02-23.log, I get log.2009-02-23.log.2009-02-23.log.
I found it so weird and fyi, this is a very simple code. It's not like I have it running in a multi-threaded environment.
My log4net config:
<log4net>
<appender name="MyLog" type="log4net.Appender.RollingFileAppender">
<file value="../../Logs/Mylog"/>
<staticLogFileName value="false" />
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<datePattern value=".yyyy-MM-dd.lo\g" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{DATE} [%t] %-5p %c - %m%n"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="MyLog"/>
</root>
</log4net>
Any ideas why?
Edit: I want to add the information about the environment I'm testing this in.
- asp.net
- .net framework 2.0
- windows server 2003 64-bit service pack 2
- log4net 1.2.10
This happens if there is a problem accessing the log file when you initialize the log system.
It can happen if you initialize the log system twice, if you run your program while another copy is running and writing to the log file, or if you are editing the log file in a text editor. Basically anything that causes a write lock on the log file when log4net init runs.
Check your code for duplicate calls to log4net init - perhaps you are initializing in a constructor instead of in a singleton's static constructor or global init, for example.
This can also happen if you are running in a 'web garden' configuration and don't include the PID in the filename, because each different web server process tries to write to the same file. If using web gardens and writing to files, add the pid to the filename pattern so each server process gets its own file.
It's a permission problem. At least that's what's happening to me.
I'm new in using Log4Net so I didn't know that it has internal logging but I found it so I tried turning internal logging on.
I wasn't very sure what it's saying but here's what it looks like to me it's doing:
1. Append the date to the file name.
2. Try to access the file to write to it (failed).
3. Append the date to the file name again.
4. Successfully access the file (which has the weird file name now)
Before I know this, I was google-ing for the solution to this problem with keywords like what I have as a title on this stackoverflow question. There wasn't that much information out there. I found maybe one guy who said it happens to some people but never really explained why nor the solution. With this new information (+the internal error message from Log4Net), I was looking at different threads from the search engines. With that I found hints that it might be a permission problem.
It seems that the writing application doesn't have sufficient permission to the logs folder. The default identity of the application is usually NETWORK_SERVICE. After I give more permission (I gave it full control but i don't know what is the minimum to make it work) to the folder, it works just fine.
If anyone can explain this better than me, please feel free to edit.
I run into the same problem. For me, it was a combination of using RollingFileAppender for my test logs, and running my NUnit tests with ReSharper.
It turns out that ReSharper uses two processes to run the tests:
which creates a race condition on the log file.
Now, if we change the log file name to include the process id:
<appender name="MyLog" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="MyLog.pid.%processid" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="false"/>
<datePattern value="_yyyy-MM-dd'.log'"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss.fff} [%15.15t] %-5p '%40.40c' - %m%n" />
</layout>
</appender>
the problem is solved. Each file gets its own, unique name:
MyLog.pid.5440_2010-10-13.log
MyLog.pid.1496_2010-10-13.log
Note the use of PatternString for 'type'.
Hope that helps.
As olle pointed out. your problem is related to the '\g', which your log4net is interpreting as another dateformat.
Try deleting the ".yyyy-MM-dd.lo\g" and replacing it with "yyyy-MM-dd"
The ".log" doesn't belong in the dateformat
I use the following:
<param name="DatePattern" value="yyyy.MM.dd.\l\o\g"/>
With this I get filenames like: 2009.02.23.log
try <datePattern value=".yyyy-MM-dd.lo\g" /> I don't understand what the \g is for.

Resources