How to populate custom field value for logback? - spring-logback

I am trying to write one custom starter in sprintboot for logging. So that all downstream project can follow the same pattern of logging on adding starter in class path.
For this I am trying to create one logback.xml file and using LogstashEncoder.
In this project I am using sleuth and zipking also so that I can see the traceId and spanId.
Following is the logback.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/console.xml"/>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} %5p [Orders:%thread:%X{X-B3-TraceId}:%X{X-B3-SpanId}] %logger{40} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="fileout"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>c:/elk/orders4.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<maxIndex>8</maxIndex>
<FileNamePattern>./logs/orders.log.%i
</FileNamePattern>
</rollingPolicy>e
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>128MB</MaxFileSize>
</triggeringPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"tenantId":"log-odyssey"}</customFields>
</encoder>
</appender>
<root level="info">
<appender-ref ref="fileout" />
<appender-ref ref="stdout" />
</root>
</configuration>
Now If you will see in RollingFileAppender I am using one custom field with hardcode value.
I want to populate its value dynamically from http request. as tenantId will be resolved from request itself.
Can someone help me to solve this issue how I can populate custom fields value dynamically.

Create a Servlet Filter that retrieves the tenantId from the request and populates the tenantId property in the logback MDC. LogstashEncoder will automatically include all properties from the MDC in the JSON output for a log event. You don't even need to define a custom field in xml.

Related

Is there a way to exclude a project from being logged?

I have an app where sometimes I'd like to log in Debug mode. Unfortunately i link with a third party lib that I can't rebuild. It was built to use log4net and on the Debug mode it is very verbose.
I don't want to get any notifications from that library. I do however want to get log notifications from all other code that wants to write.
Is there a way to exclude a namespace or library from logging when using either the SMTPAppender or RollingFile Appender writers?
You could use a filter, e.g.
<filter type="log4net.Filter.LoggerMatchFilter">
<!-- allows this sub-namespace to be logged... -->
<loggerToMatch value="Noisy.Namespace.But.Important" />
</filter>
<filter type="log4net.Filter.LoggerMatchFilter">
<!-- ...but not the rest of it -->
<loggerToMatch value="Noisy.Namespace" />
<acceptOnMatch value="false" />
</filter>
More details from this article.
Im imagine that you are using a configuration where you set only the root level of your logging infrastructure:
<root>
<level value="DEBUG" />
<appender-ref ref="A1" />
</root>
However it is possible to define other levels of logging using the logger names. If you or the third party app followed standard practices, your loggers are named after the class they live with its namespace, so you will have loggers called
MyApp.Main
MyApp.Business
MyApp.Business.Messages
ThirdParty.API
etc...
What you can do in this case is declare the logging at the namespace level you're interested in. For example to log only what lives under MyApp.Main add the following
<logger name="MyApp.Main">
<level value="DEBUG" />
<appender-ref ref="A1" />
</logger>
and remove any appender from the root level. Then you only log the loggers that live under the MyApp name. See the documentation for more info.
If you are unlucky and the loggers don't conform to this hierarchy, you can still filter them out by using a LoggerMatchFilter in your appender; this lets you either define what logger can pass, or what loggers cannot. There are lots of filters, feel free to explore them

log4net creates 2 log files instead of expected one, when log4net is configure both in mine and 3rd party dll

I have 2 projects in my solution, both of class library type.
Actions: Project which contains actions, written using White (UI automation framework over MS UI Automation)
Tests: Project with test fixtures and test methods, using MbUnit
I decided to add logging using log4net for both projects. The log4net configuration I'm using is below:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString"
value="c:/AutomationLog/Automation_%date{dd.MM.yy_HH.mm.ss}.log" />
<appendToFile value="false" />
<rollingStyle value="Once" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="10MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date{HH:mm:ss,fff} %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingLogFileAppender" />
</root>
<logger name="root">
<level value="OFF" />
</logger>
</log4net>
I would like that one file is created each run (one per fixture suite run). But two files are created:
Automation_27.01.13_07.33.53.log
Automation_27.01.13_07.33.53.log.1
After investigation I found that log is spitted into 2nd file each time in the same place -- when actions contain types from White is called. Looks like it happens due to White also uses log4net internally.
So, I guess, situation is like this:
I have a class which initializes log4net
I start the fixtures suite
In the tests project there is a class which runs 1st, which contains Log.Info("...")
log file is created
text is appended until..
1st action which references White's types is run from tests project
At this stage a new file is created
I guess it happens because of inside White Dlls there is another call to initialize log4net, it is hard coded inside
Any idea how to prevent log splitting without modifying the code of White (3rd party dlls)?
I have solved the problem by just renaming the config file, white looks for log4net.config name. But I still haven't got the answer - is it possible how to force log4net to be initialized just once, and skip future attempts.

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!!

How do I configure log4j to start with some text and end with some text?

I'd like to make a log4j output file that is XML and give it a root element.
Hence, I'd like it to start with a tag and end with a tag.
What do I put in my log4j.xml to make this happen?
Right now, all I have is this:
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/file.log" />
<param name="Append" value="false" />
<param name="MaxFileSize" value="5000KB" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n" />
</layout>
</appender>
Change that PatternLayout to an org.apache.log4j.xml.XMLLayout.
Have a look at the api of XMLLayout:
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/XMLLayout.html
It clearly explains that you need to include the resulting xml output within another document (by using xml entity). So in your parent document you can place a root element of your choice.
This will also allow you to use chain saw.

Resources