SLF4J - 根据标签记录到不同的文件

Abh*_*h.M 4 java logging log4j logback slf4j

我有一个要求,其中我需要创建日志文件,以便基于标签(最好是文本)的所有日志都需要记录到相应的日志文件中。

例如,

我有关于苹果、橙子和芒果的日志。

logger.info("Apples: They are red in color");
logger.info("Oranges: They are orange in color");
logger.info("Mangoes: They are yellowish in color");
Run Code Online (Sandbox Code Playgroud)

根据我的要求,第一个日志应记录到Apples.log,第二个日志记录到Oranges.log,第三个日志记录到Mangoes.log

日志文件应该动态创建。

下面显示的是我的logback.xml文件

    <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>
Run Code Online (Sandbox Code Playgroud)

下面给出的是我的LogManager.java文件

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里,当我在 main 方法中初始化记录器时运行 jar 文件时,会创建我的日志。

但我的需要是根据日志中的标签或 id 使用不同的名称创建不同的日志文件。

rgo*_*ers 9

SLF4J 和 Log4j-API 都提供标记来完成您想要的操作。在 SLF4J 中,您可以使用以下命令创建标记:

\n\n
Marker apples = MarkerFactory.getMarker("Apples");\nMarker oranges = MarkerFactory.getMarker("Oranges");\nMarker mangos = MarkerFactory.getMarker("Mangos");\n
Run Code Online (Sandbox Code Playgroud)\n\n

此外,标记可以有一个父级,因此您可以执行以下操作:

\n\n
Marker fruit = MarkerFactory.getMarker("Fruit");\nMarker apples = MarkerFactory.getMarker("Apples");\napples.add(fruit);\nMarker oranges = MarkerFactory.getMarker("Oranges");\napples.add(fruit);\nMarker mangos = MarkerFactory.getMarker("Mangos");\napples.add(fruit);\n
Run Code Online (Sandbox Code Playgroud)\n\n

在配置中,您可以检查特定标记,或者如果您想检查属于水果的所有标记,则可以检查该标记。

\n\n

然后,您可以在应用程序中使用这些标记:

\n\n
logger.info(apples, "They are red in color");\nlogger.info(oranges, "They are orange in color");\nlogger.info(mangoes, "They are yellowish in color");\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,在您的配置中,您可以使用涡轮过滤器来执行以下操作:

\n\n
  <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">\n    <Marker>Apples</Marker>\n    <OnMatch>NEUTRAL</OnMatch>\n    <OnMismatch>DENY</OnMismatch>\n  </turboFilter>\n
Run Code Online (Sandbox Code Playgroud)\n\n

在全局级别进行过滤,或者您可以使用评估器过滤器之一在 Appender 上进行过滤。如果您编写自定义鉴别器,您还可以使用SiftingAppender动态创建 Appender。

\n\n

使用 Log4j API 会使事情变得更容易一些。要创建没有父级的标记:

\n\n
Marker apples = MarkerManager.getMarker("Apples");\nMarker oranges = MarkerManager.getMarker("Oranges");\nMarker mangos = MarkerManager.getMarker("Mangos");\n
Run Code Online (Sandbox Code Playgroud)\n\n

或与家长一起:

\n\n
Marker fruit = MarkerManager.getMarker("Fruit");\nMarker apples = MarkerManager.getMarker("Apples").setParents(fruit);\nMarker oranges = MarkerManager.getMarker("Oranges").setParents(fruit);\nMarker mangos = MarkerManager.getMarker("Mangos").setParents(fruit);\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 Log4j 中使用它们的代码完全相同:

\n\n
logger.info(apples, "They are red in color");\nlogger.info(oranges, "They are orange in color");\nlogger.info(mangoes, "They are yellowish in color");\n
Run Code Online (Sandbox Code Playgroud)\n\n

最大的区别在于配置。Log4j 只有一种 Filter,它可以在全局级别(如 Turbo Filter)或 Logger、Appender 引用或 Appender 上使用。在您的情况下,您需要使用MarkerFilter

\n\n
<MarkerFilter marker="Apples" onMatch="NEUTRAL" onMismatch="DENY"/>\n
Run Code Online (Sandbox Code Playgroud)\n\n

并将其添加到每个 Appender 引用或每个 Appender。

\n\n

与 SiftingAppender 类似,Log4j 也提供了RoutingAppender。它使用查找来确定如何执行路由。开箱即用的 Log4j 不提供从日志事件中检索数据的方法,但编写一个或向 Log4j 添加一个很简单,或者您可以使用脚本从事件中检索标记。

\n\n

您应该意识到使用 MarkerFilters 会产生一些开销,尽管不多。这是在我的 MacBook Pro 上运行 4 个线程时 log4j-perf 模块的基准测试。即使在最坏的情况下,Logback 根据包含子标记的事件检查父标记,每次比较平均仍然只需要 17 纳秒。

\n\n
Benchmark                                  Mode  Cnt   Score   Error  Units\nMarkerFilterBenchmark.baseline             avgt   10   2.412 \xc2\xb1 0.088  ns/op\nMarkerFilterBenchmark.log4jParentMarker    avgt   10   8.337 \xc2\xb1 0.186  ns/op\nMarkerFilterBenchmark.log4jSimpleMarker    avgt   10   8.043 \xc2\xb1 0.145  ns/op\nMarkerFilterBenchmark.log4jTooFine         avgt   10   2.825 \xc2\xb1 0.281  ns/op\nMarkerFilterBenchmark.logbackParentMarker  avgt   10  17.865 \xc2\xb1 0.533  ns/op\nMarkerFilterBenchmark.logbackSimpleMarker  avgt   10  10.471 \xc2\xb1 0.089  ns/op\nMarkerFilterBenchmark.logbackTooFine       avgt   10   4.255 \xc2\xb1 0.014  ns/op\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后的想法。Ceki Gulcu 在创建 SLF4J 时发明了标记的概念,他值得赞扬,因为这是一个奇妙的想法。

\n