`
schy_hqh
  • 浏览: 555728 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Chapter 3: Logback configuration

 
阅读更多

学习一套日志框架,以便在后续项目中使用

 

Logback配置方式

Logback can be configured either programmatically or with a configuration script expressed in XML

基于编程方式
XML配置(推荐)

 

Logback初始化步骤

 在classpath路径下,依次寻找,如果找到,则使用此配置:
  1. logback.groovy
  2. logback-test.xml
  3. logback.xml
  4. Automatically using the BasicConfigurator which will cause logging output to be directed to the console. By default the root logger is assigned the DEBUG level
     最后一步,确保了logback始终有1个可用配置

 

Automatically configuring logback

自动配置,level=DEBUG,向控制台进行输出

package manual.configuration;

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

public class MyApp1 {
  final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

  public static void main(String[] args) {
    logger.info("Entering application.");

    Foo foo = new Foo();
    foo.doIt();
    logger.info("Exiting application.");
  }
}

 

package chapters.configuration;
  
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
   
public class Foo {
  static final Logger logger = LoggerFactory.getLogger(Foo.class);
  
  public void doIt() {
    logger.debug("Did it again!");
  }
}

 

Logback将使用默认的配置进行日志输出,控制台输出: 

16:06:09.031 [main] INFO chapters.configuration.MyApp1 - Entering application. 
16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again! 
16:06:09.046 [main] INFO chapters.configuration.MyApp1 - Exiting application.

 

Automatic configuration with logback-test.xml or logback.xml

自动读取配置文件进行日志输出,如配置向控制台输出:

 

 <configuration>

   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
     <!-- encoders are assigned the type
   ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
     <encoder>
       <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
     </encoder>
   </appender>

   <root level="debug">
     <appender-ref ref="STDOUT" />
   </root>
 </configuration>

 

Automatic printing of status messages in case of warning or errors

 默认,logback在读取配置文件出错时,会打印错误信息
但是,如果配置了listener,为防止重复打印错误消息,默认机制将取消
而且,没有错误发生,又想查看logback的status,可通过 StatusPrinter 的printf()进行输出

logback-test.xml

  public static void main(String[] args) {
    // assume SLF4J is bound to logback in the current environment
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    // print logback's internal status
    StatusPrinter.print(lc);
    ...
  }

 将看到控制台打印出如下信息

17:44:58,578 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml]
17:44:58,671 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
17:44:58,671 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
17:44:58,687 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Popping appender named [STDOUT] from the object stack
17:44:58,812 |-INFO in ch.qos.logback.classic.joran.action.LevelAction - root level set to DEBUG
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[root]

17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Entering application.
17:44:58.828 [main] DEBUG chapters.configuration.Foo - Did it again!
17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Exiting application.

 

 另一种在没有错误的情况下,想看到logger初始化过程的方式:

 在configuration标签上设置属性debug="true"

 debug="true"能工作的前提:配置文件被找到,并且没有错误

<configuration debug="true"> 

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <!-- encoders are  by default assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

 

Automatically reloading configuration file upon modification

 当配置文件发生改变之后,Logback会自动加载配置文件

 机制:当若干个logger被执行后,将进行一次扫描,扫描频率还与CPU能力相关

 Values can be specified in units of milliseconds, seconds, minutes or hours.

 If no unit of time is specified, then the unit of time is assumed to be milliseconds

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration>

  

 

Viewing status messages

Logback-classic ships with a servlet called ViewStatusMessagesServlet

在WEB应用中,可以从网页上查看Logger的状态

To add this servlet to your web-application, add the following lines to its WEB-INF/web.xml file.

  <servlet>
    <servlet-name>ViewStatusMessages</servlet-name>
    <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ViewStatusMessages</servlet-name>
    <url-pattern>/lbClassicStatus</url-pattern>
  </servlet-mapping>

 The ViewStatusMessages servlet will be viewable at the URL

  http://host/yourWebapp/lbClassicStatus

 

 

Listening to status messages

配置一个状态监听器,自动输出Logger的状态

It is also possible to register one or more status listeners within a configuration file

<configuration>
  <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />  

  ... the rest of the configuration file  
</configuration>

 

 

Stopping logback-classic

在应用结束的时候,释放资源(关闭已激活的日志线程)

通过ServletContextListener 的contextDestroyed(ServletContextEvent sce)调用

import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
...

// assume SLF4J is bound to logback-classic in the current environment
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();

 

Configuration file syntax

logback可以控制APP中某部分的日志打开,某部分日志关闭

可以往控制台、文件、数据库、邮件、日志查看器等进行日志输出

 

配置文件语法

最基本原则:

<configuration>中只能有1个 <root> ,0个或多个<appender>,0个或多个<logger>

 

Configuring loggers, or the <logger> element

Effective Level aka Level Inheritance

Logger的Level继承原则:

The effective level for a given logger L, is equal to the first non-null level in its hierarchy, starting at L itself and proceeding upwards in the hierarchy towards the root logger.   

如果没有具体指定level,则向上查找非空的那个父类logger,使用其level作为自己的level

 

To ensure that all loggers can eventually inherit a level, the root logger always has an assigned level. By default, this level is DEBUG.  

为了确保每个logger最终都能有一个level,root logger的级别默认设置为了DEBUG



 

logger的属性配置

唯一的name属性,可选的level属性,可选的additivity属性

name attribute: logger的名称,一般为大写

level attribute:大小写不敏感的TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF

additivity attribute: ture/false

<logger>中可以配置0个或多个 <appender-ref>

与log4j不同,logback-classic不会移除前面设置的appender,而是采用追加方式

 

Configuring the root logger, or the <root> element

 root logger,只支持1个属性,即level属性

 由于是根logger,因此没有additivity 属性

 由于默认为名称为“ROOT”,因此没有name属性

 level属性合法的值:

 case-insensitive strings TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF

 不允许设置为 INHERITED or NULL.   

 

 允许0个或多个 <appender-ref>

 与log4j不同,logback-classic不会移除前面设置的appender,而是采用追加方式

 

为Logger设置级别level

指定某个包下的logger级别,覆盖从父类继承下来的level

"chapters.configuration" package的level设置为了INFO,因此,

"chapters.configuration" package下的debug级别将不会输出!

 

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO"/>

  <!-- Strictly speaking, the level attribute is not necessary since -->
  <!-- the level of the root level is set to DEBUG by default.       -->
  <root level="DEBUG">          
    <appender-ref ref="STDOUT" />
  </root>  
  
</configuration>

 

 为某个类指定logger的Level

 set the level of the chapters.configuration.Foo logger to DEBUG

 设置chapters.configuration.Foo 的logger级别为DEBUG,则该类的debug将被输出!

<configuration>

  <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
     </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />
  <logger name="chapters.configuration.Foo" level="DEBUG" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

 

 

 

子Logger的配置会覆盖root logger的配置

即使root logger处于关闭,但子logger仍可以正常工作

chapters.configuration由于有自己的logger配置,因此,正常工作

chapters.configuration之外的logger,将被关闭,因为root logger已经处理OFF状态

<configuration>

  <appender name="STDOUT"
   class="ch.qos.logback.core.ConsoleAppender">
   <encoder>
     <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />

  <!-- turn OFF all logging (children can override) -->
  <root level="OFF">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

 

 

 

 

 Logger的appender追加原则:

Configuring Appenders

 <appender> 只有两个可用属性:

name 属性: appender的名称

class 属性: appender对应的类

 

 <appender>可以有

0个或多个 <layout>元素

0个或多个 <encoder> 元素

0个或多个  <filter>元素

还可以设置对应class的JavaBean属性

 

  <layout>默认对应的类PatternLayout,则可以省略不写

  <encoder> 默认对应的类为PatternLayoutEncoder,可以省略不写

 

 1个logger引用多个appender

  注意: 每个appender都有属于自己的encoder,encoder没有提供共享功能!

              layout也是如此!

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

 

 

Appenders accumulate

叠加性

一个记录器会记录到连接到其自身的appender (如果有的话) ,以及所有连接到它的祖先的appender

Logger的Level受继承关系影响,Logger的appender也受继承关系影响

不同的是:

Logger的level会根据自己是否被指定level,再决定是否使用父类的level

Logger的appender则默认会叠加父类的appender,除非明确说明不叠加

 

chapters.configuration包下的日志将记录到文件,同时,也会输出到控制台

因为, chapters.configuration对应的logger继承了root logger中的appender!

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
 

chapters.configuration.Foo 对应的logger只会将日志往文件中输出,而不会往控制台输出

因为,明确指定了additivity="false",将不会叠加root logger中的appender!

 当某个logger使用了additivity="false",则它的子logger也不会继承root logger的appender~

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>foo.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file : %line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration.Foo" additivity="false">
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

 

 

Setting the context name

为每个Logger设置不同的context名称

这样,不同logger所记录的日志将很好的区分开

<configuration>
  <contextName>myAppName</contextName>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

 

 

Variable substitution

定义变量,实现属性替换By  "${aName}"

 

Defining variables

在配置文件configuration中定义

在外部properties文件中定义

在外部resource文件中定义

 

在configuration文件中设置变量:指定文件的输出位置 

<configuration>
  <!-- 注意,最开始不能加斜线"/" -->
  <property name="USER_HOME" value="home/sebastien" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

 

logback解析到配置文件中有${aName},如果没有对应的属性定义,将查询 Java system properties。因此,也可以通过设置 Java system properties 实现变量的定义。 

System.setProperty("USER_HOME", "home/sebastien");

 

当有多个变量属性需要定义时,通过1个专门的属性配置文件进行实现,再好不过

variables.properties

USER_HOME=home/sebastien

引入外部properties文件

<configuration>

  <property file="src/main/java/chapters/configuration/variables.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${USER_HOME}/myApp.log</file>
     <encoder>
       <pattern>%msg%n</pattern>
     </encoder>
   </appender>

   <root level="debug">
     <appender-ref ref="FILE" />
   </root>
</configuration>

 

还可以引入classpath下的资源文件,更方便

variables.properties

USER_HOME=home/sebastien

 引入外部资源文件  

<configuration>

  <property resource="resource1.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${USER_HOME}/myApp.log</file>
     <encoder>
       <pattern>%msg%n</pattern>
     </encoder>
   </appender>

   <root level="debug">
     <appender-ref ref="FILE" />
   </root>
</configuration>

 

 

Logback预定义的变量

 HOSTNAME   主机名
 CONTEXT_NAME

 Timestamp

<configuration>

  <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
       the key "bySecond" into the logger context. This value will be
       available to all subsequent configuration elements. -->
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!-- use the previously created timestamp to create a uniquely
         named log file -->
    <file>log-${bySecond}.txt</file>
    <encoder>
      <pattern>%logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

 

 

File inclusion

分离配置文件

通过<include>标签导入其它配置文件

<configuration>
  <include file="src/main/java/chapters/configuration/includedConfig.xml"/>

  <root level="DEBUG">
    <appender-ref ref="includedConsole" />
  </root>

</configuration>

 

被include的文件必须包含在<included/>标签中

 

<included>
  <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>"%d - %m%n"</pattern>
    </encoder>
  </appender>
</included>

 

As a file:

使用file属性进行引入,相对路径是相对与项目根路径的,不是configuration文件

As a resource:

从classpath进行导入

<include resource="includedConfig.xml"/>

As a URL:

从网络上导入

<include url="http://some.host.com/includedConfig.xml"/>

 

 

 

 

  • 大小: 76.1 KB
  • 大小: 20.7 KB
  • 大小: 20.2 KB
分享到:
评论
1 楼 superich2008 2014-05-22  
logback配置文件的改动会导致应用重新加载,多改动几次后就会出现【java.lang.OutOfMemoryError: PermGen space】的异常,因为Class在每次Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以多次Loader,就很可能出现PermGen space错误,这个问题如何解决?

相关推荐

    logback-classic-1.2.3-API文档-中英对照版.zip

    赠送jar包:logback-classic-1.2.3.jar; 赠送原API文档:logback-classic-1.2.3-javadoc.jar; 赠送源代码:logback-classic-1.2.3-sources.jar; 包含翻译后的API文档:logback-classic-1.2.3-javadoc-API文档-...

    logback-core-1.2.10-API文档-中文版.zip

    赠送jar包:logback-core-1.2.10.jar; 赠送原API文档:logback-core-1.2.10-javadoc.jar; 赠送源代码:logback-core-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.10.pom; 包含翻译后的API文档...

    logback-classic-1.2.6-API文档-中文版.zip

    赠送jar包:logback-classic-1.2.6.jar; 赠送原API文档:logback-classic-1.2.6-javadoc.jar; 赠送源代码:logback-classic-1.2.6-sources.jar; 赠送Maven依赖信息文件:logback-classic-1.2.6.pom; 包含翻译后...

    logback-classic-1.2.10-API文档-中文版.zip

    赠送jar包:logback-classic-1.2.10.jar; 赠送原API文档:logback-classic-1.2.10-javadoc.jar; 赠送源代码:logback-classic-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-classic-1.2.10.pom; 包含...

    logback-classic-1.2.3-API文档-中文版.zip

    赠送jar包:logback-classic-1.2.3.jar; 赠送原API文档:logback-classic-1.2.3-javadoc.jar; 赠送源代码:logback-classic-1.2.3-sources.jar; 赠送Maven依赖信息文件:logback-classic-1.2.3.pom; 包含翻译后...

    logback-core-1.2.3-API文档-中文版.zip

    赠送jar包:logback-core-1.2.3.jar; 赠送原API文档:logback-core-1.2.3-javadoc.jar; 赠送源代码:logback-core-1.2.3-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.3.pom; 包含翻译后的API文档:...

    logback-classic-1.2.10-API文档-中英对照版.zip

    赠送jar包:logback-classic-1.2.10.jar; 赠送原API文档:logback-classic-1.2.10-javadoc.jar; 赠送源代码:logback-classic-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-classic-1.2.10.pom; 包含...

    logback-core-1.2.10-API文档-中英对照版.zip

    赠送jar包:logback-core-1.2.10.jar; 赠送原API文档:logback-core-1.2.10-javadoc.jar; 赠送源代码:logback-core-1.2.10-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.10.pom; 包含翻译后的API文档...

    logback-core-1.2.6-API文档-中文版.zip

    赠送jar包:logback-core-1.2.6.jar; 赠送原API文档:logback-core-1.2.6-javadoc.jar; 赠送源代码:logback-core-1.2.6-sources.jar; 赠送Maven依赖信息文件:logback-core-1.2.6.pom; 包含翻译后的API文档:...

    logback-core-1.2.3-API文档-中英对照版.zip

    赠送jar包:logback-core-1.2.3.jar; 赠送原API文档:logback-core-1.2.3-javadoc.jar; 赠送源代码:logback-core-1.2.3-sources.jar; 包含翻译后的API文档:logback-core-1.2.3-javadoc-API文档-中文(简体)-...

    完整jar包资源,COULD NOT FIND logback-classic,包缺失使用

    打包找不到 logback-classic问题 COULD NOT FIND logback-classic:logback-classic-1.1.3 解压后将jar包与pom文件都放在.m2\repository指定路径下

    10 reasons to use logback !------log4j他爹告诉你为何要使用新的日志包logback

    3. 动态配置:logback提供动态配置功能,可以通过JMX(Java Management Extensions)接口在运行时调整日志级别,无需重启应用。 4. 分级日志记录:logback支持基于类、包或MDC(Mapped Diagnostic Context)的精细...

    logback-chinese-manual:logback 中文手册文档

    logback-chinese-manuallogback 中文手册翻译自简介Logback 继承自 log4j。Logback 的架构非常的通用,适用不同的使用场景。Logback 被分成三个不同的模块:logback-core,logback-classic,logback-access。logback...

    logback-1.1.3.zip

    3. **Appenders**:Logback 提供了多种 Appender,如 ConsoleAppender(控制台输出)、FileAppender(文件输出)、SMTPAppender(发送邮件)等,可以根据需要选择或自定义。 4. **Layouts**:布局类负责格式化日志...

    Java开发-日志管理-logback框架日志系统基础

    在日常工程开发中,日志是非常重要的一部分,通过日志可以迅速定位线上问题,日志框架也有很多选择,日志框架Logback和Log4j是同一个作者,Logback相比于Log4j,性能提高了10倍以上的性能,占用的内存也变小了,并且...

    Logback所需的jar包

    3.logback主要标签: logger:日志的记录器(可以存放日志对象,也可以第一日志的级别,类型等); appender:指定日志输出的媒介,即输出地(可以是控制台,可以是文件,远程套接字服务器等); layout:用来格式化...

    十个 log4j 转移到LogBack的理由

    3. **无缝集成 SLF4J**:SLF4J(Simple Logging Facade for Java)是一个日志门面,允许用户在运行时选择不同的日志实现。LogBack 作为 SLF4J 的原生实现,提供了更紧密的集成和更高的性能。 4. **SLF4J 桥接器**:...

    logback例子

    3. **日志级别**:Logback支持多种日志级别,从低到高为TRACE、DEBUG、INFO、WARN、ERROR和OFF。开发过程中,通常使用DEBUG级别调试,生产环境中则调整为INFO或WARN,以减少不必要的性能影响。 4. **Appender**:...

    Logback_doc.zip_doc_logback

    3. **Appenders**:Appenders 是日志输出的目标,如控制台、文件、SMTP、数据库等。手册会介绍如何配置不同的 Appender 类型。 4. **Layouts**:Layouts 决定了日志消息的格式。例如,SimpleLayout、PatternLayout ...

    Logback框架需要的3个jar包和logback.xml文件

    它通常包含`&lt;configuration&gt;`、`&lt;appender&gt;`、`&lt;logger&gt;`和`&lt;root&gt;`等元素。 - **日志级别**:可以设置全局默认级别(`&lt;root&gt;`元素的`level`属性),以及特定包或类的级别(`&lt;logger&gt;`元素的`level`属性)。 - **...

Global site tag (gtag.js) - Google Analytics