Log4j2: Динамично създаване на регистрационни файлове за множество регистрационни файлове

В момента създавам система, която може да има модули (мислете за тях като плъгини), където всеки един от тях може да има свой собствен журнал, предназначен.

Бих искал да използвам проекта log4j2 за регистриране, но изглежда, че имам проблеми с добавящите файлове.

Основният проект (модулът за зареждане и „ядрото“ на цялото нещо) трябва да има свой собствен лог файл, докато модулите трябва да имат свой собствен (като mod_XXXXXXXX.log).

Като прочетох документацията за добавките, открих класа FileAppender и щях да го използвам. Докато не разбрах, че не мога просто да добавя appender към регистратора по подразбиране, създаден от LogManager.getLog().

Регистраторът, върнат от LogManager, е различен от Logger интерфейса.

Дори търсенето не ми даде почти никакво решение, всичко, което намерих, бяха предварително дефинирани файлови регистрационни файлове в xml конфигурацията - което не е това, което искам.

Благодаря ви, че прочетохте; и най-малката следа е добре дошла :)


person spaceemotion    schedule 27.09.2013    source източник


Отговори (3)


ако наистина трябва да определите динамично регистрационния файл, погледнете Log4J2 RoutingAppender. По-дълъг пример е в ЧЗВ и тези въпроси на stackoverflow може представлява интерес: Заместващ шаблон за RoutingAppender на Log4j2 и Как да записвам различни регистрационни файлове в различни файлове с log4j2 ( MDC в xml)?

Обърнете внимание, че трябва да зададете стойности в картата ThreadContext, която RoutingAppender използва, за да реши към кой appender да насочи събитието в журнала. Това означава, че ще трябва да поставите някаква стойност в картата на ThreadContext всеки път, когато вашият код влезе в различен плъгин.

Наистина ли е необходимо обаче да бъде толкова динамичен? Ако знаете предварително какви плъгини имате, можете просто да декларирате регистратор за всеки плъгин (използването на името на пакета на плъгина е често срещан начин за това) и да картографирате всеки такъв регистратор към отделен допълнител.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
  <Appenders>
    <File name="MyFile" fileName="logs/app.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
    <File name="plugin1" fileName="logs/plugin1.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
    <File name="plugin2" fileName="logs/plugin2.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
  </Appenders>
  <Loggers>
    <Logger name="com.mycomp.project.plugin1" level="debug">
      <AppenderRef ref="plugin1" level="debug" />
    </Logger>
    <Logger name="com.mycomp.project.plugin2" level="debug">
      <AppenderRef ref="plugin2" level="debug" />
    </Logger>
    <Root level="trace">
      <AppenderRef ref="MyFile" level="trace" />
    </Root>
  </Loggers>
</Configuration>
person Remko Popma    schedule 28.09.2013
comment
Задължително ли е да се дадат имена на пакети към името на атрибута за регистратор. Ами ако класовете са в различни пакети. Имам нужда от помощ за това, тъй като имам нужда от конкретен дневник на потока. stackoverflow.com/questions/43586574/ - person Tushar Banne; 04.05.2017
comment
Не е задължително, но много хора го правят, защото ви позволява да конфигурирате нивото на журнал за всичко в пакет, което може да бъде полезно. - person Remko Popma; 04.05.2017
comment
добави additivity=false към logger plugin1 и plugin2, въпреки че регистрационните файлове се записват в app.log. Какво ми липсва тук? - person Tushar Banne; 04.05.2017
comment
Открих грешката. ЗАБЕЛЕЖКА: Замених името на пакета съответно с plug1 и plug2. Правеше Logger adminLog = LogManager.getLogger(plug1+Example.class); Вместо Logger adminLog = LogManager.getLogger(plug1); Сега трябва да разберете как да отпечатвате имена на класове в регистрационни файлове. Всяка помощ се оценява. - person Tushar Banne; 04.05.2017

Предполагам, че искате вашият код за управление на модула да дефинира конфигурацията на регистратора, нали? Ако е така, може да искате да погледнете тази част от ръководството, която говори за разширяване на LoggerConfig, което въз основа на това, което питате, е това, което мисля, че търсите.

http://logging.apache.org/log4j/2.x/manual/extending.html

Колкото и да си струва, и преди съм участвал в големи системи, базирани на плъгини (използвайки OSGi) и честно казано не сме поели по този път. Обикновено е по-лесно просто да grep класа или пакета, който ви интересува, от един лог файл.

person babernathy    schedule 27.09.2013

Въпреки че отговорът на Remko Popma може да е най-ефективният начин за регистриране, създадох малък клас, който може сам да създава регистрационни файлове.

Мисля, че ще използвам решението на приетия отговор, така че ето кода, който написах, за да заобиколя нещата с XML файла:

import gnu.trove.map.hash.THashMap;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.apache.logging.log4j.core.async.AsyncLoggerContext;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.message.FormattedMessageFactory;
import org.apache.logging.log4j.message.MessageFactory;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * Represents a manager for custom log files stored inside a log folder.
 */
public class LoggingManager {
    /** The default log file extension */
    public static final String FILE_EXTENSION = "log";

    /** The global context used for all loggers */
    private final LoggerContext context;

    /** The global message factory used for all loggers */
    private final MessageFactory msgFactory;

    /** A map of all created logs */
    private final Map<String, Logger> logCache;

    /** The folder containing the log files */
    private final File logFolder;


    public LoggingManager(String name, File logFolder) throws IOException {
        this.logFolder = logFolder;

        if(!logFolder.exists()) {
            if(!logFolder.mkdirs()) {
                throw new IOException("Could not create log folder");
            }
        }

        this.logCache = new THashMap<String, Logger>();

        // Create logger context
        this.context = new AsyncLoggerContext(name);

        // Create formatted message factory
        this.msgFactory = new FormattedMessageFactory();
    }

    public Logger getLogger(String name) {
        Logger logger = logCache.get(name);

        // Create a new one
        if(logger == null) {
            logger = new SimpleLogger(name);

            FileAppender appender = FileAppender.createAppender(
                    new File(logFolder, name + "." + FILE_EXTENSION).getAbsolutePath(),
                    "true",
                    "false",
                    "file_appender-" + name,
                    "true",
                    "false",
                    "true",
                    PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, null, null, "UTF-8", "true"),
                    null,
                    "false",
                    null,
                    null
            );

            appender.start();
            logger.getContext().getConfiguration().getLoggerConfig("root").addAppender(appender, Level.ALL, null);

            // Add to log cache
            logCache.put(name, logger);
        }

        // Return the logger
        return logger;
    }

    private class SimpleLogger extends Logger {

        public SimpleLogger(String name) {
            super(context, name, msgFactory);

            // Set to all levels
            this.setLevel(Level.ALL);
        }

    }

}

Ако не използвате trove, можете да го замените с нормална java HashMap, ако искате.

person spaceemotion    schedule 30.09.2013
comment
Все пак това отговаря ли на въпроса ›? динамично-създаване-на-лог-файлове? - person Caffeinated; 27.06.2015