Why is log4j2 logger definition lengthy? - log4j

i am upgrading from log4j to log4j2 and new to log4j in general. I am finding it difficult to introduce lengthy loggers for every class file in the log4j2.properties file. For instance, if i had to create a new logger in log4j, it would be as simple as introducing a single line in the log4j.properties file compared to a whole block of properties against the same logger.
Ex:- If i have to add a logger for a class2 in package A, i would simply add it as follows :-
log4j.logger.A.Class1= DEBUG,file
log4j.logger.A.Class2 = DEBUG,file.
I can easily add another logger by simply introducing a third line in the log4j.properties file.
Whereas, if i have to do the same thing, i would have to add the loggers as below :-
loggers=file1,file2
logger.file1.name=A.Class1
logger.file1.level = debug
logger.file1.appenderRefs = file
logger.file1.appenderRef.file.ref = LOGFILE
logger.file2.name=A.Class2
logger.file2.level = debug
logger.file2.appenderRefs = file
logger.file2.appenderRef.file.ref = LOGFILE
So, if i have 100 classes the log4j2.properties file would be quite lengthy. Unlike if i had to do the same thing in log4j. Please note the prefix of file1, file2, etc.
Question is, is there a way i can write the logger the same way as i did in log4j? Or, is there a simpler way to achieve the same?
If above is not possible, i might as well stick to log4j. Cause it becomes a serious trouble for me to create loggers for each class in large projects.
Thanks in advance.

Take a look at the Log4J2 XML configuration file format with which it will suffice to add one single line to configure logging for a class. This provided that you are content with writing all the log to one and the same destination, otherwise more than one line per class may be required.
Example:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration>
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p %-30C - %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="se.ivankrizsan.java.MyClass" level="DEBUG"/>
<Logger name="org.springframework" level="INFO"/>
<Root level="INFO">
<AppenderRef ref="CONSOLE" />
</Root>
</Loggers>
</Configuration>
Note also that you can specify the log-level for entire packages and thus multiple classes at once as with the org.springframework package in the above example.
Reference: Log4J2 XML configuration documentation.

Related

log4net use logger name in appender

I am trying to clean up the logging configuration one of our applications currently uses for it's log4net implementation. The application is called with an argument containing the filepath to an XML file. That XML file includes various configuration information, one of which is the logger name to use.
Currently, every configuration file has it's own logger, and every logger has their own appenders. As an example we would have:
logger job1
logger job2
logger job3
and
appender consoleJob1
appender consoleJob2
appender consoleJob3
appender rollingFileJob1
appender rollingFileJob2
appender rollingFileJob3
appender smtpJob1
appender smtpJob2
appender smtpJob3
Even though each of those appenders have nearly identical configurations. With hundreds of configuration files, this logging configuration section of the app.config is quite large. I believe I can consolidate most of these down to just a handful of generic appenders (Console, rollingFile, smtpToIT, smptpToSupport etc), and change each logger to use the generic appenders.
A big roadblock to how I visualize this working, is that each appender would need to use the logger's name in the configuration somewhere. Is there a variable or setting I can use in an appender that will allow the appender to use the logger's name? For instance, the RollingFileAppender should log to '\log[loggername].txt' The smtpAppender should have a subject of 'Log for [loggername] on MM\DD\YYYY'.
I took a look at http://logging.apache.org/log4net/release/config-examples.html, and believe I understand how the date can be added but I don't see anything about accessing the logger name from within the appender.
Is there anyway to access a property of the logger being used within the appender? Further, am I understanding how log4net is meant to be configured, with appenders being re-used among multiple loggers? I hadn't heard of log4net until a few weeks ago so I might be going about this all wrong.
I found the solution elsewhere, in an answer to a different question. Unfortunately I don't remember where I found it and only came back to my original question because of Newtopian's answer.
You can set a Global property through the following line:
log4net.GlobalContext.Properties["id"] = "SomeText";
Then refer to it in the appender as I did below:
<appender name="NewAuto2ProcessingTestFILE" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="Log/%property{id}NewAuto2ProcessingTest.txt" />
<appendToFile value="true" />
<maxSizeRollBackups value="10" />
<staticLogFileName value="true" />
<datePattern value=".yyyy-MM-dd.\\t\\x\\t" />
<rollingStyle value="Date" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p - %m%n" />
</layout>
</appender>
Was looking for the same thing, unfortunately it seems it's not possible out of the box, check the doc here about the accepted variables in the pattern String.
You'd probably would have to create your own appender, or your own formatter, to gain access to more variables (I suspect both).

why do we need root and logger in log4j.xml

pardon if the question is too trivial. I am completely new to log4j. I have seen that there are two tags and tags, which refer to various appenders.
Say i want to log the information in my code base in a file, send it to my email and print it to console. I want the level set to info. Isnt it enough to have a single tag which has references to the three appenders ?( file, email and the console) why do we need another for the same ?
It is enough.
In log4j a logger is associated with a package or sometimes with a particular class. Package/class of a logger is defined by the attribute "name". A logger logs messages in its package and also in all the child packages and their classes. The only exception is the root logger that logs messages for the all classes in the application.
A logger also has level and may have one or many appenders (logging destinations) attached to it.
In the next example we have two loggers:
the root logger that logs messages with level INFO or above in the all packages to the various destinations: console, e-mail and file,
"com.foo" logger that logs messages with level WARN or above in package "com.foo" and its child packages to the another file.
<log4j:configuration>
<!-- Declaration of appenders FILE, MAIL, CONSOLE and ANOTHERFILE -->
...
<!-- -->
<logger name="com.foo">
<level value="warn"/>
<appender-ref ref="ANOTHERFILE" />
</logger>
<root>
<priority value ="info" />
<appender-ref ref="FILE" />
<appender-ref ref="MAIL" />
<appender-ref ref="CONSOLE" />
</root>
</log4j:configuration>
You should read more about the log4j basics.

Log4j : Interesting Issue and needs solution

My Application is using logging in two manner....1) programatic 2) log4j.xml
I have to create the logs files in two ( 1 using programatic and other using log4j.xml ) locations.
Programatic way ( have one more properties file in which all the things are mention like log level and all....lets say..thorugh this...file is getting created..name as "SAS_VP.log") :
Enumeration loggers = Logger.getRootLogger().getLoggerRepository().getCurrentLoggers();
......
Logger temp = (Logger)iter.next();
temp.setLevel(level);
log4j.xml
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="/LOGS/SAM/SAM_VJ.log"/>
<param name="Threshold" value="DEBUG"/>
<param name="MaxFileSize" value="10000KB"/>
<param name="MaxBackupIndex" value="10"/>
<param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{dd MMM yyyy HH:mm:ss,SSS} [%t] %5p [%F(% M):%L] %m%n"/>
</layout>
</appender>
<root>
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
ISSUE :
Log level which i set programatically overwrite the log level of log4j.xml.Like in log4j.xml is have set the level "Debug" and Programatically I have set the level as "ERROR" then the file (SAM_VJ.log) which is created by log4j.xml only contains ERROR level logs.
How to solve this issue...I want that...my both logging ( programmatic and log4j ) should be indepedent.
Is there anything in log4j in which...if i have set the log level of package "com.sas" is "Debug" then nobody can modify that...something like mutable type
<logger name="com.sam">
<priority value="DEBUG"/>
</logger>
Looking for your suggesstion....
I'm not sure you should really ask for such a functionality.
You're talking about a way to configure the log4j framework, and yes, it supports 3 different ways of configuration:
properties file
xml configuration
programmatically, via your java code
Its ok to me that the programmatic configuration allows to change the configured state of log4j loggers/appenders whatsoever.
Your xml configuration should be loaded during the system startup, and then you apply your java code that overrides the configuration.
If you have a logic of supplying a configuration in Java, why don't you improve your logic and define an error level (from your example) only if you really wish to do it.
Its impossible to configure the same logger to work both with DEBUG level (and up) AND ERROR level (and up).
This is a feature in fact, and not a drawback, since it allows to change the behavior of LOG4j on the running system (without a restart) which is useful for issue tracking.
Of course you can WRAP your loggers so that they won't allow setLevel, but, I really don't see why would you do that.
Hope, this helps
Why not just use two appenders with different log levels instead?You can add levelMax and levelMin params to tell log4j the appender just log those levels.
<param name="LevelMax" value="warn" />
<param name="LevelMin" value="info" />

Enabling log levels in log4net

I'm writing a simple test project to experiment with log4net and I've hit a wall right off the bat. No matter what I do in my config file, the my logger is initialized with all "IsXXXXEnabled" flags set to false. Here is my very simple app.config:
<log4netgroup>
<log4net xsi:noNamespaceSchemaLocation="http://csharptest.net/downloads/schema/log4net.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
<param name="LogName" value="Application" />
<param name="ApplicationName" value="HelloProgram" />
<threshold value="DEBUG"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger - %newline%message" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="EventLogAppender" />
</root>
<logger name="HelloLogger">
<level value="DEBUG" />
<appender-ref ref="EventLogAppender" />
</logger>
</log4net>
</log4netgroup>
Here is the trivial test in Main:
ILog Log = LogManager.GetLogger("HelloLogger");
if(Log.IsErrorEnabled)
Console.WriteLine("The logger is working!");
else
Console.WriteLine("Nope");
The output is "Nope". I tried switching the threshold and level values to "ALL", but nothing changed. This seems so simple, what am I missing to enable everything?
Thanks
Fixed it! I don't know why this call is not mentioned in the log4net manual or why I specifically need it, but adding this assembly to my project enabled all log levels:
[assembly:XmlConfigurator(Watch = true)]
Found here:
How do I configure log4net so that log.IsDebugEnabled is true?
You should configure the root logger:
<root>
<level value="DEBUG" />
<appender-ref ref="EventLogAppender" />
</root>
Any non-root loggers (the ones you create with <logger name="...">) apply only to classes whose namespace-qualified name has the logger name as a prefix. So the logger you have created will only apply to a classes that is outside of a namespace and whose name is HelloLogger, or to any classes residing in a namespace called HelloLogger (and possibly within namespaces nested inside that one). (When I say that a logger "applies to" a class X, I mean that that that's the logger you will get when you call LogManager.GetLogger(typeof(X)).)
Edit: You also need to call log4net.Config.XmlConfigurator.Configure(); in order to get log4net to read App.config. Also, delete the outermost <log4netgroup> element and rename the config section name: <section name="log4net" .../>.
Configuring the root logger is not strictly necessary, but the argument of Aasmund is certainly valid. I think the problem is that you try to use the EventLogAppender. For simple tests you should use the ConsoleAppender as this is probably the simplest appender that you can make work in a console application.
The EventLogAppender requires some additional steps to setup: You need to create an event source and that requires administrative rights. The Appender attempts to do this on the fly, but it usually fails silently if UAC is turned on. To see if that is a problem you can try to turn on internal debugging.
Usually you would create an event source with an installation program.
If you are using a separate configuration file for log4net, do this: after following all the other setup instructions, make sure that u right click on the file in the visual studio solution explorer, select properties, expand the "Advanced" option group, set the "Copy To Output Directory" value as "Copy always". That will do the magic... :) cheers!!

Using Logger Filter with Not Equal condition Log4net

I am using log4net in my c# application i have different logger which insert text lines in my single log file.
But now i wanted to add a new logger which should not post log entries in the same file rather i should log in a different file so i configured a new fileAppender, After doing whatever i found on the net i am able to create a different file for my new logger but it echoes the same value in first log file too.
so please if anybody knows about the use of LogFilters so that i could add "Logger <> New logger " match in previously configured appender.
Regards
Mubashar
Assuming you have your "special" logger like this:
ILog logger1 = LogManager.GetLogger("namespace.special_class");
then you can configure log4net as follows:
<logger name="namespace.special_class" additivity="false">
<appender-ref ref="RollingFileAppender4SpecialMessages" />
</logger>
<root>
<level value="ALL" />
<appender-ref ref="StandardRollingFileAppender" />
</root>
This way your special class will use its own file appender. If you need the log messages from this class in your normal log file, then you need to remove the "additivity" attribute.

Resources