The application threads get stuck whenever the log file rotates, this causes spike in latency of the API
I'm using an Async Appender, not sure why during rotation the application threads are waiting.
logback.xml
<configuration debug="true">
<property name="async.discardingThreshold" value="0"/>
<property name="async.queueSize" value="500"/>
<property name="log.dir" value="/var/log"/>
<property name="log.pattern" value="%highlight(%-5level) [%date] [%thread] [%X{id}] [%cyan(%logger{0})]: %message%n"/>
<property name="errorLog.pattern" value="%highlight(%-5level) [%date] [%thread] [%X{id}] [%red(%logger{0})]: %message%n"/>
<property name="log.maxHistory" value="200"/>
<property name="log.default.maxFileSize" value="100MB"/>
<property name="log.error.maxFileSize" value="10MB"/>
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.dir}/default.log</File>
<Append>true</Append>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${log.dir}/default.%i.log.gz</fileNamePattern>
<maxIndex>${log.maxHistory}</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.default.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%replace(${log.pattern}){'"pin":"\d+"','"pin":"XXXX"'}%n</pattern>
</encoder>
</appender>
<appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>${async.discardingThreshold}</discardingThreshold>
<queueSize>${async.queueSize}</queueSize>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<OnMismatch>DENY</OnMismatch>
<OnMatch>NEUTRAL</OnMatch>
</filter>
<appender-ref ref="INFO"/>
</appender>
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${log.dir}/error.%i.log.gz</fileNamePattern>
<maxIndex>${log.maxHistory}</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${log.error.maxFileSize}</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%replace(${errorLog.pattern}){'"pin":"\d+"','"pin":"XXXX"'}%n</pattern>
</encoder>
</appender>
<appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>${async.discardingThreshold}</discardingThreshold>
<queueSize>${async.queueSize}</queueSize>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<appender-ref ref="ERROR"/>
</appender>
<root level="INFO">
<appender-ref ref="ASYNC-ERROR"/>
<appender-ref ref="ASYNC-INFO"/>
</root>
In our logback.xml we have specified,
<property name="async.discardingThreshold" value="0"/>
Now a quick look at the source code suggests what possibly might be happening that is causing the delay at the time of rotation
#Override
protected void append(E eventObject) {
if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject)) {
return;
}
preprocess(eventObject);
put(eventObject);
}
private boolean isQueueBelowDiscardingThreshold() {
return (blockingQueue.remainingCapacity() < discardingThreshold);
}
blockingQueue.remainingCapacity() < discardingThreshold, this condition will never evaluate to true if discarding threshold is 0, what that means is the async-appender thread will try to push to an already full blocking queue, hence, will park itself and wait on it causing the application thread to wait as well.
Setting this value to anything above 0, is causing no timeouts, however, some events might get lost.
The other option to keep all the events without any discard would be to increase the queue size as much that at the instant of file rotation, there are no more than the size of the queue element in the queue. In which case, the async-appender thread won't wait on the blocking queue.
So my finding is logback AsyncAppender is NOT so Async if message incoming rate exceeds the queue consumption rate and discarding rate is 0.
Related
I read the official document of log4j2 and get a question about RollingFileAppender.
That's what the document says:
Below is a sample configuration that uses a RollingFileAppender with both the time and size based triggering policies, will create up to 100 archives on the same day (1-100) that are stored in a directory based on the current year and month, and will compress each archive using gzip and will roll every hour. During every rollover, this configuration will delete files that match "/app-.log.gz" and are 30 days old or older, but keep the most recent 100 GB or the most recent 10 files, whichever comes first.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
<DefaultRolloverStrategy max="100">
<!--
Nested conditions: the inner condition is only evaluated on files
for which the outer conditions are true.
-->
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz">
<IfLastModified age="30d">
<IfAny>
<IfAccumulatedFileSize exceeds="100 GB" />
<IfAccumulatedFileCount exceeds="10" />
</IfAny>
</IfLastModified>
</IfFileName>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
I think this configuration will create up to 100 archives on the same hour of the day, not 100 archives on the same day, can anybody who give me a hand? Thanks!
Yes, it will keep up to 100 files in the hour but in reality it will never get that high since it is only keeping a maximum of 10 files overall.
hey I was wondering if it possible to have the same output in Console as in the file output.
Here is my XML config.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" name="log4j2 Logs">
<Properties>
<Property name="basePath">./logs</Property>
</Properties>
<Appenders>
<RollingFile name="file" fileName="${basePath}/ActivateMaintenancePage.logs"
filePattern="${basePath}/ActivateMaintenancePage-%d{yyyy-MM-dd}">
<PatternLayout header="LOGGING START%n%n" footer="%n%nLOGGING END"
pattern="%3sn %30d{DEFAULT} [%M] %-7level %c{30} - %m%n" />
<Policies>
<OnStartupTriggeringPolicy minSize="0"/>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="500 MB"/>
</Policies>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout header="LOGGING START%n%n" footer="%n%nLOGGING END"
pattern="%3sn %30d{DEFAULT} [%M] %-7level %c{30} - %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="console" level="error"/>
<AppenderRef ref="file" level="trace"/>
</Root>
</Loggers>
</Configuration>
Output in RollingFile
1 2017-07-25 11:16:36,762 [initializeChrome] INFO class testNG.SimSettings - Web Chrome driver is now initilized.
2 2017-07-25 11:16:36,762 [lambda$0] INFO class testNG.SimSettings - Opening... http://msrvaq11vm.technomedia.ca/sigal_60/2017sp1/sp_polymont/_sim/PROD Sp2 2016 Sim...
3 2017-07-25 11:16:47,926 [initilizeAllElements] INFO class testNG.SimSettings - All #FindBy elements have been initilized.
4 2017-07-25 11:16:48,006 [change1stLevelFrame] INFO class testNG.SimSettings - Changing target to 1st level frame.
5 2017-07-25 11:16:49,719 [enterCredentials] INFO class testNG.SimSettings - UserName & Password: Success!
and empty in Console. But now if I change
<AppenderRef ref="console" level="error"/>
to "trace"
It will be 2,4,6....in console and in my file it will be 1,3,5,7... which is easily understandable.
But my question is how can we have both the same log-level (trace) output in Console and File?
(adding tag with package name and level did not work)
Related to this question: log4j2 xml configuration - Log to file and console (with different levels)
I'm not sure if I read your question correctly but it seems that you want to render some unique value in the log output, such that the same log event has the same unique value in the Console log and the File log output.
The sequence number pattern converter will increment every time a log event is rendered. The same log event is rendered separately for each Appender, so different Appenders will never have the same sequence number.
There are a number of alternatives. One idea is to include %nano nanotime in the pattern layout. This value is captured when the application makes the logging call and will be the same for all appenders. An alternative is to create a custom Log4j2 pattern converter or lookup.
Can someone tell me, How to configure custom layout for FileAppender?
Can anyone tell me, how to configure custom layout for FileAppender?
I'm created copy of HTMLLayout and made some changes there (it's cannot be extends because it's final class) and now I want use this layout, but I don't know how :(
This error is showed with bellow listed configuration:
ERROR File contains an invalid element or attribute "ibtrader.log4j2.MYHTMLLayout"
Here is my log4j2.xml configuration file
<?xml version="1.0" encoding="UTF-8"?>
<configuration strict="true" monitorInterval="30">
<appenders>
<appender name="Console" type="Console" target="SYSTEM_OUT">
<layout type="PatternLayout" pattern="%highlight{%d{ISO8601} [%t] %-5level %logger{36} - %msg%n}" />
</appender>
<appender name="DEBUG_FILE" type="File" fileName="logs/errors.txt" >
<layout type="PatternLayout" pattern="%d{ISO8601} [%t] %-5level %logger{36} - %msg%n}" />
</appender>
<appender name="HTMLAppender" type="File" fileName="logs/mainlog.html">
<layout type="ibtrader.log4j2.MYHTMLLayout" charset="UTF-8" title="IBTRader logs" locationInfo="true" />
</appender>
</appenders>
<loggers>
<root level="trace">
<appender-ref ref="Console"/>
<appender-ref ref="DEBUG_FILE" level="WARN" />
<appender-ref ref="HTMLAppender" />
</root>
</loggers>
</configuration>
Thanks for help!
The comments mention this is already fixed but just for completeness, a (simplified) configuration with a custom MYHTMLLayout plugin could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- the packages attribute contains a comma-separated list
of the packages that Log4J2 will scan for custom plugins. -->
<configuration packages="ibtrader.log4j2">
<appenders>
<appender name="HTMLAppender" type="File" fileName="logs/mainlog.html">
<!-- Each plugin has a *name*, declared with annotation on the
plugin implementation class.
The plugin name does not need to match the class name.
The plugin name needs to match the *type* attribute in the config.
For example:
package ibtrader.log4j2;
import ...;
#Plugin(name="MYHTMLLayout", category="Core",
elementType="layout", printObject=true)
public class MyHTMLLayoutImpl extends AbstractStringLayout {...
-->
<layout type="MYHTMLLayout" charset="UTF-8" title="IBTRader logs" locationInfo="true" />
</appender>
</appenders>
<loggers>
<root level="trace">
<appender-ref ref="HTMLAppender" />
</root>
</loggers>
</configuration>
You have to extend AbstractStringLayout, setting the #Plugin properties with category = "Core", elementType = "layout" and name="The name of the class itself that should be refered from the configuration file" (i.e.: "ExtHtmlLayout")
You could just copy the whole class HtmlLayout from the sources and change whatever you want, for example, the time in millis column to the time in hours.
Define the package property in "Configuration" tag to use the package to the extended class you have created.
Finally, just call the new layout from the configuration file:
<ExtHtmlLayout/>
I'm using log4j2-beta9 and want to configure it using a log4j2.xml in strict mode.
My issue is: how do I specify attributes that are not in the shipped schema file?
An Example:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration
status="DEBUG"
strict="true"
monitorInterval="5"
name="TestingAttributes"
verbose="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Log4j-config.xsd">
<Properties>
</Properties>
<Appenders>
<Appender
type="Console"
name="SYSERR"
target="SYSTEM_ERR"> <!-- cvc-complex-type.3.2.2: Attribute 'target' is not allowed to appear in element 'Appender'. -->
<Layout Type="PatternLayout">
<Pattern>%date{dd.MM.yyyy HH:mm:ss,SSS} %5p %logger %m%n</Pattern>
</Layout>
<Filters>
<Filter
type="MarkerFilter"
marker="FLOW"
onMatch="DENY"
onMismatch="NEUTRAL" />
<Filter
type="MarkerFilter"
marker="EXCEPTION"
onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
</Appender>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="SYSERR" />
</Root>
</Loggers>
</Configuration>
Notice that I want to set the appender to have the target SYSTEM_ERR but the attribute is not allowed in strict mode.
target="SYSTEM_ERR"> <!-- cvc-complex-type.3.2.2: Attribute 'target' is not allowed to appear in element 'Appender'. -->
I could always edit the Log4j-config.xsd and allow that attribute there but that would be kind of wrong also because not all appenders have a target attribute.
As searching the web didn't help me so far, I'm asking you:
Is there anything I'm missing in configuring Log4j2 in strict XML mode?
Do I have to "patch" the XMLConfiguration and the schema file and commit a change to log4j or is there another way besides not using strict mode?
Thanks in advance.
Can you ask this on the log4j-user mailing list? It could be a bug in the schema, but I suspect the schema can do with more improvements and your feedback would be valuable.
I recently ran into an issue where I'm being reauthenticated every time I launch or bring my web app to the foreground when launching it from the homescreen on iOS (I added it to the homescreen from Safari originally). This does not happen when I'm in Safari directly.
My research has shown that this can be overcome in php by creating/restarting the session and then adding a session cookie as follows:
// Start or resume session
session_start();
// Extend cookie life time by an amount of your liking
$cookieLifetime = 365 * 24 * 60 * 60; // A year in seconds
setcookie(session_name(),session_id(),time()+$cookieLifetime);
Rather than do this programatically, I was wondering if there is a way to do this through the XML configuration. Otherwise, how could I accomplish something similar with Spring Security?
Here is my security-ctx.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
</bean>
<sec:http auto-config="false" entry-point-ref="http403EntryPoint">
<sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</sec:http>
<bean id="siteminderFilter" class=
"org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="x-paas-uid"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="ldapUserDetailsService"/>
</bean>
</property>
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="preauthAuthProvider"/>
</sec:authentication-manager>
<!-- Example using LDAP, but will ultimately use database service -->
<sec:ldap-server id="ldapServer" port="636" root="o=home"
url="ldaps://ldap.home.com"/>
<sec:ldap-user-service id="ldapUserDetailsService" server-ref="ldapServer"
group-search-base="ou=groups,o=home"
role-prefix="ROLE_" group-role-attribute="cn"
user-search-base="ou=people,o=home" user-search-filter="uid={0}"/>
</beans>
As far as I know Spring Security does not manage session timeout value. So there is no way to do it in security xml out of the box. If you want to define this value system wide (for all sessions) then look into your servlet container / application server documentation. In a case of Tomcat you can add following snippet to the web.xml descriptor:
<web-app ....>
.....
<session-config>
<!-- value is in minutes -->
<!-- 60x24x365 -->
<session-timeout>525600</session-timeout>
</session-config>
....
</web-app>