Log4j 学习笔记

1. 快速入门

 public class log4jL {
     public static void main(String[] args) {
         //1 初始化 用于没有配置文件
         BasicConfigurator.configure();
 ​
         //2 生成logger对象
         Logger logger = Logger.getLogger(log4jL.class);
 ​
         //3 日志信息输出
         logger.info("test");
     }
 }

从快速入门的案例中可以学到 配置一个日志信息至少需要三步

  • 初始化 读取配置文件

  • 生成 Logger 对象

  • 输出日志信息

接下来由这三个步骤开始讲述


2. 配置信息

2.1 配置文件类型

首先进入Logger类 找到getLogger()

   public
   Logger getLogger(Class clazz) {
     return LogManager.getLogger(clazz.getName());
   }

可以看到有一个LoggerManager的对象,点进这个loggerManager类中可以看到Log4j的配置信息以及加载管理方式。

 ​
   /**
    * @deprecated This variable is for internal use only. It will
    * become package protected in future versions.
    * */
   static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
   
   static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";  
    
   /**
    * @deprecated This variable is for internal use only. It will
    * become private in future versions.
    * */
   static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
 ​
   /**
    * @deprecated This variable is for internal use only. It will
    * become private in future versions.
    * */
   static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
 ​
   /**
   * @deprecated This variable is for internal use only. It will
   * become private in future versions.
   */
   public static final String DEFAULT_INIT_OVERRIDE_KEY = 
                                                  "log4j.defaultInitOverride";
 ​

可以看到 Log4j的配置文件支持上面几种

  • log4j.properties (过时

  • log4j.xml

  • log4j.configuration (过时

  • log4j.configuratorClass(过时

  • log4j.defaultInitOverride(过时

但是我还是用properties 比较方便

在这个类的108行可以看到这些配置文件都是由Loader.getResource的方式加载的,所以只需要将配置文件放在resource的文件夹中即可以被识别到。

2.2 配置文件内容

  // If we have a non-null url, then delegate the rest of the
  // configuration to the OptionConverter.selectAndConfigure
  // method.
  if(url != null) {
 LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
    try {
        OptionConverter.selectAndConfigure(url, configuratorClassName,
    LogManager.getLoggerRepository());
    } catch (NoClassDefFoundError e) {
        LogLog.warn("Error during default initialization", e);
    }
  } else {
 LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
  }

还是在LogManager类的下方可以看到如果在类加载过程中找到配置文件,则执行OptionConverter.selectAndConfigure()这个函数,进入这个函数

   static
   public
   void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
    Configurator configurator = null;
    String filename = url.getFile();
 ​
    if(clazz == null && filename != null && filename.endsWith(".xml")) {
      clazz = "org.apache.log4j.xml.DOMConfigurator";
    }
 ​
    if(clazz != null) {
      LogLog.debug("Preferred configurator class: " + clazz);
      configurator = (Configurator) instantiateByClassName(clazz,
                        Configurator.class,
                        null);
      if(configurator == null) {
          LogLog.error("Could not instantiate configurator ["+clazz+"].");
          return;
      }
    } else {
      configurator = new PropertyConfigurator();
    }
 ​
    configurator.doConfigure(url, hierarchy);
   }
 }

在这个函数中,可以看到程序执行的步骤是 识别配置文件的类型 新建一个configurator对象 执行

configurator.doConfigure(url, hierarchy);方法,所以进入这个方法就可以看到配置信息的写法了。由于这个方法是一个抽象的方法,我们需要查看PropertyConfigurator类的具体实现。

进入这个类之后,如果是下载代码源的话,就可以看到非常详细的注释 包括每个参数的作用 配置的方法 还有样例提供,基本上通过阅读这个源码注释就可以完成对配置文件的学习。

2.2.1 RootLogger

定义每个appender的跟输出级别,这里就需要先登记一下日志的输出级别,从上到下递减

  • fatal 严重错误 影响系统运行

  • error 错误信息 不影响系统运行

  • warn 警告信息 可能会发生问题

  • info 运行信息 数据连接等信息

  • debug 调试信息 开发中使用

  • trace 追踪信息 记录查询程序运行

在rootLogger配置中可以配置每一个appender对应的最低日志输出级别 比如在console中输出bebug以上,在文件中输出error以上的日志级别

 # 表示在console输出tarce级别以上的日志信息
 # 格式为  级别,名称
 # 例子
 log4j.rootLogger=trace,console 

2.2.1.1 自定义logger

设定根logger是遵照所有logger对象的默认配置 自定义logger可以配置某一个logger的个性设置

 /*<p>For non-root categories the syntax is almost the same:
 <pre>
 log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
 </pre>

要注意的是 在PropertyConfigurator这个类中的parseCategory函数 可以看到 在while循环里面 他可以识别多个appendername 也就是说,配置Rootlogger可以向多个appender输出

2.2.2 Appender

Appender 用于配置日志输出的方向

在代码注释中他提供的格式是

 log4j.appender.appenderName=fully.qualified.name.of.appender.class

appenderName可以自己定义 后面是对应输出append方法的全类名。

以下是所有appender的类型,常用的为前三种

  • ConsoleAppender

  • FileAppender

  • JDBCAppender

  • AppenderSkeleton

  • AsyncAppender

  • DailyRollingFileAppender

  • ExternallyRolledFileAppender

  • JMSAppender

  • LF5Appender

  • NTEventLogAppender

  • NullAppender

  • RollingFileAppender

  • SMTPAppender

  • SocketAppender

  • SocketHubAppender

  • SyslogAppender

  • TelnetAppender

  • WriterAppender

# 例子
log4j.appender.console=org.apache.log4j.ConsoleAppender

在所有的Appender中有一些特殊的参数 在propertyconfigrator类中都指定了,你可以通过配置文件来设置

/*
# Set appender specific options.
log4j.appender.appenderName.option1=value1
...
log4j.appender.appenderName.optionN=valueN
</pre>

2.2.2.1 WriterAppender

在设置consoleAppender 和FilerAppender的时候我发现了中文都会乱码,但是实际生产情况中并不会,所以应该是我遗漏了哪个设置 结果在父类中找到了对应的设置参数,经过测试之后,也可以在配置文件中以option的格式进行定义

protected boolean immediateFlush = true;

/**
   The encoding to use when writing.  <p>The
   <code>encoding</code> variable is set to <code>null</null> by
   default which results in the utilization of the system's default
   encoding.  */
protected String encoding;

/**
   This is the {@link QuietWriter quietWriter} where we will write
   to.
*/
protected QuietWriter qw;

2.2.2.2 FileAppender

FileAppender 可以设置的变量为下图。

/**
   The name of the log file. */
protected String fileName = null;

/**
   Do we do bufferedIO? */
protected boolean bufferedIO = false;

/**
 * Determines the size of IO buffer be. Default is 8K. 
 */
protected int bufferSize = 8*1024;

以下是例子

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%15.15t] %-5p %l %x - %m%n
# 设置文件的路径 这个文件会在你该程序的根目录下作为基路径 算是一种绝对路径的格式
log4j.appender.file.file=/Doc/logs/log4j.log
log4j.appender.file.encoding=UTF-8

同时 FileAppender还发展出了RollingFileAppender、DailyRollingFileAppender 日常使用的话一般使用这两个,这样可以将日志文件分批管理。

RollingFileAppender有两个参数设置的文件的大小和备份数量,同样也可以在配置文件中配置。

/**
   The default maximum file size is 10MB.
*/
protected long maxFileSize = 10*1024*1024;

/**
   There is one backup file by default.
 */
protected int  maxBackupIndex  = 1;
public
void setMaxFileSize(String value) {
  maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
}

在设置文件大小的时候有着这样一个函数,可以自动帮我们把文件大小转化为系统可以识别的大小,比如你写10MB,它可以自动转化为10 * 1024 * 1024,方便用户操作,具体的转换类型就是在toFileSize这文件里面。


2.2.3 Appender.Layout

配置完Appender之后,还需要配置对应的输出格式

  • EnhancedPatternLayout

  • HTMLLayout

  • PatternLayout

  • SimpleLayout

  • TTCCLayout

log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class

2.2.3.1 PatternLayout

在PropertyConfigrator类中 在介绍这个PatternLayout的时候,提供了一个ConversionPattern参数,表示我们可以通过配置信息,自己配置pattern的格式

/*
# A1's layout is a PatternLayout, using the conversion pattern
# <b>%r %-5p %c{2} %M.%L %x - %mn</b>. Thus, the log output will
# include # the relative time since the start of the application in
# milliseconds, followed by the level of the log request,
# followed by the two rightmost components of the logger name,
# followed by the callers method name, followed by the line number,
# the nested disgnostic context and finally the message itself.
# Refer to the documentation of {@link PatternLayout} for further information
# on the syntax of the ConversionPattern key.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %mn

我们查看PatternLayout这个类 发现确实有对于格式的定义 包括默认格式和设置自定义格式的方法

/** Default pattern string for log output. Currently set to the
    string <b>"%m%n"</b> which just prints the application supplied
    message. */
public final static String DEFAULT_CONVERSION_PATTERN ="%m%n";

PatternLayout 默认的格式 记录

其中 该类提供了一个方法给我们设置 Pattern的格式

 /**
   Set the <b>ConversionPattern</b> option. This is the string which
   controls formatting and consists of a mix of literal content and
   conversion specifiers.
 */
public
void setConversionPattern(String conversionPattern) {
  pattern = conversionPattern;
  head = createPatternParser(conversionPattern).parse();
}

于是,要想设置自己的Pattern 格式,也只需要在配置文件里面配置,以下是源码给的样例。

在PatternLayout源码上方也提供了很多格式可供参考,既提供了各个参数的含义,也提供了几个常用格式。

log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %mn

2.3 内置日志记录

找到这个功能的原因是在阅读LogManager源码的时候发现,在LogManager找到的识别url之后要输出的识别记录 ,但是实际运行过程中并没有看到这些信息的输出,于是进入LogLog类查看原因,发现了这个内置日志记录的功能。

  • LogManager 使用到LogLog的代码

  // If we have a non-null url, then delegate the rest of the
  // configuration to the OptionConverter.selectAndConfigure
  // method.
  if(url != null) {
 LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
    try {
        OptionConverter.selectAndConfigure(url, configuratorClassName,
      LogManager.getLoggerRepository());
    } catch (NoClassDefFoundError e) {
        LogLog.warn("Error during default initialization", e);
    }
  } else {
 LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
  }
} else {
    LogLog.debug("Default initialization of overridden by " + 
        DEFAULT_INIT_OVERRIDE_KEY + "property."); 
}  

发现LogLog类是用于记录Log状态的代码

/**
   This class used to output log statements from within the log4j package.

   <p>Log4j components cannot make log4j logging calls. However, it is
   sometimes useful for the user to learn about what log4j is
   doing. You can enable log4j internal logging by defining the
   <b>log4j.configDebug</b> variable.

   <p>All log4j internal debug calls go to <code>System.out</code>
   where as internal error messages are sent to
   <code>System.err</code>. All internal messages are prepended with
   the string "log4j: ".
   
   @since 0.8.2
   @author Ceki G&uuml;lc&uuml;
*/

LogManager使用的段落为

/**
   This method is used to output log4j internal debug
   statements. Output goes to <code>System.out</code>.
*/
public
static
void debug(String msg) {
  if(debugEnabled && !quietMode) {
    System.out.println(PREFIX+msg);
  }
}

默认情况下的这两个参数都为false

protected static boolean debugEnabled = false;  

/**
   In quietMode not even errors generate any output.
 */
private static boolean quietMode = false

只需要将debugEnabled设置为true即可.

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>