日志级别有高到低;
fatal(致命) :直接程序报错
error
info
debug
trace(堆栈)
日志级别为fatal只会输出 fatal 错误
日志级别为error会输出 error 错误,fatal错误
........
日志框架:
根据日志门面和日志实现来划分日志框架:
日志门面有:JCL, Slf4j,jboss-logging
日志实现有:log4j,log4j2,logback,JUL。
对于JCL(commons-logging):spring框架日志是以他作为门面的,本身没有实现真正的日志能力,它依赖其他的日志系统如log4j或者java本身的java.util.logging。可以通过配置文件来设定最终使用log4j还是java.util.logging。没有配置log4j的时候就会调用java.util.logging包。一旦程序中检测 log4j在classpath,Commons Logging将会使用log4j作为底层实现。
SpringMVC日志
原来的spring框架中以JCL为日志接口,java.util.logging为日志实现的,网上说如果spring识别到 log4j配置在classpath,Commons Logging将会使用log4j作为底层实现。如果需要改变spring框架的日志接口。参考spring Boot的日志。
我们自己应用可以用slf4j为日志接口(调用slf4j的api),log4j为日志实现,可以不用管spring的日志。
1、配置
在pom.xml添加(https://mvnrepository.com/artifact/log4j/log4j)
适配器:目的将log4j和slf4j进行绑定,原本log4j框架被开发根本没有想到slf4j(之后才出来的),所以他没有按照slf4j定义的样式开发,后来又开发出新的日志框架logback,slf4j才被开发出来,让所有的日志类实现这个slf4j。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
在 src/main/resources
目录下创建名为 log4j.properties
的属性配置文件
log4j.rootLogger=INFO, console, file
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=logs/log.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.MaxFileSize=1024KB
log4j.appender.A3.MaxBackupIndex=10
log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n
日志配置相关说明:
-
log4j.rootLogger
:根日志,配置了日志级别为INFO
,预定义了名称为console
、file
两种附加器 -
log4j.appender.console
:console 附加器,日志输出位置在控制台 -
log4j.appender.console.layout
:console 附加器,采用匹配器布局模式 -
log4j.appender.console.layout.ConversionPattern
:console 附加器,日志输出格式为:日期 日志级别 [类名] - 消息换行符
-
log4j.appender.file
:file 附加器,每天产生一个日志文件 -
log4j.appender.file.File
:file 附加器,日志文件输出位置logs/log.log
-
log4j.appender.file.layout
:file 附加器,采用匹配器布局模式 -
log4j.appender.A3.MaxFileSize
:日志文件最大值 -
log4j.appender.A3.MaxBackupIndex
:最多纪录文件数 -
log4j.appender.file.layout.ConversionPattern
:file 附加器,日志输出格式为:日期 日志级别 [类名] - 消息换行符
如果上面的配置不行,使用下面的
log4j.rootCategory=debug, console, file //如果配置的是info,那么在输出日志的时候,logger.debug("xx")就不会打印,info比debug级别高
#log4j.logger.com.zy.servlet=debug,console,file //表示局部的日志输出(如果配置了全局了,就不用写了)
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=${catalina.home}/logs/log.log //${catalina.home}这个在tomcat服务器下,或者直接配合绝对路径,不可以用相对路径(测试过)
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.A3.MaxFileSize=1024KB
log4j.appender.A3.MaxBackupIndex=10
log4j.appender.file.layout.ConversionPattern=%d %p [%c] - %m%n
2、使用
注意使用占位符:减少内存开销
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
private static final Logger logger = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
String test1 = "测试";
String test2 = "测试2";
logger.info("{} {}",test1,test2);
}
}
Spring Boot日志(内部使用logback作为日志实现)
spring boot让系统中所有的日志都统一到slf4j,这是如何实现的呢?
1、将系统中其他日志框架先排除出去,防止jar包冲突
2、用中间包来替换原有的日志框架;
3、我们导入slf4]其他的实现
以spring boot 1.x 版本看,它排除了commons-logging,映入了代替他的包 jcl-over-slf4j,jar(注意这个包里面是包含comons-logging中的class的,不然spring找不到响应的class,就会报错,他本质上还是调用自己的接口,只是这个接口由中的方法不一样了),但是spring boot2.x 又改动了
使用
1、配置
参考:https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/html/boot-features-logging.html
1、在application.properties配置
##指定目录
#logging.level.com.zy.springbootproject.SpringbootProjectApplicationTests=trace
##全局配置
##logging.level.root=debug
#
##如果不指定目录,只要文件名,就会在当前项目下生成一个日志文件
##logging.file=springBoot.log
##如果指定了目录,就在当前目录下生成配置文件(项目下不会生成配置文件了)
##logging.file=D:/logs/springboot.log
#
##在当前磁盘的根路径下创建spring文件夹,使用spring.log作为默认文件
#logging.path=/spring
#
##在控制台输出的日志格式
#logging.pattern.console==%d{yyyy-MM-dd HH:mm:ss.SSS}[%thread]%-5level %logger{50}-%msg%n
1、或者创建 logback.xml,最好将名字改为logback-spring.xml,原因配置文件中有解释(参考)
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒,当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!--解析配置文件的时间戳-->
<timestamp key="time" datePattern="yyyyMMdd'T'HHmmss"/>
<!--上下文名称,默认名称为"default"-->
<contextNmae>${time}</contextName>
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="/var/log"/>
<!-- 定义日志文件名称 -->
<property name="appName" value="spring"></property>
<!--
SpringBoot的特性,与property类似,只是并不是直接指定给name一个value值,
而是通过source从环境中获取值,并且可以设置一个默认值
-->
<springProperty scope = "context" name = "hostName" source = "host.name" defaultValue = "localhost"/>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割
%msg:日志消息
%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="fileLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责触发滚动。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
false:表示只用当前logger的appender-ref
true:表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="com.yt" level="debug" />
<!-- Spring framework logger -->
<logger name="org.springframework" level="debug" additivity="false">
<!--指定appender,如果没有指定则继承root-->
<appender-ref ref="stdout" />
</logger>
<!--springProfile是SpringBoot的特性,日志配置文件名必须是*-spring.xml(比如将logback.xml改为logback-spring.xml)
用于指定不同的profile,可以使用在configuration标签内任意位置
-->
<springProfile name="prod,!dev">
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
-->
<root level="info">
<appender-ref ref="stdout" />
<appender-ref ref="fileLogAppender" />
</root>
</springProfile>
<springProfile name="dev">
<root level="debug">
<appender-ref ref="stdout" />
<appender-ref ref="fileLogAppender" />
</root>
</springProfile>
</configuration>
1、或者 创建 logback.xml(参考)
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="E:\logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%line:行号,%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} Line:%line ----------------> %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/system/sysWeb-%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} Line:%line ----------------> %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<!--分包输出日志,分包配置-->
<appender name="serviceAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/service/Service-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} Line:%line ----------------> %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="controllerAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/controller/Controller-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} Line:%line ----------------> %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!--分包输出日志,分包指向-->
<logger name="com.example.demo" level="DEBUG" additivity="false">
<appender-ref ref="controllerAppender" />
</logger>
</configuration>
2、使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootProjectApplicationTests {
@Test
public void test(){
Logger logger = LoggerFactory.getLogger(SpringbootProjectApplicationTests.class);
logger.info("xxx");
}
}
控制台打印所以的日志,错误日志通过FileErrorLog写入文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->
<!-- 属性描述
scan:设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定义日志文件的存储地址 -->
<property name="LOG_HOME" value="C:/AEPCLOG" />
<!-- 控制台输出 -->
<appender name="ConsoleLog" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--Info文件输出-->
<!-- 按照每天和固定大小(5MB)生成日志文件【最新的日志,是日期最大数字最大的】 -->
<appender name="FileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
所以我们使用下面的策略,可以避免输出 Error 的日志,这种方式不能避免warn-->
<!-- 过滤日志 -->
<!--<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!–过滤 Error–>
<level>ERROR</level>
<!–匹配到就禁止–>
<onMatch>DENY</onMatch>
<!–没有匹配到就允许–>
<onMismatch>ACCEPT</onMismatch>
</filter>-->
<!--只输出INFO-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 INFO-->
<level>INFO</level>
<!--匹配到就禁止-->
<onMatch>ACCEPT</onMatch>
<!--没有匹配到就允许-->
<onMismatch>DENY</onMismatch>
</filter>
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/Info/DenseTubeManage_Info_%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>10MB</MaxFileSize>
</rollingPolicy>
<!--格式化输出-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--Error文件输出-->
<!-- 按照每天和固定大小(5MB)生成日志文件【最新的日志,是日期最大数字最大的】 -->
<appender name="FileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--设置日志级别,过滤掉info日志,只输入error日志-->
<level>ERROR</level>
</filter>
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/Error/DenseTubeManage_Error_%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>5MB</MaxFileSize>
</rollingPolicy>
<!--格式化输出-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--日志等级设置-->
<logger name="org.springframework" level="error"></logger>
<!--系统配置info,目的,可以将系统启动参数都打印出来-->
<root level="info">
<appender-ref ref="ConsoleLog"/>
</root>
<!--项目系统,日志等级配置debug-->
<!--控制台打印所以的日志,错误日志通过FileErrorLog写入文件-->
<logger name="com.aepcmis" level="debug">
<!--系统打印日志,会根据 ConsoleLog、FileErrorLog里面的过滤filter来选择策略,
由于ConsoleLog没有配置任何filter,所以所有的debug日志都会走consolelog
由于FileErrorLog配置了filter,所以只有error的日志会走FileErrorLog
-->
<appender-ref ref="ConsoleLog"/>
<appender-ref ref="FileErrorLog"/>
</logger>
</configuration>
Spring Boot日志切换框架(了解)
如果需要使用log4j
1.首先根据排除原本框架的依赖
2、根据下面添加依赖
pom展示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j-to-slf4j</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</dependency>
3、添加配置,在resourcs下创建log4j.properities
登录日志
不管在前台还是后台用户登录,不管是本次登录成功还是失败,都需要记录登录的日志:登录的日志记录了本次登录的时间,ip,登录结果等信息:
登录日志可以有效的查看用户的登录记录。
从运营数据来说,通过前端用户的登承日志,可以分析出这个用户的粘度:可以用来分析整个网站的用户活跃度等内容:
从安全性来说,通过登录日志可以查看是否有人恶意登录或者恶意猜测用户密码的情况:可以用于系统前端或者后端的安全预警:
方式1:
1、建表和pojo对象(可以由表逆向生成)
保存用户登录时候的那些数据日志(是保存用户登录成功的信息,还是只要登录就保存日志)
2、controller
在用户登录的时候,就插入日志的操作。
方式2
1、使用文件进行保存日志
2、方式使用日志框架