【问题标题】:log4j2 (2.0.1) Async Appender errorRef usagelog4j2 (2.0.1) Async Appender errorRef 使用
【发布时间】:2015-07-02 20:10:29
【问题描述】:

我们在应用程序中使用 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 服务器不可用的情况下包含一个备用 RollingFile Appender,为了实现这一点,我们考虑通过以下方式修改 Async Appender:

  • 设置 'blocking=false'。
  • 设置 'ignoreExceptions="false"'
  • 将“errorRef”设置为指向我们的备用 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,688 错误无法为元素 Socket 调用类 org.apache.logging.log4j.core.appender.SocketAppender 中的工厂方法。 2015-04-24 09:55:43,702 错误为附加程序中的套接字返回空对象。 2015-04-24 09:55:43,707 错误没有配置名为 logstash 的附加程序 2015 年 4 月 24 日上午 9:55:43 org.apache.catalina.core.StandardContext startInternal 严重:ServletContainerInitializer 处理 javax.servlet.ServletException 期间出错:失败在 org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5481) 在 org.apache.catalina.util.LifecycleBase 的 org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:160) 实例化 WebApplicationInitializer 类.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) 在 org.apache.catalina.startup.HostConfig.deployApps(HostConfig. java:553) 在 org.apache.catalina.startup.HostConfig.check(Host Config.java:1668) 在 sun.reflect.GeneratedMethodAccessor532.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.tomcat .util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(Unknown Source) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(Unknown Source) at org. apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1480) 在 org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:709) 在 org.apache.catalina.manager.ManagerServlet.doPut(ManagerServlet.deploy(ManagerServlet.java:709) java:450) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:649) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.tomc 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) at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at 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) 在 org.apache.tomcat.util.net.JIoEndpoint $SocketProcessor.run(JIoEndpoint.java:314) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at org.apache.tomcat.util。 thread.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Unknown Source) 原因:sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect 的 java.lang.ExceptionInInitializerError .NativeConstructorAccessorImpl.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImp l.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at java.lang.Class.newInstance(Unknown Source) at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:157) ... 42 更多原因:org.apache.logging.log4j.core.config.AbstractConfiguration 的 org.apache.logging.log4j.core.appender.AsyncAppender.start(AsyncAppender.java:108) 的 java.lang.NullPointerException .start(AbstractConfiguration.java:157) 在 org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:364) 在 org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:422 ) 在 org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:146) 在 org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:75) 在 org.apache。 logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:37) 在 org.apache.logging.log4j.LogManager.getLogger(LogManager.jav a:468) 在 org.apache.logging.log4j.LogManager.getLogger(LogManager.java:403) 在 com.company.service.config.WebInitialiser.(WebInitialiser.java:21)

我们做错了什么?我们是否应该改用 Failover Appender?

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

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

现在,为了让 fallbackFile Appender 在两种情况下(服务不可用和未知主机)都能正常工作,我在我们的 SocketAppender 上包含了一个故障转移 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>

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

任何更清洁/更整洁的解决方案,甚至此配置上的 cmets 都将受到欢迎。

干杯, 下午

【问题讨论】:

    标签: logstash log4j2


    【解决方案1】:

    logstash-gelf 比 log4j2 的 SocketAppender 更有弹性。 AsyncAppender 可以在一定程度上保护应用程序,但您仍然可能会遇到 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/

    【讨论】:

      【解决方案2】:

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

      log4j async appender 中所述,socket appender 上的 ignoreExceptions 必须设置为 false,才能与故障转移 appender 一起使用。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多