目录
目前比较常用的ava日志框架:Logback、log4j、log4j2、JUL等等。
Logback是在log4j的基础上重新开发的一套日志框架,是完全实现SLF4J接口API(也叫日志门面)。
Logback 的架构非常通用,可以应用于不同的环境。目前logback分为三个模块,logback-core,logback-classic和logback-access。
logback-core模块为其他两个模块奠定了基础。logback-classic模块原生实现了SLF4JAPI,因此您可以轻松地在logback和其他日志记录框架(例如 log4j1.x或java.util.logging (JUL))之间来回切换。
logback-access模块与Tomcat和 Jetty 等 Servlet容器集成,以提供HTTP访问日志功能。请注意,您可以轻松地在logback-core之上构建自己的模块。
1)创建一个maven项目
2)引入logback依赖
Maven Repository: logback (mvnrepository.com)
找个稳定版
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
package test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class applog {
static Logger logger= LoggerFactory.getLogger("自定义日志名.test.applog");//名字同时代表了级别
public static void main(String[] args) {
logger.info("no1");
}
}
运行
成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
日志的五个等级
TRACE < DEBUG < INFO < WARN <ERROR
拓展:日志一共分成5个等级,从低到高分别是:
DEBUG:详细的信息,通常只出现在诊断问题上
INFO:确认一切按预期运行
WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”)。这个软件还能按预期工作。
ERROR:更严重的问题,软件没能执行一些功能
CRITICAL:一个严重的错误,这表明程序本身可能无法继续运行
这5个等级,也分别对应5种打日志的方法: debug 、info 、warning 、error 、critical。默认的是WARNING,当在WARNING或之上时才被跟踪。
日志记录器(Logger):控制要输出哪些日志记录语句,对日志信息进行级别限制。如何生成记录器:
final static Logger logger = LoggerFactory.getLogger(“名称”);
1)记录器层级结构
所有的记录器都是缓存在 Map中的,记录器的关系有点类似于继承,是由名称决定的
父记录器logger2和子记录器logger,如果没有.标记,顶层记录器继承自root根记录器。
static Logger logger= LoggerFactory.getLogger("自定义日志名.test.applog");//名字同时代表了级别
static Logger logger2= LoggerFactory.getLogger("自定义日志名.test");//名字同时代表了级别,父记录器
2)子记录器会同时创建父类记录器
当父记录器存在的时候,再次创建子记录器则只会创建子记录器。
name属性:记录器的名称
level属性(可选):记录器的级别,允许的级别从低到高,TRACE<DEBUG<INFO< WARN <ERROR
logger.setLevel() ; 设置日志级别。可以使用设置的以及以上的级别的日志
logger.getLevel(); 查看设置的级别
logger.getEffectiveLevel() 查看实际生效的级别,比如默认或者继承自父记录器的级别
additivity属性(可选):是否允许叠加打印日志, true或false
说明:
1)如果记录器未设置level属性,则该记录器的级别从上级记录器继承
2)如果想查看记录器的级别,应该通过logger.getEffectiveLevel()方法,同时要将Logger转为ch.qos.logback.classic.Logger类型,如下:
ch.qos.logback.classic.Logger logger =
(ch.qos.logback.classic.Logger)LoggerFactory.getLogger(App.class);
1)简单演示修改日志级别
package test;
import ch.qos.logback.classic.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* 创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
* */
public class applog2 {
public static void main(String[] args) {
ch.qos.logback.classic.Logger logger= (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("自定义日志名");//名字同时代表了级别
System.out.println("设置之前的级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
logger.setLevel(Level.INFO);
System.out.println("设置之后的级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
logger.trace("no0");
logger.debug("no1");
logger.info("no2");
logger.warn("no3");
logger.error("no4");
/*
* 成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
* 日志的五个等级
* TRACE < DEBUG < INFO < WARN <ERROR
* */
}
}
输出
设置之前的级别
null
DEBUG
设置之后的级别
INFO
INFO
23:47:37.632 [main] INFO 自定义日志名 - no2
23:47:37.647 [main] WARN 自定义日志名 - no3
23:47:37.647 [main] ERROR 自定义日志名 - no4进程已结束,退出代码0
代码中我们将日志级别置为INFO,测试打印日志,打印出来了 INFO以及更高级别的日志记录,同时可以看到设置之前的日志级别和手动或执行后的日志级别。
2)修改父类日志级别查看子类日志级别
package test;
import ch.qos.logback.classic.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* 创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
* */
public class applog3 {
public static void main(String[] args) {
ch.qos.logback.classic.Logger logger= (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("自定义日志名");//名字同时代表了级别
ch.qos.logback.classic.Logger rootLogger=(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);//获取Root根记录器
rootLogger.setLevel(Level.INFO);
System.out.println("设置之前的级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
logger.setLevel(Level.INFO);
System.out.println("设置之后的级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
logger.trace("no0");
logger.debug("no1");
logger.info("no2");
logger.warn("no3");
logger.error("no4");
/*
* 成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
* 日志的五个等级
* TRACE < DEBUG < INFO < WARN <ERROR
* */
}
}
输出
设置之前的级别
null
INFO
设置之后的级别
INFO
INFO
00:00:27.430 [main] INFO 自定义日志名 - no2
00:00:27.437 [main] WARN 自定义日志名 - no3
00:00:27.437 [main] ERROR 自定义日志名 - no4进程已结束,退出代码0
提前把Root根记录器的日志级别改为INFO后,可以看出子类的生效级别变成了INFO.
3)层次结构
当前的记录器如果没有设置级别的话,就会向父类查询,如果父类也没有设置就向父类递归查询到ROOT记录器,默认DEBUG级别
1)创建配置文件 main-》resource->logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
</configuration>
如果命名空间和资源有问题的话,将光标移到xsd资源上按住 ALT+回车 手动设置外部资源,将外部资源导入就好了。
2)设置ROOT级别
代码中加入
<root level="info"></root>
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<root level="info"></root>
</configuration>
测试java代码
package test;
import ch.qos.logback.classic.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* 创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
* */
public class applog4 {
public static void main(String[] args) {
ch.qos.logback.classic.Logger rootLogger=(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);//获取Root根记录器
rootLogger.setLevel(Level.INFO);
System.out.println("设置之前的级别");
System.out.println(rootLogger.getLevel());
System.out.println(rootLogger.getEffectiveLevel());
rootLogger.setLevel(Level.WARN);
System.out.println("设置之后的级别");
System.out.println(rootLogger.getLevel());
System.out.println(rootLogger.getEffectiveLevel());
rootLogger.trace("no0");
rootLogger.debug("no1");
rootLogger.info("no2");
rootLogger.warn("no3");
rootLogger.error("no4");
/*
* 成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
* 日志的五个等级
* TRACE < DEBUG < INFO < WARN <ERROR
* */
}
}
输出
设置之前的级别
INFO
INFO
设置之后的级别
WARN
WARN进程已结束,退出代码0
可以看到默认的ROOT记录器日志级别从DEBUG变成了配置文件里的INFO。
3)设置其他记录器级别
修改配置文件加入
<logger name="com.aa" level="debug"></logger>
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<root level="info"></root>
<logger name="com.aa" level="debug">
</logger>
</configuration>
使用java程序测试
package test;
import ch.qos.logback.classic.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* 创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
* */
public class applog5 {
public static void main(String[] args) {
ch.qos.logback.classic.Logger logger= (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.aa");//名字同时代表了级别
System.out.println("com.aa级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
ch.qos.logback.classic.Logger logger2= (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com");//名字同时代表了级别
System.out.println("com的级别");
System.out.println(logger2.getLevel());
System.out.println(logger2.getEffectiveLevel());
/*
* 成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
* 日志的五个等级
* TRACE < DEBUG < INFO < WARN <ERROR
* */
}
}
输出
com.aa级别
DEBUG
DEBUG
com的级别
null
INFO进程已结束,退出代码0
在这里可以看到,提前设置好 <logger name="com.aa" level="debug"></logger>,那么以com.aa命名的记录器将不受ROOT记录器影响,在创建后就被就设置了日志级别。但是父记录器com依然是继承自ROOT的INFO级别。
什么是附加器?
记录器会将输出日志的狂务交给附加器完成,不同的附加器会将日志输出到不同的地方,比如控制台附加器、文件附加器、网络附加器等等。
常用的附加器
控制台附加器: ch.qos.logback.core.ConsoleAppender文件附加器: ch.qos.logback.core.FileAppender
滚动文件附加器: ch.qos.logback.core.rolling.RollingFileAppender
实际上仅仅有记录器是不能写日志的 ,附加器才是日志输出的工具。实现附加器需要设置附加器名字和Class实现类,并且要配置编码器模板,配置完成后将附加器放到记录器里面
1)控制台附加器输出
<!--实现附加器需要设置附加器名字和Class实现类,并且要配置编码器模板,配置完成后将附加器放到记录器里面-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
将附加器放到纪录器里,可以放多个附加器。
<logger name = "org.example.App" level = "DEBUG" >
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
测试:
完整的xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info"></root>
<logger name="com.aa" level="debug">
<appender-ref ref="STDOUT" />
</logger>
</configuration>
java程序
package test;
import org.slf4j.LoggerFactory;
/*
* 创建测试类
test.applog.java
创建一个记录器
用记录器生成日志
* */
public class applog6 {
public static void main(String[] args) {
ch.qos.logback.classic.Logger logger= (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.aa");//名字同时代表了级别
System.out.println("com.aa级别");
System.out.println(logger.getLevel());
System.out.println(logger.getEffectiveLevel());
logger.trace("no0");
logger.debug("no1");
logger.info("no2");
logger.warn("no3");
logger.error("no4");
/*
* 成功将日志输出到了控制台,因为我们没有做相关的配置,所以只能将debug及以上的日志输出到控制台(日志分为五个等级)
* 日志的五个等级
* TRACE < DEBUG < INFO < WARN <ERROR
* */
}
}
输出:
com.aa级别
DEBUG
DEBUG
00:46:30 [main] DEBUG com.aa - no1
00:46:30 [main] INFO com.aa - no2
00:46:30 [main] WARN com.aa - no3
00:46:30 [main] ERROR com.aa - no4进程已结束,退出代码0
2)pattern标签
Pattern由文字文本和转换说明符的格式控制表达式组成。您可以在其中自由插入任何文字文本。每个转换说明符都以百分号"%',后跟可选的格式修饰符、转换字和大括号之间的可选参数。转换字控制要转换的数据字段,例如记录器名称、级别、日期或线程名称。格式修饰符控制字段宽度、填充以及左对齐或右对齐。
3)文件附加器输出
需要多配置一个file标签,用于存放文件
<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>
完整xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<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>
<append>true</append>
<!--表示记录方式为追加-->
</appender>
<root level="info"></root>
<logger name = "com.aa" level = "DEBUG" >
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
</configuration>
依然执行上一个测试用例
输出了一个日志文件
这个方法生成的日志会不断叠加,更多的使用的是滚动文件附加器,可以设置时间和大小生成多个文件,方便阅读调阅。
4)滚动文件附加器
滚动策略
1.基于时间的滚动策略
ch.qos.logback.core.rolling.TimeBasedRollingPolicy
2.基于大小和时间的滚动策略
ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
(1)基于时间的
<!--滚动文件附加器-->
<appender name="runFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog2.log</file>
<!--编码器-->
<encoder>
<pattern>%50date %msg</pattern>
</encoder>
<!--滚动策略-->
<!--按照时间滚动生成-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.log</fileNamePattern>
<maxFileSize>10</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
这里面的mylog2.log指的是当前正在工作的日志文件,当满足设定条件后就重构重命名为归档文件,
<maxFileSize>10</maxFileSize> 则是设定归档文件的最大数量,超过数量会删除最早的归档文件。
<totalSizeCap>5GB</totalSizeCap> 用于设置所有日志文件的大小
测试
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<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>
<append>true</append>
<!--表示记录方式为追加-->
</appender>
<!--滚动文件附加器-->
<appender name="runFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog2.log</file>
<!--编码器-->
<encoder>
<pattern>%50date %msg</pattern>
</encoder>
<!--滚动策略-->
<!--按照时间滚动生成-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.log</fileNamePattern>
<!--编设定每秒执行一次归档文件-->
<maxFileSize>10</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="info"></root>
<logger name = "com.aa" level = "DEBUG" >
<appender-ref ref="runFile"/>
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
</configuration>
执行程序
设定为每秒一个日志,执行多次程序后,日志1被输出到文件列表
(2)基于时间和大小的
<!--滚动文件附加器-->
<appender name="runFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog3.log</file>
<!--编码器-->
<encoder>
<pattern>%50date %msg</pattern>
</encoder>
<!--滚动策略-->
<!--按照时间滚动生成-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.%i.log</fileNamePattern>
<maxFileSize>10</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
<maxFileSize>1KB</maxFileSize>
</rollingPolicy>
</appender>
这里面的标签多了一个
<maxFileSize>1KB</maxFileSize>
用于限定日志文件的大小
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.%i.log</fileNamePattern>
这个标签没发生一次变化代表着一个新的文件,前面是时间,后面的%i则是第几个触发的文件编号。
<maxFileSize>10</maxFileSize>
这个标签是按照时间的归档数量,而不是文件数量。
<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<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>
<append>true</append>
<!--表示记录方式为追加-->
</appender>
<!--滚动文件附加器-->
<appender name="runFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog2.log</file>
<!--编码器-->
<encoder>
<pattern>%50date %msg</pattern>
</encoder>
<!--滚动策略-->
<!--按照时间滚动生成-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.log</fileNamePattern>
<maxFileSize>10</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
<!--滚动文件附加器-->
<appender name="runFiletime" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog3.log</file>
<!--编码器-->
<encoder>
<pattern>%50date %msg</pattern>
</encoder>
<!--滚动策略-->
<!--按照时间滚动生成-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>%d{yyyy-mm-dd HH-mm-ss}.%i.log</fileNamePattern>
<maxFileSize>10</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
<maxFileSize>1KB</maxFileSize>
</rollingPolicy>
</appender>
<root level="info"></root>
<logger name = "com.aa" level = "DEBUG" >
<appender-ref ref="runFile"/>
<appender-ref ref="runFiletime"/>
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</logger>
</configuration>
自定义附加器
模拟控制台附加器
自行探索吧。。。
过滤器是附加器的一个组件,它用于决定附加器是否输出日志。一个附加器可以包含一个或多个过滤器。每个过滤器都会返回一个枚举值,可选的值:DENY、NEUTRAL、ACCEPT
附加器根据过滤器返回值判断是否输出日志:
DENY :不输出日志
ACCEPT:输出日志
NEUTRAL:中立,即不决定是否输出日志
如果当前过滤器决定输出日志,那么日志直接输出,忽略后面的过滤器
如果当前过滤器决定不输出日志,那么日志直接不输出,忽略后面的过滤器
如果当前过滤器待定是否输出日志,那么将询问下一个过滤器是否输出
常用的过滤器
LevelFilter(级别过滤器)︰实现类ch.qos.logback.classic.filter.LevelFilter
ThresholdFilter(阈值过滤器):实现类ch.qos.logback.classic.filter.ThresholdFilterEvaluatorFilter(评估者过滤器):实现类ch.qos.logback.core.filter.EvaluatorFilterJanino
EventEvaluator过滤器:实现类ch.qos.logback.core.filter.EvaluatorFilter
TurboFilter涡轮过滤器
DuplicateMessageFilter重复消息过滤器
级别过滤器
级别匹配一致打印日志并返回
级别匹配不一致不打印日志并返回
可以更改返回值。
自定义过滤器
文章浏览阅读3.9k次,点赞2次,收藏4次。STM32F207调试记录之串口配置_stm f207 串口速率
文章浏览阅读4k次,点赞6次,收藏8次。接着上一Pa说。就是如何建立这个堆呢。可以从空的堆开始,然后依次往堆中插入每一个元素,直到所有数都被插入(转移到堆中为止)。因为插入第i个元素的所用的时间是O(log i),所以插入所有元素的整体时间复杂度是O(NlogN),代码如下。n=0;for(i=1;i){ n++; h[ n]=a[ i]; //或者写成scanf("%d",&h[ n]); _4 17啊哈(i说哈1
文章浏览阅读215次。将pandas的DataFrame数据写入MySQL数据库 + sqlalchemyimportpandasaspdfromsqlalchemyimportcreate_engine##将数据写入mysql的数据库,但需要先通过sqlalchemy.create_engine建立连接,且字符编码设置为utf8,否则有些latin字符不能处理yconnect=create_engin..._pandas questdb create_engine
文章浏览阅读1.1w次。针对普通的弹框,React Native(RN)给我们提供了有Alert,但使用局限性很大,没有办法自定义,要实现自定义的弹框,我们应该如何来实现呢,这里提供两种方法:第一就是native本地来实现,然后暴露给RN来条用,第二就是使用组件Modal来实现,第一种方法这里就不写了,这里讲解下用Modal如何来实现。 首先我们先来了解下Modal是什么。 Modal组件可以_react-native-paper 中的dialog
文章浏览阅读4.1k次,点赞3次,收藏26次。龙芯1b:有源蜂鸣器播放音乐例程。_有源蜂鸣器播放音乐
文章浏览阅读3.6k次。选择题题目:()是突发公共事件应急管理工作的最高行政领导机构。题目:以下突发公共事件中,属于公共安全事件的是()?题目:我们赖以生活的价值是天生的,包括真、善、美在内的人类的古老价值,以及后来的愉快、正义和欢乐等价值,是人类本性固有的,这种观点体现了()?题目:“大安全”是指(),是最高决策机构,是俄罗斯国家安全的中枢机构,并且该机构设有宪法安全、国际安全、信息安全、经济安全等12个部门委员会。题目:美国应急处置管理体系的特征是()?题目:以下突发公共事件中,属于公共卫生事件的是()?题目:以_从处置主体来说,现代社会突发事件处置常常涉及
文章浏览阅读4.4k次。错误描述models仓库地址:https://github.com/tensorflow/models在使用TensorFlow的models来训练目标检测算法,通过object_detection/datasets_tools来在自己的数据集上构建一个tfrecord文件的时候报ImportError: cannot import name 'string_int_label_map_pb2'错误错误定位在label_map_util文件中第27行from object_detect_cannot import name 'string_int_label_map_pb2' from 'object_detection.protos
文章浏览阅读9.7k次,点赞2次,收藏6次。Git用户名/密码/邮箱,及设置git配置_git配置邮箱
文章浏览阅读1.4k次。hugo是由Go语言实现的静态网站生成器。简单、易用、高效、易扩展、快速部署。官网地址:https://gohugo.io/中文文档:https://www.gohugo.org/参考视频:手把手教你从0开始搭建自己的个人博客-CodeSheep这个项目,主要是通过hugo来搭建一个属于自己的个人博客网站。官网有现成的博客主题可供下载,对于想快速拥有一个个人主页或搭建一个网站的程序猿来说,是个不二之选~这是我搭建的一个比较基础的博客网站,大家可以先看看效果是怎样的博客地址:https://._hugo 博客 官网
文章浏览阅读229次。商用现货产品(COTS)对企业组织来说是有吸引力的选择,因为它们包含了可配置的开箱即用功能,可以在不编写任何代码的情况下满足大部分业务需求。Dynamics 365也不例外。Dynamics CRM 365专门提供功能强大的模块化功能丰富的产品,可根据您的组织需求进行定制。一般来说,随着产品的发展,可配置的无代码扩展实现起来更便宜,维护起来更容易,升级起来也更容易。正确建模,这些扩展可以大大提高您的投资价值。如果建模不正确,它们可能会导致平台只锁定一个目的。_dynamics 365 ce
文章浏览阅读1w次。如果忘记 SQL Server 管理员密码,可以使用下面的方式处理 1. 使用 SQL Server 服务器计算机本地 Administrators 组的任何成员登录到 SQL Server 服务器 2. 确定忘记管理员密码的 SQL Server 服务 可以在服务(services.msc)里面查看,或者使用下面的 Powershell 命令 Get-Service | ? Displ_找回sqlsever本地服务器管理员
文章浏览阅读3.7k次。一、二值化的定义从维基百科拿过来的定义:二值化是图像分割的一种方法。在二值化图象的时候把大于某个临界灰度值的像素灰度设为灰度极大值,把小于这个值的像素灰度设为灰度极小值,从而实现二值化。根据阈值选取的不同,二值化的算法分为固定阈值和自适应阈值。 比较常用的二值化方法则有:双峰法、P参数法、迭代法和OTSU法等。二、 二值化的算法这里就简单讲一下固定阈值的算法:..._二值化