【问题标题】:Too many open files due to log4j config由于 log4j 配置,打开的文件太多
【发布时间】:2017-11-10 06:56:29
【问题描述】:

我们使用的是 log4j 2.5。我的问题是关于 ConferenceLog 所以请忽略下面的其他配置。

log4j2.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
    <Configuration monitorInterval="180">
        <Properties>
            <!-- change the path to conference logs below to fit your system -->
            <Property name="LOG_DIR">C:\CodeRepos\logs</Property>
            <Property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level
                %logger{36} - %msg%n</Property>
        </Properties>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="${PATTERN}" />
            </Console>
            <Routing name="DailyLog">
                <Routes pattern="${ctx:logFileName}">
                    <Route>
                        <RollingFile name="Rolling-${ctx:logFileName}"
                            fileName="${LOG_DIR}/symproxy.log" 
                            filePattern="${LOG_DIR}/symproxy-%i.log">
                            <PatternLayout pattern="${PATTERN}" />
                            <SizeBasedTriggeringPolicy size="20971520" />
                            <DefaultRolloverStrategy max="100" />
                        </RollingFile>
                    </Route>
                </Routes>
            </Routing>
            <Routing name="ConferenceLog">
                <Routes pattern="${ctx:logFileName}">
                    <Route>
                        <RollingFile name="Rolling-${ctx:logFileName}"
                            fileName="${LOG_DIR}/conferences/${ctx:logFileName}.log"
                            filePattern="${LOG_DIR}/conferences/${ctx:logFileName}.%i.log.gz">
                            <PatternLayout pattern="${PATTERN}" />
                            <SizeBasedTriggeringPolicy size="20971520" />
                        </RollingFile>
                    </Route>
                </Routes>
            </Routing>
            <Routing name="DeviceLog">
                <Routes pattern="${ctx:logFileName}">
                    <Route>
                        <RollingFile name="Rolling-${ctx:logFileName}"
                            fileName="${LOG_DIR}/devices/${ctx:logFileName}.log"
                            filePattern="${LOG_DIR}/devices/${ctx:logFileName}.%i.log.gz">
                            <PatternLayout pattern="${PATTERN}" />
                            <SizeBasedTriggeringPolicy size="5kb" />
                            <DefaultRolloverStrategy max="3" />
                        </RollingFile>
                    </Route>
                </Routes>
            </Routing>
        </Appenders>
        <Loggers>
            <Root level="info">
                <AppenderRef ref="Console" />
                <AppenderRef ref="DailyLog" />
            </Root>
            <Logger name="conference.logger" level="debug" additivity="false">
                <AppenderRef ref="ConferenceLog" />
                <AppenderRef ref="Console" />
            </Logger>
            <Logger name="device.logger" level="info" additivity="false">
            </Logger>
        </Loggers>
    </Configuration>

我有一个小包装器,我在其中实例化了这个会议记录器

private final Log conferenceLogger = LogFactory.getLog("conference.logger");

之后就是这样使用

private void logger(Long meetingId, Log log, String className, Level level, String message, Throwable error) {
        ThreadContext.put(LOG_FILE_NAME, String.valueOf(meetingId));
        logger(conferenceLogger, level, className + "." + message, error);
        ThreadContext.remove(LOG_FILE_NAME);
    }

    private static void logger(Log log, Level level, String message, Throwable error) {
        if (level == Level.DEBUG) {
            log.debug(message);
        } else if (level == Level.ERROR) {
            if (error == null) {
                log.error(message);
            } else {
                log.error(message, error);
            }
        } else if (level == Level.FATAL) {
            log.fatal(message);
        } else if (level == Level.TRACE) {
            log.trace(message);
        } else if (level == Level.INFO) {
            log.info(message);
        } else if (level == Level.WARN) {
            log.warn(message);
        }
    }

这会创建一堆以“会议 ID”命名的文件。但是我的问题是这些文件在打开后永远不会关闭。

我阅读了这个similar SO post,但是我没有引用我的FileAppender 来调用close,我也没有Logger 对象,所以我不确定如何实现它的修复。如何以编程方式触发关闭这些文件? 因此,我们的一台服务器出现“打开的文件过多”错误。

在阅读了documentation 之后,似乎 IdlePurgePolicy 应该是我需要的,但我认为它对打开文件的数量没有任何影响。 如果我的 log4j2 文件有几个不同的地方,我尝试了以下行,但正如我所提到的,它没有效果

&lt;IdlePurgePolicy timeToLive="1" timeUnit="minutes"/&gt;

【问题讨论】:

    标签: java file log4j2


    【解决方案1】:

    如果包装器本身不是静态实例化的,则会为每个调用它的对象创建记录器实例。这可能会导致每次都与具体的记录器实例建立新的套接字连接。但是,当您只有一个日志文件时,打开的套接字过多也可能导致此异常。

    可能的解决方案

    1. 静态实例化包装器
    2. 静态实例化记录器引用
    3. 通过静态调用日志记录方法使包装器成为单例

    【讨论】:

    • 我试过#2,所以它是私有静态最终日志会议记录器,但是文件没有关闭。我不确定以上是我的问题。它为各种会议创建多个日志文件,2343.log、3123.log 等。我不希望整个会议记录器只停止一个文件关闭,我什至不知道 log4j2 如何知道关闭文件。但是,使用包装器时,我能够发出特定文件已准备好关闭的信号。
    【解决方案2】:

    IdlePurgePolicy 最终解决了这个问题

    <Routing name="ConferenceLog">
        <Routes pattern="${ctx:logFileName}">
            <Route>
                <RollingFile name="Rolling-${ctx:logFileName}"
                    fileName="${LOG_DIR}/conferences/${ctx:logFileName}.log"
                    filePattern="${LOG_DIR}/conferences/${ctx:logFileName}.%i.log.gz">
                    <PatternLayout pattern="${PATTERN}" />
                    <SizeBasedTriggeringPolicy size="20971520" />
                </RollingFile>
            </Route>
        </Routes>
        <IdlePurgePolicy timeToLive="30" timeUnit="seconds"/>
    </Routing>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-09
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 2011-07-18
      相关资源
      最近更新 更多