一、log4j2简介

log4j2是log4j 1.x和logback的改进版,据说采用了一些新技术(无锁异步、等等),使得日志的吞吐量、性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活

maven配置

  1. <!--log4j2核心包-->
  2. <dependency>
  3. <groupId>org.apache.logging.log4j</groupId>
  4. <artifactId>log4j-api</artifactId>
  5. <version>2.9.1</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.apache.logging.log4j</groupId>
  9. <artifactId>log4j-core</artifactId>
  10. <version>2.9.1</version>
  11. </dependency>
  12. <!-- Web项目需添加 -->
  13. <dependency>
  14. <groupId>org.apache.logging.log4j</groupId>
  15. <artifactId>log4j-web</artifactId>
  16. <version>2.9.1</version>
  17. </dependency>
  18. <!--用于与slf4j保持桥接-->
  19. <dependency>
  20. <groupId>org.apache.logging.log4j</groupId>
  21. <artifactId>log4j-slf4j-impl</artifactId>
  22. <version>2.9.1</version>
  23. </dependency>
  24. <!-- slf4j核心包-->
  25. <dependency>
  26. <groupId>org.slf4j</groupId>
  27. <artifactId>slf4j-api</artifactId>
  28. <version>1.7.25</version>

也可以配置starter

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-log4j2</artifactId>
  4. </dependency>

二、log4j2.xml配置

实现类在log4j2.xml配置文件中的标签名。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
  3. <!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
  4. <!--monitorInterval:Log4j能够自动检测修改配置文件和重新配置本身,设置间隔秒数-->
  5. <configuration status="WARN" monitorInterval="30">
  6. <properties>
  7. <property name="server.port"></property>
  8. </properties>
  9.  
  10. <!--先定义所有的appender-->
  11. <appenders>
  12. <!--这个输出控制台的配置-->
  13. <console name="Console" target="SYSTEM_OUT">
  14. <!--输出日志的格式-->
  15. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [%thread] %p %m%n"/>
  16. </console>
  17. <!-- 这个会打印出所有的info及以下级别的信息 -->
  18. <RollingFile name="RollingFile" filePattern="/data/log/tomcat${sys:server.port}/catalina.%d{yyyy-MM-dd}.log">
  19. <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
  20. <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
  21. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} [%thread] %p %m%n"/>
  22. <Policies>
  23. <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
  24. </Policies>
  25. <DirectWriteRolloverStrategy/>
  26. </RollingFile>
  27. </appenders>
  28. <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
  29. <loggers>
  30. <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
  31. <logger name="org.springframework" level="INFO"></logger>
  32. <logger name="org.mybatis" level="INFO"></logger>
  33. <root level="INFO">
  34. <appender-ref ref="Console"/>
  35. <appender-ref ref="RollingFile"/>
  36. </root>
  37. </loggers>
  38. </configuration>

简单说Appender就是一个管道,定义了日志内容的去向(保存位置)。

配置一个或者多个Filter进行过滤

配置Layout来控制日志信息的输出格式。

配置Policies以控制日志何时(When)进行滚动。

配置Strategy以控制日志如何(How)进行滚动。

简单说了下配置项,具体可参考博客:https://www.imooc.com/article/78966

https://www.cnblogs.com/hafiz/p/6170702.html

三、log4j2其实现原理

首先介绍下log4j2中的几个重要的概念

LoggerContext

LoggerContext在Logging System中扮演了锚点的角色。根据情况的不同,一个应用可能同时存在于多个有效的LoggerContext中。在同一LoggerContext下,log system是互通的。如:Standalone Application、Web Applications、Java EE Applications、”Shared” Web Applications 和REST Service Containers,就是不同广度范围的log上下文环境。

Configuration

每一个LoggerContext都有一个有效的Configuration。Configuration包含了所有的Appenders、上下文范围内的过滤器、LoggerConfigs以及StrSubstitutor.的引用。在重配置期间,新与旧的Configuration将同时存在。当所有的Logger对象都被重定向到新的Configuration对象后,旧的Configuration对象将被停用和丢弃。

 Logger

Loggers 是通过调用LogManager.getLogger方法获得的。Logger对象本身并不实行任何实际的动作。它只是拥有一个name 以及与一个LoggerConfig相关联。它继承了AbstractLogger类并实现了所需的方法。当Configuration改变时,Logger将会与另外的LoggerConfig相关联,从而改变这个Logger的行为。

LoggerConfig

每个LoggerConfig和logger是对应的,获取到一个logger,写日志时其实是通过LoggerConfig来记日志的

1、获取LoggerFactory

和logback一样,slf4j委托具体实现框架的StaticLoggerBinder来返回一个ILoggerFactory,从而对接到具体实现框架上,我们看下这个类(省略了部分代码)

  1. public final class StaticLoggerBinder implements LoggerFactoryBinder {
  2.  
  3. private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
  4. private final ILoggerFactory loggerFactory;
  5.  
  6. /**
  7. * Private constructor to prevent instantiation
  8. */
  9. private StaticLoggerBinder() {
  10. loggerFactory = new Log4jLoggerFactory();
  11. }
  12.  
  13. /**
  14. * Returns the singleton of this class.
  15. *
  16. * @return the StaticLoggerBinder singleton
  17. */
  18. public static StaticLoggerBinder getSingleton() {
  19. return SINGLETON;
  20. }
  21.  
  22. /**
  23. * Returns the factory.
  24. * @return the factor.
  25. */
  26. @Override
  27. public ILoggerFactory getLoggerFactory() {
  28. return loggerFactory;
  29. }
  30. }

可以看到

  • 1、通过getSingleton()获取该类的单例
  • 2、通过构造函数新建了Log4jLoggerFactory实例,
  • 3、通过getLoggerFactory()方法返回该实例

2、获取logger

进入Log4jLoggerFactory类中查看getLogger()方法,发现是在AbstractLoggerAdapter类中

  1. @Override
  2. public L getLogger(final String name) {
  3. final LoggerContext context = getContext();
  4. final ConcurrentMap<String, L> loggers = getLoggersInContext(context);
  5. final L logger = loggers.get(name);
  6. if (logger != null) {
  7. return logger;
  8. }
  9. loggers.putIfAbsent(name, newLogger(name, context));
  10. return loggers.get(name);
  11. }

1、通过getContext()得到LoggerContext实例

2、在context中查找是否已经有该logger,有就返回

3、如果没有则调用newLogger(name, context)方法新建logger

Log4jLoggerFactory只有两个方法,就是上面说的getContext()和newLogger(name, context)。下面分两节分别讲下这两个方法

  1. public class Log4jLoggerFactory extends AbstractLoggerAdapter<Logger> implements ILoggerFactory {
  2.  
  3. private static final String FQCN = Log4jLoggerFactory.class.getName();
  4. private static final String PACKAGE = "org.slf4j";
  5.  
  6. @Override
  7. protected Logger newLogger(final String name, final LoggerContext context) {
  8. final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;
  9. return new Log4jLogger(context.getLogger(key), name);
  10. }
  11.  
  12. @Override
  13. protected LoggerContext getContext() {
  14. final Class<?> anchor = StackLocatorUtil.getCallerClass(FQCN, PACKAGE);
  15. return anchor == null ? LogManager.getContext() : getContext(StackLocatorUtil.getCallerClass(anchor));
  16. }
  17.  
  18. }
2.1  getContext()

getContext()方法就是返回合适的loggerContext,进入LogManager.getContext()方法

  1. public static LoggerContext getContext() {
  2. try {
  3. return factory.getContext(FQCN, null, null, true);
  4. } catch (final IllegalStateException ex) {
  5. LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
  6. return new SimpleLoggerContextFactory().getContext(FQCN, null, null, true);
  7. }
  8. }

factory实在LoggerContext静态代码块中初始化的,继续进入factory.getContext(FQCN, null, null, true)方法中,进入实现类Log4jContextFactory中

  1. @Override
  2. public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
  3. final boolean currentContext) {
  4. final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext);
  5. if (externalContext != null && ctx.getExternalContext() == null) {
  6. ctx.setExternalContext(externalContext);
  7. }
  8. if (ctx.getState() == LifeCycle.State.INITIALIZED) {
  9. ctx.start();
  10. }
  11. return ctx;
  12. }

LoggerContext是从selector.getContext(fqcn, loader, currentContext)中获取的,此时判断ctx.getState()是否等于LifeCycle.State.INITIALIZED,第一次调用getlogger()时,会进入此方法,我们看下ctx.start();

  1. public void start() {
  2. LOGGER.debug("Starting LoggerContext[name={}, {}]...", getName(), this);
  3. if (PropertiesUtil.getProperties().getBooleanProperty("log4j.LoggerContext.stacktrace.on.start", false)) {
  4. LOGGER.debug("Stack trace to locate invoker",
  5. new Exception("Not a real error, showing stack trace to locate invoker"));
  6. }
  7. if (configLock.tryLock()) {
  8. try {
  9. if (this.isInitialized() || this.isStopped()) {
  10. this.setStarting();
  11. reconfigure();
  12. if (this.configuration.isShutdownHookEnabled()) {
  13. setUpShutdownHook();
  14. }
  15. this.setStarted();
  16. }
  17. } finally {
  18. configLock.unlock();
  19. }
  20. }
  21. LOGGER.debug("LoggerContext[name={}, {}] started OK.", getName(), this);
  22. }

进入reconfigure()方法

  1. private void reconfigure(final URI configURI) {
  2. final ClassLoader cl = ClassLoader.class.isInstance(externalContext) ? (ClassLoader) externalContext : null;
  3. LOGGER.debug("Reconfiguration started for context[name={}] at URI {} ({}) with optional ClassLoader: {}",
  4. contextName, configURI, this, cl);
  5. final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(this, contextName, configURI, cl);
  6. if (instance == null) {
  7. LOGGER.error("Reconfiguration failed: No configuration found for '{}' at '{}' in '{}'", contextName, configURI, cl);
  8. } else {
  9. setConfiguration(instance);
  10. /*
  11. * instance.start(); Configuration old = setConfiguration(instance); updateLoggers(); if (old != null) {
  12. * old.stop(); }
  13. */
  14. final String location = configuration == null ? "?" : String.valueOf(configuration.getConfigurationSource());
  15. LOGGER.debug("Reconfiguration complete for context[name={}] at URI {} ({}) with optional ClassLoader: {}",
  16. contextName, location, this, cl);
  17. }
  18. }

我们的配置文件log4j2.xml就是该函数中实现的,ConfigurationFactory.getInstance().getConfiguration(this, contextName, configURI, cl)得到了配置文件,并解析成Configuration。进入setConfiguration(instance)方法,启动当前的configuration,并启动该配置下的所有appender,logger和root。

  1. public Configuration setConfiguration(final Configuration config) {
  2. if (config == null) {
  3. LOGGER.error("No configuration found for context '{}'.", contextName);
  4. // No change, return the current configuration.
  5. return this.configuration;
  6. }
  7. configLock.lock();
  8. try {
  9. final Configuration prev = this.configuration;
  10. config.addListener(this);
  11. final ConcurrentMap<String, String> map = config.getComponent(Configuration.CONTEXT_PROPERTIES);
  12. try { // LOG4J2-719 network access may throw android.os.NetworkOnMainThreadException
  13. map.putIfAbsent("hostName", NetUtils.getLocalHostname());
  14. } catch (final Exception ex) {
  15. LOGGER.debug("Ignoring {}, setting hostName to 'unknown'", ex.toString());
  16. map.putIfAbsent("hostName", "unknown");
  17. }
  18. map.putIfAbsent("contextName", contextName);
  19. config.start();
  20. this.configuration = config;
  21. updateLoggers();
  22. if (prev != null) {
  23. prev.removeListener(this);
  24. prev.stop();
  25. }
  26. firePropertyChangeEvent(new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config));
  27. try {
  28. Server.reregisterMBeansAfterReconfigure();
  29. } catch (final LinkageError | Exception e) {
  30. // LOG4J2-716: Android has no java.lang.management
  31. LOGGER.error("Could not reconfigure JMX", e);
  32. }
  33. // AsyncLoggers update their nanoClock when the configuration changes
  34. Log4jLogEvent.setNanoClock(configuration.getNanoClock());
  35.  
  36. return prev;
  37. } finally {
  38. configLock.unlock();
  39. }
  40. }
2.2 newLogger(name, context)
  1. protected Logger newLogger(final String name, final LoggerContext context) {
  2. final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;
  3. return new Log4jLogger(context.getLogger(key), name);
  4. }

进入context.getLogger(key)方法

  1. @Override
  2. public Logger getLogger(final String name) {
  3. return getLogger(name, null);
  4. }
  5. @Override
  6. public Logger getLogger(final String name, final MessageFactory messageFactory) {
  7. // Note: This is the only method where we add entries to the 'loggerRegistry' ivar.
  8. Logger logger = loggerRegistry.getLogger(name, messageFactory);
  9. if (logger != null) {
  10. AbstractLogger.checkMessageFactory(logger, messageFactory);
  11. return logger;
  12. }
  13.  
  14. logger = newInstance(this, name, messageFactory);
  15. loggerRegistry.putIfAbsent(name, messageFactory, logger);
  16. return loggerRegistry.getLogger(name, messageFactory);
  17. }

进入newInstance(this, name, messageFactory)方法

  1. protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
  2. return new Logger(ctx, name, messageFactory);
  3. }
  1. protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) {
  2. super(name, messageFactory);
  3. this.context = context;
  4. privateConfig = new PrivateConfig(context.getConfiguration(), this);
  5. }
  1. public PrivateConfig(final Configuration config, final Logger logger) {
  2. this.config = config;
  3. this.loggerConfig = config.getLoggerConfig(getName());
  4. this.loggerConfigLevel = this.loggerConfig.getLevel();
  5. this.intLevel = this.loggerConfigLevel.intLevel();
  6. this.logger = logger;
  7. }
  1. public LoggerConfig getLoggerConfig(final String loggerName) {
  2. LoggerConfig loggerConfig = loggerConfigs.get(loggerName);
  3. if (loggerConfig != null) {
  4. return loggerConfig;
  5. }
  6. String substr = loggerName;
  7. while ((substr = NameUtil.getSubName(substr)) != null) {
  8. loggerConfig = loggerConfigs.get(substr);
  9. if (loggerConfig != null) {
  10. return loggerConfig;
  11. }
  12. }
  13. return root;
  14. }

可以看到首先从loggerConfigs也就是配置文件中配置的logger中获取,如果获取不到则循环递归name中"."之前的logger,如果还是获取不到,则默认使用root的配置。

3、logger.info()

Log4jLogger.class

  1. public void info(final String format) {
  2. logger.logIfEnabled(FQCN, Level.INFO, null, format);
  3. }
  1. @Override
  2. public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message) {
  3. if (isEnabled(level, marker, message)) {
  4. logMessage(fqcn, level, marker, message);
  5. }
  6. }
  7.  
  8. public boolean isEnabled(final Level level, final Marker marker, final String message) {
  9. return privateConfig.filter(level, marker, message);
  10. }
  11.  
  12. protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message) {
  13. final Message msg = messageFactory.newMessage(message);
  14. logMessageSafely(fqcn, level, marker, msg, msg.getThrowable());
  15. }

可以看到isEnabled()方法中用来通过配置的filter来判断是否符合,如果符合则进入logMessage()方法

  1. protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message) {
  2. final Message msg = messageFactory.newMessage(message);
  3. logMessageSafely(fqcn, level, marker, msg, msg.getThrowable());
  4. }
  5.  
  6. private void logMessageSafely(final String fqcn, final Level level, final Marker marker, final Message msg,
  7. final Throwable throwable) {
  8. try {
  9. logMessageTrackRecursion(fqcn, level, marker, msg, throwable);
  10. } finally {
  11. // LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
  12. ReusableMessageFactory.release(msg);
  13. }
  14. }
  15.  
  16. private void logMessageTrackRecursion(final String fqcn,
  17. final Level level,
  18. final Marker marker,
  19. final Message msg,
  20. final Throwable throwable) {
  21. try {
  22. incrementRecursionDepth(); // LOG4J2-1518, LOG4J2-2031
  23. tryLogMessage(fqcn, level, marker, msg, throwable);
  24. } finally {
  25. decrementRecursionDepth();
  26. }
  27. }
  1. private void tryLogMessage(final String fqcn,
  2. final Level level,
  3. final Marker marker,
  4. final Message msg,
  5. final Throwable throwable) {
  6. try {
  7. logMessage(fqcn, level, marker, msg, throwable);
  8. } catch (final Exception e) {
  9. // LOG4J2-1990 Log4j2 suppresses all exceptions that occur once application called the logger
  10. handleLogMessageException(e, fqcn, msg);
  11. }
  12. }
  1. public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
  2. final Throwable t) {
  3. final Message msg = message == null ? new SimpleMessage(Strings.EMPTY) : message;
  4. final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
  5. strategy.log(this, getName(), fqcn, marker, level, msg, t);
  6. }
  1. public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn, final Marker marker, final Level level,
  2. final Message data, final Throwable t) {
  3. loggerConfig.log(loggerName, fqcn, marker, level, data, t);
  4. }
  1. public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
  2. final Message data, final Throwable t) {
  3. List<Property> props = null;
  4. if (!propertiesRequireLookup) {
  5. props = properties;
  6. } else {
  7. if (properties != null) {
  8. props = new ArrayList<>(properties.size());
  9. final LogEvent event = Log4jLogEvent.newBuilder()
  10. .setMessage(data)
  11. .setMarker(marker)
  12. .setLevel(level)
  13. .setLoggerName(loggerName)
  14. .setLoggerFqcn(fqcn)
  15. .setThrown(t)
  16. .build();
  17. for (int i = 0; i < properties.size(); i++) {
  18. final Property prop = properties.get(i);
  19. final String value = prop.isValueNeedsLookup() // since LOG4J2-1575
  20. ? config.getStrSubstitutor().replace(event, prop.getValue()) //
  21. : prop.getValue();
  22. props.add(Property.createProperty(prop.getName(), value));
  23. }
  24. }
  25. }
  26. final LogEvent logEvent = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t);
  27. try {
  28. log(logEvent, LoggerConfigPredicate.ALL);
  29. } finally {
  30. // LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
  31. ReusableLogEventFactory.release(logEvent);
  32. }
  33. }
  1. protected void log(final LogEvent event, final LoggerConfigPredicate predicate) {
  2. if (!isFiltered(event)) {
  3. processLogEvent(event, predicate);
  4. }
  5. }
  1. private void processLogEvent(final LogEvent event, final LoggerConfigPredicate predicate) {
  2. event.setIncludeLocation(isIncludeLocation());
  3. if (predicate.allow(this)) {
  4. callAppenders(event);
  5. }
  6. logParent(event, predicate);
  7. }
  8.  
  9. protected void callAppenders(final LogEvent event) {
  10. final AppenderControl[] controls = appenders.get();
  11. //noinspection ForLoopReplaceableByForEach
  12. for (int i = 0; i < controls.length; i++) {
  13. controls[i].callAppender(event);
  14. }
  15. }

这时候终于到了appender的处理了,直接定位到RollingFileAppender类中

  1. public void append(final LogEvent event) {
  2. getManager().checkRollover(event);
  3. super.append(event);
  4. }
  1. private void tryAppend(final LogEvent event) {
  2. if (Constants.ENABLE_DIRECT_ENCODERS) {
  3. directEncodeEvent(event);
  4. } else {
  5. writeByteArrayToManager(event);
  6. }
  7. }
  8. protected void directEncodeEvent(final LogEvent event) {
  9. getLayout().encode(event, manager);
  10. if (this.immediateFlush || event.isEndOfBatch()) {
  11. manager.flush();
  12. }
  13. }

这时候可以看到layout和encode的使用了

  1. public void encode(final StringBuilder source, final ByteBufferDestination destination) {
  2. try {
  3. final Object[] threadLocalState = getThreadLocalState();
  4. final CharsetEncoder charsetEncoder = (CharsetEncoder) threadLocalState[0];
  5. final CharBuffer charBuffer = (CharBuffer) threadLocalState[1];
  6. final ByteBuffer byteBuffer = (ByteBuffer) threadLocalState[2];
  7. TextEncoderHelper.encodeText(charsetEncoder, charBuffer, byteBuffer, source, destination);
  8. } catch (final Exception ex) {
  9. logEncodeTextException(ex, source, destination);
  10. TextEncoderHelper.encodeTextFallBack(charset, source, destination);
  11. }
  12. }

最后写日志。

四、通过代码动态生成logger对象

  1. public class LoggerHolder {
  2.  
  3. //加个前缀防止配置的name正好是我们某个类名,导致使用的日志路径使用了类名的路径
  4. private static final String PREFIX = "logger_";
  5.  
  6. /**
  7. * 支持生成写大数据文件的logger
  8. *
  9. * @param name logger name
  10. * @return Logger
  11. */
  12. public static Logger getLogger(String name) {
  13. String loggerName = PREFIX + name;
  14. Log4jLoggerFactory loggerFactory = (Log4jLoggerFactory) LoggerFactory.getILoggerFactory();
  15. LoggerContext context = (LoggerContext) LogManager.getContext();
  16. //如果未加载过该logger,则新建一个
  17. if (loggerFactory.getLoggersInContext(context).get(loggerName) == null) {
  18. buildLogger(name);
  19. }
  20. //
  21. return loggerFactory.getLogger(loggerName);
  22. }
  23.  
  24. /**
  25. * 包装了Loggerfactory,和LoggerFactory.getLogger(T.class)功能一致
  26. *
  27. * @param clazz
  28. * @return
  29. */
  30. public static Logger getLogger(Class<?> clazz) {
  31. Log4jLoggerFactory loggerFactory = (Log4jLoggerFactory) LoggerFactory.getILoggerFactory();
  32. return loggerFactory.getLogger(clazz.getName());
  33. }
  34.  
  35. /**
  36. * @param name logger name
  37. */
  38. private static void buildLogger(String name) {
  39. String loggerName = PREFIX + name;
  40. LoggerContext context = (LoggerContext) LogManager.getContext();
  41. Configuration configuration = context.getConfiguration();
  42. //配置PatternLayout输出格式
  43. PatternLayout layout = PatternLayout.newBuilder()
  44. .withCharset(UTF_8)
  45. .withPattern("%msg%n")
  46. .build();
  47. //配置基于时间的滚动策略
  48. TimeBasedTriggeringPolicy policy = TimeBasedTriggeringPolicy.newBuilder()
  49. .withInterval(24)
  50. .build();
  51. //配置同类型日志策略
  52. DirectWriteRolloverStrategy strategy = DirectWriteRolloverStrategy.newBuilder()
  53. .withConfig(configuration)
  54. .build();
  55. //配置appender
  56. RollingFileAppender appender = RollingFileAppender.newBuilder()
  57. .setName(loggerName)
  58. .withFilePattern("/data/bigdata/" + name + "/" + name + ".%d{yyyyMMdd}.log")
  59. .setLayout(layout)
  60. .withPolicy(policy)
  61. .withStrategy(strategy)
  62. .withAppend(true)
  63. .build();
  64. //改变appender状态
  65. appender.start();
  66. //新建logger
  67. LoggerConfig loggerConfig = new LoggerConfig(loggerName, Level.INFO, false);
  68. loggerConfig.addAppender(appender, Level.INFO, null);
  69. configuration.addLogger(loggerName, loggerConfig);
  70. context.updateLoggers();
  71. }
  72. }

logger(三)log4j2简介及其实现原理的更多相关文章

  1. logger(二)logback简介及其实现原理

    一.logback简介 logback是log4j创始人写的,性能比log4j要好,目前主要分为3个模块 logback-core:核心代码模块 logback-classic:log4j的一个改良版 ...

  2. logger(一)slf4j简介及其实现原理

    一.slf4j简介 slf4j(Simple logging facade for Java)是对所有日志框架制定的一种规范.标准.接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体 ...

  3. Mybatis sql映射文件浅析 Mybatis简介(三) 简介

    Mybatis sql映射文件浅析 Mybatis简介(三)   简介 除了配置相关之外,另一个核心就是SQL映射,MyBatis 的真正强大也在于它的映射语句. Mybatis创建了一套规则以XML ...

  4. Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理

    Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理 2017年01月04日 08:52:12 阅读数:18366 基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB ...

  5. MariaDB/MySQL备份和恢复(三):xtrabackup用法和原理详述

    本文目录: 1.安装xtrabackup 2.备份锁 3.xtrabackup备份原理说明 3.1 备份过程(backup阶段) 3.2 准备过程(preparing阶段) 3.3 恢复过程(copy ...

  6. 2017-2018-2 20155228 《网络对抗技术》 实验三:MAL_免杀原理与实践

    2017-2018-2 20155228 <网络对抗技术> 实验三:MAL_免杀原理与实践 实验内容 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasi ...

  7. VMware虚拟机三种联网方法及原理

    VMware虚拟机三种联网方法及原理   一.Brigde——桥接:默认使用VMnet0   1.原理:   Bridge 桥"就是一个主机,这个机器拥有两块网卡,分别处于两个局域网中,同时 ...

  8. VMware虚拟机的三种联网方法及原理

    VMware虚拟机的三种联网方法及原理 博客分类: 操作系统 虚拟机Vmware互联网网络应用网络协议 一.Brigde——桥接  :默认使用VMnet0 1.原理: Bridge  桥"就 ...

  9. Log4j2 简介

    介绍 Log4j2是Log4j的升级版,与之前的版本Log4j 1.x相比.有重大的改进,修正了Logback固有的架构问题的同事,改进了许多Logback所具有的功能. 特性 一.API 分离 Lo ...

随机推荐

  1. shell 之for循环几种写法

    参见博客 http://blog.csdn.net/babyfish13/article/details/52981110 ,此博客写的非常清晰明了.

  2. JWT权限设计思维导图

  3. 如何做到MySQL的高可用?

    本课时的主题是“MySQL 高可用”,主要内容包含: 什么是高可用性 MySQL 如何提升 MTBF MySQL 如何降低 MTTR 避免单点失效 基础软硬件避免单点 MySQL 高可用架构选型 故障 ...

  4. LeetCode 204. Count Primes计数质数 (C++)

    题目: Count the number of prime numbers less than a non-negative number, n. Example: Input: 10 Output: ...

  5. JAVA基础概念(二)

    一.java修饰符和使用场景 修饰符是用来定义类.方法或者变量的访问权限,分为两大类: 访问修饰符: 限定类.属性.方法是否可以被程序里其他部分访问和调用. private<default< ...

  6. [LeetCode] 494. Target Sum 目标和

    You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symb ...

  7. 申请Github学生包(用学生证就行,免教育邮箱)

    GitHub教育包的福利: 大名鼎鼎的JetBrains给学生教师的免费个人许可 https://education.github.com/pack/redeem/jetbrains 有Github学 ...

  8. 微信小程序绑定列表数据

    js代码 Page({ /** * 页面的初始数据 */ data: { words:[] } wxml代码 <view wx:for="{{words}}" class=' ...

  9. git强制合并另一个分支

    New分支和Old分支都修改了同样的部分,有冲突,但是想在Old分之上合并New分支的内容,并且以New分支为主,就是不自己手动解决冲突,碰到冲突,直接以New分支为主. 参考 https://git ...

  10. Java之数据库基础理论

    一.事务的四大特性 ACID 只有满足一致性,事务的执行结果才是正确的. 在无并发的情况下,事务串行执行,隔离性一定能够满足.此时要只要能满足原子性,就一定能满足一致性. 在并发的情况下,多个事务并发 ...