log4j2(2.0.1)Async Appender errorRef usage

时间:2015-04-24 09:32:12

标签: logstash log4j2

我们在应用程序中使用log4j2进行消息记录。目前,我们的log4j2配置使用Async Appender,然后引用Socket Appender(protocol =" tcp")将日志写入远程Logstash服务器:

<Socket name="logstash" host="logging" port="4560" protocol="tcp" >
      <LogStashJSONLayout>

        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />

        <KeyValuePair key="tomcat.host" value="${env:HOSTNAME}"/>
        <KeyValuePair key="tomcat.port" value="${env:CONNECTOR_PORT}"/>
        <KeyValuePair key="tomcat.service" value="${web:contextPath}"/>
      </LogStashJSONLayout>       
    </Socket>

    <Async name="async">
        <AppenderRef ref="logstash"/>
    </Async>

我们现在要做的是,修改我们的log4j2配置,以便在Logstash Server不可用的情况下包含一个回退RollingFile Appender,为了实现这一点,我们认为我们将通过以下方式修改Async Appender:

  • 设置&#39; blocking = false&#39;。
  • 设置&#39; ignoreExceptions =&#34; false&#34;&#39;
  • 设置&#39; errorRef&#39;指向我们的后备RollingFile Appender。

这是实现这一目标的明智方式吗?如果是这样,Async Appender的XML会如何?我们尝试了以下方法:

    <RollingFile name="fallbackFile"
        fileName="${sys:catalina.base}/logs/${web:contextPath}-fallback.log" 
        filePattern="${sys:catalina.base}/logs/${web:contextPath}-%d{dd-MMM-yyyy}-%i.log"
        append="true">
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        <Policies>
            <SizeBasedTriggeringPolicy size="1 GB" />
        </Policies>
    </RollingFile>

    <Socket name="logstash" host="logging" port="4560" protocol="tcp" >
      <LogStashJSONLayout>
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        <KeyValuePair key="tomcat.host" value="${env:HOSTNAME}"/>
        <KeyValuePair key="tomcat.port" value="${env:CONNECTOR_PORT}"/>
        <KeyValuePair key="tomcat.service" value="${web:contextPath}"/>
      </LogStashJSONLayout>       
    </Socket>       

    <Async name="async" blocking="false" ignoreExceptions="false" errorRef="fallbackFile">
        <AppenderRef ref="logstash"/>           
    </Async>

但是在Logstash Server节点故意不可用的环境中部署应用程序时出现错误:

2015-04-24 09:55:43,488错误无法在类类org.apache.log4.c..penpen.logpen.log4j.core.appender.SocketAppender中调用元素Socket的工厂方法。 2015-04-24 09:55:43,402 ERROR Null对象为Appenders中的Socket返回。 2015-04-24 09:55:43,407错误没有配置名为logstash的appender 2015年4月24日上午9:55:43 org.apache.catalina.core.StandardContext startInternal SEVERE:ServletContainerInitializer处理时出错javax.servlet.ServletException:失败实例WebApplicationInitializer类在org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:160)在org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5481)在org.apache.catalina.util.LifecycleBase .start(LifecycleBase.java:150)org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)org。 apache.catalina.core.StandardHost.addChild(StandardHost.java:649)org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1081)at org.apache.catalina.startup.HostConfig.deployApps(HostConfig。 java:553)at org.apache.catalina.startup.HostConfig.check(Host Config.java:1668)atg.apache.tomcat上java.lang.reflect.Method.invoke(未知来源)的sun.reflect.DelegatingMethodAccessorImpl.invoke(未知来源)sun.reflect.GeneratedMethodAccessor532.invoke(未知来源)位于org的com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(未知来源)的com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(未知来源)中的.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)。 apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1480)位于org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:709)org.apache.catalina.manager.ManagerServlet.doPut(ManagerServlet。 java:450)在javax.servlet.http.HttpServlet.service(HttpServlet.java:649)的javax.servlet.http.HttpServlet.service(HttpServlet.java:727)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:303)在org.apache.tomc的org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at.websocket.server.WsFilter.doFilter(WsFilter.java:52)在org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)在org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain。 java:208)org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)org.apache.catalina.core .ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)在org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)在org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)在org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:612)org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)org.apache.catalina.valves.ErrorReportValve.invoke( ErrorReportValve.java:103)org.apache.catalina.val ves.AccessLogValve.invoke(AccessLogValve.java:950)org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process(AbstractProtocol.java:611)at org.apache.tomcat.util.net.JIoEndpoint位于org.apache.tomcat.util的java.util.concurrent.ThreadPoolExecutor $ Worker.run(未知来源)的java.util.concurrent.ThreadPoolExecutor.runWorker(未知来源)中的$ SocketProcessor.run(JIoEndpoint.java:314)。 threads.TaskThread $ WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Unknown Source)由sun.reflect的sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)引起的java.lang.ExceptionInInitializerError引起的sun.reflect.DelegatingConstructorAccessorImp中的.NativeConstructorAccessorImpl.newInstance(未知来源) l.newInstance(未知来源)位于org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:157)java.lang.Class.newInstance(未知来源)的java.lang.reflect.Constructor.newInstance(未知来源) ... 42更多引起:org.apache.log中的java.lang.NullPointerException(async.apache.log。) .start(AbstractConfiguration.java:157)org.apache.log4中的org.apache.log4.Core.LoggerContext.setConfiguration(LoggerContext.java:364)。(LoggerContext.java:422) )org.apache.logache.log4j.core.LoggerContext.start(LoggerContext.java:146)org.apache中的org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:75)。 log.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:37)at org.apache.logging.log4j.LogManager.getLogger(LogManager.jav) a:468)atg.apache.logging.log4j.LogManager.getLogger(LogManager.java:403)at com.company.service.config.WebInitialiser。(WebInitialiser.java:21)

我们做错了什么?我们应该使用故障转移Appender吗?

---------更新---------

在进一步测试之后,我可以说上述设置适用于Socket Appender主机可用但不是端口(例如服务不可用)的情况。但它不适用于Socket Appender的主机不可用的情况(例如未知主机)。

现在,为了让fallbackFile Appender在两种情况下工作(服务不可用和未知主机),我在SocketAppender上包含了一个Failover Appender:

    <RollingFile name="fallbackFile"
        fileName="${sys:catalina.base}/logs/${web:contextPath}-fallback.log" 
        filePattern="${sys:catalina.base}/logs/${web:contextPath}-%d{dd-MMM-yyyy}-%i.log"
        append="true">
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        <Policies>
            <SizeBasedTriggeringPolicy size="1 GB" />
        </Policies>
    </RollingFile>

    <Socket name="logstash" host="logging" port="4560" protocol="tcp" >
      <LogStashJSONLayout>
        <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        <KeyValuePair key="tomcat.host" value="${env:HOSTNAME}"/>
        <KeyValuePair key="tomcat.port" value="${env:CONNECTOR_PORT}"/>
        <KeyValuePair key="tomcat.service" value="${web:contextPath}"/>
      </LogStashJSONLayout>       
    </Socket>       

    <Failover name="failover" primary="logstash">
        <Failovers>
            <AppenderRef ref="fallbackFile"/>
        </Failovers>
    </Failover>

    <Async name="async" bufferSize="10" blocking="false" ignoreExceptions="false" errorRef="fallbackFile">
        <AppenderRef ref="failover"/>
    </Async>

这种配置似乎给了我们想要的行为。

任何更清洁/更整洁的解决方案甚至对此配置的评论都是最受欢迎的。

干杯, PM

2 个答案:

答案 0 :(得分:0)

logstash-gelf比log4j2的SocketAppender更有弹性。 AsyncAppenders可以在一定程度上保护应用程序,但仍然可能遇到TCP问题,例如服务不可用,速度慢或连接/重新连接耗费时间。

GELF通过UDP工作,因此如果服务已关闭/无法访问,则不会以任何方式影响您的应用程序性能。唯一可能发生的事情是您可能会丢失日志事件,但是您已经获得了该案例的文件回退。

logstash-gelf配置的完整示例如下:

<Configuration>
    <Appenders>
        <Gelf name="gelf" host="udp:localhost" port="12201" version="1.1" extractStackTrace="true"
              filterStackTrace="true" mdcProfiling="true" includeFullMdc="true" maximumMessageSize="8192"
              originHost="%host{fqdn}">
            <Field name="timestamp" pattern="%d{dd MMM yyyy HH:mm:ss,SSS}" />
            <Field name="level" pattern="%level" />
            <Field name="simpleClassName" pattern="%C{1}" />
            <Field name="className" pattern="%C" />
            <Field name="server" pattern="%host" />
            <Field name="server.fqdn" pattern="%host{fqdn}" />

            <!-- This is a static field -->
            <Field name="fieldName2" literal="fieldValue2" />

            <!-- This is a field using MDC -->
            <Field name="mdcField2" mdc="mdcField2" /> 
            <DynamicMdcFields regex="mdc.*" />
            <DynamicMdcFields regex="(mdc|MDC)fields" />
        </Gelf>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="gelf" />
        </Root>
    </Loggers>
</Configuration>  

此处提供完整文档:http://logging.paluch.biz/

答案 1 :(得分:0)

更新的解决方案是99%好的。

log4j async appender中所指定,必须在套接字附加器上将ignoreExceptions设置为false ,以使其与故障转移附加器一起使用。

在将此Appender包装在FailoverAppender中时,必须将其设置为false。