log4j2 — Может ли одно приложение управлять более чем 1 файлом «одновременно»?

#java #logging #log4j2 #mdc #threadcontext

#java #ведение журнала #log4j2 #mdc #threadcontext

Вопрос:

Я хочу создать приложение, которое регистрирует каждое действие пользователя в отдельный файл для каждого пользователя, используя MDC / ThreadContext для сохранения имени пользователя и последующего использования его для присвоения имени файлу.

Таким образом, для пользователя 1 у нас будет «web_debug_user1_yyyy-MM-DD», для пользователя 2 «web_debug_user2_yyyy-MM-DD».

Эти пользователи могут войти в приложение одновременно.

Вот соответствующая часть конфигурации:

 <Properties>
        <Property name="logPath">/data/logs</Property>
        <Property name="rollingFileName">web_debug</Property>
        <Property name="rollingFileNameError">web_Error</Property>
        <Property name="patternLog">%d %-5p [%c] %m [SID: %X{sessionId}]%n</Property>
        <Property name="patternLogUser">%d %-5p amp;<%X{userId}amp;>amp;<%X{customerID}amp;>amp;<%X{oid}amp;> [%c] %m [SID: %X{sessionId}]%n</Property>
    </Properties>
<Appenders>
<RollingFile name="rollingFileUser"
    filePattern="${logPath}/${rollingFileName}_${ctx:userId}%d{yyyy-MM-dd}_%i.txt">
    <PatternLayout pattern="${patternLogUser}" />
    <Policies>
        <UserLoggingTriggerPolicy />
        <TimeBasedTriggeringPolicy interval="1"/>
    </Policies>
    <DirectWriteRolloverStrategy />
</RollingFile>
 

А вот пользовательская политика UserLoggingTriggeringPolicy, которая устанавливает свойство fileName для менеджера каждый раз, когда запускается пользовательское событие.

 @Plugin(name = "UserLoggingTriggerPolicy", category = "Core")
public class UserLoggingTriggerPolicy implements TriggeringPolicy {

private RollingFileManager manager;
private String typelog;
private File[] debugFilesUser;

@Override
public void initialize(RollingFileManager manager) {
    this.manager = manager;
    this.typelog = manager.getFileName().contains("debug") ? "debug" : "Error";
    this.debugFilesUser = null;
}

@Override
public boolean isTriggeringEvent(LogEvent arg0) {
    return isRolling();
}

public boolean isRolling() {
    boolean roll = false;
    if (!this.manager.getFileName().contains(MDC.get("userId"))) {
        ((DirectFileRolloverStrategy) manager.getRolloverStrategy()).clearCurrentFileName();
        ((DirectFileRolloverStrategy) manager.getRolloverStrategy()).getCurrentFileName(manager);
    }
    File f = new File(this.manager.getFileName());
    File folder = new File(f.getParent());
    if (debugFilesUser == null) {
        getFiles(folder);
    }
    if ((debugFilesUser.length != 0 amp;amp; debugFilesUser[debugFilesUser.length - 1].length() / 1024 / 1024 > 10)
            || !f.exists()) {
        debugFilesUser = null;
        roll = true;
    }

    return roll;
}

private void getFiles(File folder) {
    debugFilesUser = folder.listFiles(new FilenameFilter() {

        @Override
        public boolean accept(File dir, String name) {
            if (name.contains(MDC.get("userId")) amp;amp; name.contains(typelog)) {
                return true;
            }
            return false;
        }
    });
}

@PluginFactory
public static UserLoggingTriggerPolicy createPolicy() {
    return new UserLoggingTriggerPolicy();
}

}
 

Дело в том, что кажется недостаточным изменить имя файла FileManager, учитывая, что он по-прежнему указывает на один и тот же выходной поток, таким образом регистрируя все разные сообщения пользователя в файл, принадлежащий первому зарегистрированному пользователю в приложении. После некоторой отладки выяснилось, что OutputStream изменяется только при 2 обстоятельствах: инициализации FileManager и ролловера. Затем принудительное переключение в пользовательской политике при изменении текущего пользователя, но в итоге после каждого рулона создавался новый файл, а не запись в ранее существовавшие, поэтому в течение 10 минут было около 20-30 разных файлов.

Итак, вопрос (ы): есть ли какой-либо способ заставить приложение использовать предыдущий файл, скажем, «для отката», а не только создавать новый?

Был ли мой подход неправильным?

Спасибо.

Комментарии:

1. Вероятно, вам следует изучить приложение RoutingAppender

2. Да, также пробовал что-то вроде следующего, но столкнулся с той же проблемой. <Имя маршрутизации =»Маршрутизация»> <Шаблон маршрутов =»$${ctx:userId}»> <Имя файла RollingFile=»rollingFileUser» FilePattern=»${Путь к журналу}/${Имя файла rollingFileName}_$${ctx:userId}%d{гггг-ММ-дд}_%i.txt «> <PatternLayout pattern=»${patternLogUser}» /> <Policies> <UserLoggingTriggerPolicy /> <TimeBasedTriggeringPolicy interval=»1″/> </Policies> <DirectWriteRolloverStrategy /> </RollingFile> </Routes </Routing> В любом случае спасибо.