SLF4J - вход в разные файлы на основе тега - PullRequest
0 голосов
/ 12 марта 2020

У меня есть требование, при котором мне нужно создавать файлы журналов таким образом, чтобы все журналы, основанные на теге (предпочтительно текст), должны регистрироваться в соответствующих файлах журналов.

Например,

У меня есть журналы, касающиеся яблок, апельсинов и манго.

logger.info("Apples: They are red in color");
logger.info("Oranges: They are orange in color");
logger.info("Mangoes: They are yellowish in color");

Согласно моему требованию, первый журнал должен быть зарегистрирован в Apples.log , второй в Апельсины .log и третий к Mangoes.log

Файлы журнала должны создаваться динамически.

Ниже показан мой logback. xml file

    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>
                %d %-5p - %marker%m%n
            </Pattern>
        </encoder>
    </appender>
  <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator>
      <key>fruitName</key>
      <defaultValue>Common_logs</defaultValue>
    </discriminator>
    <sift>
      <appender name="FILE-${instanceName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>./Logs/${fruitName}/${instanceName}.log</fileNamePattern>
            <maxHistory>50</maxHistory>
            <cleanHistoryOnStart>false</cleanHistoryOnStart>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>%d %-5p - %m%n</pattern>
        </encoder>
        </appender>
    </sift>
  </appender>

  <logger name="AssetInstanceService" level="info" additivity="false">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
    <appender-ref ref="SIFT" />
  </logger>

  <root level="info">
    <appender-ref ref="SIFT" />
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
  </root>
</configuration>

Ниже приведен мой LogManager. java file

package Data;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;

public class LogManager {

    static String configFile = "./logback.xml";

    private static Logger _logger = LoggerFactory.getLogger(LogManager.class);
    private static boolean _isInitialized = false;

    private LogManager() {

    }

    public static Logger Instance() {
        if (_logger == null) {
            _logger = LoggerFactory.getLogger(LogManager.class);
        }
        return _logger;
    }

    public static Logger Instance(String instanceName) {
        if (!_isInitialized) {
            if (!CommonMethods.CheckFileExist(configFile)) {
                configFile = "../logback.xml";
                if (!CommonMethods.CheckFileExist(configFile)) {
                    return null;
                }
            }
            LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
            JoranConfigurator configurator = new JoranConfigurator();
            lc.reset();
            configurator.setContext(lc);
            try {
                configurator.doConfigure(configFile);
                MDC.put("fruitName", instanceName);
            } catch (JoranException e) {
                System.out.println(e);
            }
            _isInitialized = true;
        }
        if (_logger == null) {
            _logger = LoggerFactory.getLogger(LogManager.class);
        }
        return _logger;
    }
}

Здесь мои журналы создаются, когда файл jar запускается как Я инициализирую регистратор в своем основном методе.

Но мне нужно, чтобы разные файлы журналов создавались с разными именами на основе тега или идентификатора в журнале.

Ответы [ 2 ]

1 голос
/ 14 марта 2020

SLF4J и Log4j-API предоставляют маркеры для того, что вы хотите. В SLF4J вы можете создавать свои маркеры с:

Marker apples = MarkerFactory.getMarker("Apples");
Marker oranges = MarkerFactory.getMarker("Oranges");
Marker mangos = MarkerFactory.getMarker("Mangos");

Кроме того, у маркеров может быть родитель, поэтому вы можете сделать:

Marker fruit = MarkerFactory.getMarker("Fruit");
Marker apples = MarkerFactory.getMarker("Apples");
apples.add(fruit);
Marker oranges = MarkerFactory.getMarker("Oranges");
apples.add(fruit);
Marker mangos = MarkerFactory.getMarker("Mangos");
apples.add(fruit);

В конфигурации вы можете либо проверить указать c Маркер или если вы хотите проверить все Маркеры, которые являются Фруктами, вы бы проверили этот Маркер.

Затем вы используете маркеры в своем приложении как:

logger.info(apples, "They are red in color");
logger.info(oranges, "They are orange in color");
logger.info(mangoes, "They are yellowish in color");

Наконец, в вашей конфигурации вы можете использовать турбо-фильтр для:

  <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
    <Marker>Apples</Marker>
    <OnMatch>NEUTRAL</OnMatch>
    <OnMismatch>DENY</OnMismatch>
  </turboFilter>

для фильтрации на глобальном уровне или вы можете использовать один из фильтров оценщика для фильтрации в Appender. Вы также можете использовать SiftingAppender для динамического создания приложений, если вы пишете пользовательский дискриминатор.

С API Log4j все немного проще. Чтобы создать маркер без родителя:

Marker apples = MarkerManager.getMarker("Apples");
Marker oranges = MarkerManager.getMarker("Oranges");
Marker mangos = MarkerManager.getMarker("Mangos");

или с родителем:

Marker fruit = MarkerManager.getMarker("Fruit");
Marker apples = MarkerManager.getMarker("Apples").setParents(fruit);
Marker oranges = MarkerManager.getMarker("Oranges").setParents(fruit);
Marker mangos = MarkerManager.getMarker("Mangos").setParents(fruit);

Код для их использования в Log4j точно такой же:

logger.info(apples, "They are red in color");
logger.info(oranges, "They are orange in color");
logger.info(mangoes, "They are yellowish in color");

Большая разница в конфигурации. Log4j имеет только один вид фильтра, и его можно использовать на глобальном уровне (например, турбо-фильтр), либо в журнале, справочнике Appender или в Appender. В вашем случае вы захотите использовать MarkerFilter :

<MarkerFilter marker="Apples" onMatch="NEUTRAL" onMismatch="DENY"/>

и добавить это либо к каждой ссылке на Appender, либо к каждому Appender.

Аналогично SiftingAppender Log4j также предоставляет RoutingAppender . Он использует поиск, чтобы определить, как выполнить маршрутизацию. Из коробки Log4j не предоставляет один для извлечения данных из события журнала, но было бы просто написать один или добавить один в Log4j , или вы можете использовать скрипт для извлечения маркера из события .

Вы должны знать, что использование MarkerFilters сопряжено с некоторыми издержками, хотя и незначительными. Вот тест из модуля log4j-perf при запуске 4 потоков на моем MacBook Pro. Даже в худшем случае, когда Logback проверяет наличие родительского маркера по отношению к событию, содержащему дочерний маркер, каждое сравнение в среднем занимает всего 17 наносекунд.

Benchmark                                  Mode  Cnt   Score   Error  Units
MarkerFilterBenchmark.baseline             avgt   10   2.412 ± 0.088  ns/op
MarkerFilterBenchmark.log4jParentMarker    avgt   10   8.337 ± 0.186  ns/op
MarkerFilterBenchmark.log4jSimpleMarker    avgt   10   8.043 ± 0.145  ns/op
MarkerFilterBenchmark.log4jTooFine         avgt   10   2.825 ± 0.281  ns/op
MarkerFilterBenchmark.logbackParentMarker  avgt   10  17.865 ± 0.533  ns/op
MarkerFilterBenchmark.logbackSimpleMarker  avgt   10  10.471 ± 0.089  ns/op
MarkerFilterBenchmark.logbackTooFine       avgt   10   4.255 ± 0.014  ns/op

Последняя мысль. Ceki Gulcu изобрел концепцию Markers, когда создал SLF4J, и он заслуживает похвалы за это, поскольку это была фантастическая идея c.

0 голосов
/ 17 марта 2020

Динамическое создание RollingFileAppenders и добавление фильтров для каждого аппендера.

package zinit;

import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.spi.FilterReply;

public class main {

    private static Logger logger = (Logger) LoggerFactory.getLogger(main.class);

    public static void main(String[] args) {

        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        String[] fruitList = { "Apple", "Orange", "Mango" };
        Marker apple = null;
        Marker orange = null;
        Marker mango = null;

        for (String instanceName : fruitList) {

            String fileName = "./Logs/" + instanceName + "/" + instanceName + "_%d{yyyy-MM-dd}-%i.log";
            apple = MarkerFactory.getMarker("Apple");
            orange = MarkerFactory.getMarker("Orange");
            mango = MarkerFactory.getMarker("Mango");
            logger = RollingFile(lc, fileName, instanceName);
        }

        for (int i = 0; i < 10000; i++) {

            logger.info(apple, "Apple is red");
            logger.info(apple, "An apple a day keeps the doctor away");
            logger.info(orange, "Oranges are orange");
            logger.info(orange, "Orange is a fruit and a color");
            logger.info(mango, "Mango is yellowish");
            logger.info(mango, "Color of mango is very much variying");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static Logger RollingFile(LoggerContext loggerContext, String filePath, String instanceName) {

        RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<>();
        rollingFileAppender.setName("ROLLINGFILE-" + instanceName);
        rollingFileAppender.setContext(loggerContext);

        TimeBasedRollingPolicy<ILoggingEvent> timeBasedRollingPolicy = new TimeBasedRollingPolicy<>();
        timeBasedRollingPolicy.setContext(loggerContext);
        timeBasedRollingPolicy.setMaxHistory(3);
        timeBasedRollingPolicy.setCleanHistoryOnStart(false);
        timeBasedRollingPolicy.setFileNamePattern(filePath);
        timeBasedRollingPolicy.setParent(rollingFileAppender);
        timeBasedRollingPolicy.start();

        SizeAndTimeBasedFNATP<ILoggingEvent> sizeAndTimeBasedFNATP = new SizeAndTimeBasedFNATP<>();
        sizeAndTimeBasedFNATP.setContext(loggerContext);
        sizeAndTimeBasedFNATP.setMaxFileSize("10KB");
        sizeAndTimeBasedFNATP.setTimeBasedRollingPolicy(timeBasedRollingPolicy);
        sizeAndTimeBasedFNATP.start();

        timeBasedRollingPolicy.setTimeBasedFileNamingAndTriggeringPolicy(sizeAndTimeBasedFNATP);
        timeBasedRollingPolicy.start();

        rollingFileAppender.setRollingPolicy(timeBasedRollingPolicy);

        PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
        patternLayoutEncoder.setContext(loggerContext);
        patternLayoutEncoder.setPattern("%d %-5p - %m%n");
        patternLayoutEncoder.start();
        Filter filter = new Filter() {

            @Override
            public FilterReply decide(Object obj) {
                if (!isStarted()) {
                    return FilterReply.NEUTRAL;
                }
                LoggingEvent event = (LoggingEvent) obj;
                if (event.getMarker().getName().equals(instanceName)) {
                    return FilterReply.NEUTRAL;
                } else {
                    return FilterReply.DENY;
                }
            }

        };
        filter.start();
        rollingFileAppender.addFilter(filter);
        rollingFileAppender.setEncoder(patternLayoutEncoder);

        rollingFileAppender.start();

        logger.addAppender(rollingFileAppender);
        logger.setLevel(Level.DEBUG);
        logger.setAdditive(false);
        return logger;
    }

}
...