日志总结---从common-log、self4j、log4j到logback、logstash

1. log的历史

log4j --其他日志                       后来log4j--->logback (与log4j同一作者,性能得到提高,配置更灵活)
    |
   V
common-log接口,自动扫描实现类,有确定,在独立进程中的类扫描不到
    |
   V
sef4j接口

2.如何打印日志:
log.info("运行错误{}",e.getMessage());
log.info("运行错误",e);
主要使用上述方式打印日志时,如果使用%c%L打印类名和行号时,class的名称显示的是超类的名字,L显示的当前类的行号。

3.项目的坑
core-MD居然用到了3种getLoger的方法,有common-logs的,有sellf4j的,有log4j的,所以在排查时遇到一些问题。
多种日志实现并存时,比如log4j和logback,随机得到日志实现。

由于历史原因,系统有logback、log4j两套日志,试着关闭log4j,后发现spring的日志没有啦,spring和hibernate等使用了log4j.而习题自动找到了logback的配置。另外如果在spring中没有配置logback.xml,则maven启动时使用src/test/resoureces/log_back.xml文件,发布时使用src/main/resource目录下的。

在生产机A上,由于多个项目使用了公共lib,所以日志打印总是有问题,不能上传到logstash,好像也不能生成文件。
在另外一台生产机使用独立lib时时正常。

addActivity属性:是否还是其他匹配打印日志。

      比如第一个logger设置了additivity=true,所以除了写入file_access还会写入stdout。
     <logger name="com.mindao.app.ea.interceptor.AccessLogInterceptor" level="info" additivity="true">        
        <appender-ref ref="file_access" />
    </logger>

    <logger name="com.mindao" level="info" additivity="false">        
        <appender-ref ref="stdout" />
    </logger>

4.log4j如何对接logstash
 
log4j.rootLogger=INFO,console,socket

# for package com.demo.elk, log would be sent to socket appender.
#log4j.logger.com.mindao.elk=info, socket
log4j.logger.com.mindao.elk=info, socket

# appender socket
log4j.appender.socket=org.apache.log4j.net.SocketAppender
log4j.appender.socket.Port=4567
log4j.appender.socket.RemoteHost=120.76.44.235
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=%d [%-5p] [%l] %m%n
log4j.appender.socket.ReconnectionDelay=10000

# appender console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d [%-5p] [%l] %m%n

logstash的配置
mkdir config
vi config/log4j_to_es.conf
输入以下内容:

# For detail structure of this file# Set: https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html
input {
  # For detail config for log4j as input, # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html
  log4j {
    mode => "server"
    host => "centos2"
    port => 4567
  }
}
filter {
}
output {
  # For detail config for elasticsearch as output, # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
  elasticsearch {
    action => "index"#The operation on ES
    hosts  => "centos2:9200"#ElasticSearch host, can be array.
    index  => "applog"#The index to write data to.
  }
}
5 logback如何对接logstash
https://github.com/logstash/logstash-logback-encoder
Including it in your project
Maven style:

<dependency>
  <groupId>net.logstash.logback</groupId>
  <artifactId>logstash-logback-encoder</artifactId>
  <version>4.7</version>
</dependency>
UDP Appender
To output JSON for LoggingEvents to a syslog/UDP channel, use the LogstashSocketAppender in your logback.xml like this:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appendername="stash"class="net.logstash.logback.appender.LogstashSocketAppender">
    <host>MyAwesomeSyslogServer</host>
    <!-- port is optional (default value shown) -->
    <port>514</port>
  </appender>
  <rootlevel="all">
    <appender-refref="stash" />
  </root>
</configuration>

logstash的配置
input {
  syslog {
    codec => "json"
  }
}

 

 

SpringBoot Starter 包下面默认已经集成了Self4J + LogBack。

问题
大家都知道SpringBoot可以使用yml和properties两种配置方式。但是这边有一个问题,在使用yml方式配置logback的时候,不能用LogHome指定它的路径。如:

logging:
config:
classpath: config/logback-spring:xml
path: log
file: loginfo

<property name=”LOG_HOME” value=”${LOG_PATH}/${LOG_FILE}” />
这样做会导致在你的目录下生成一个loginfo的文件,而没有路径。但是如果你用properties配置文件,就不会有这个问题。我被困扰了好久···。

yml多环境配置logback
首先是主要的配置文件:application.yml
spring:
profiles:
active: dev //这边代表你需要激活哪个环境
创建你需要的环境配置文件,
在同一目录下:如application-dev.yml

在resource根目录下创建logback配置文件
<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration debug=”true”>
<!– 项目名称 –>
<property name=”PROJECT_NAME” value=”projectmanage”/>

<!–定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径–>
<property name=”LOG_HOME” value=”${catalina.base:-.}/logs”/>

<!– 控制台输出 –>
<appender name=”CONSOLE” class=”ch.qos.logback.core.ConsoleAppender”>
<withJansi>true</withJansi>
<encoder class=”ch.qos.logback.classic.encoder.PatternLayoutEncoder”>
<!–格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符–>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %highlight([%-5level] %logger{50} – %msg%n)</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>

<!– 系统错误日志文件 –>
<appender name=”SYSTEM_FILE” class=”ch.qos.logback.core.rolling.RollingFileAppender”>
<!– 过滤器,只打印ERROR级别的日志 –>
<filter class=”ch.qos.logback.classic.filter.LevelFilter”>
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class=”ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy”>
<!–日志文件输出的文件名–>
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}.system_error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!–日志文件保留天数–>
<MaxHistory>15</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>
<logger name=”system_error” additivity=”true”>
<appender-ref ref=”SYSTEM_FILE”/>
</logger>

<!– 自己打印的日志文件,用于记录重要日志信息 –>
<appender name=”MY_INFO_FILE” class=”ch.qos.logback.core.rolling.RollingFileAppender”>
<!– 过滤器,只打印ERROR级别的日志 –>
<filter class=”ch.qos.logback.classic.filter.LevelFilter”>
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class=”ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy”>
<!–日志文件输出的文件名–>
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}.my_info.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!–日志文件保留天数–>
<MaxHistory>15</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>
<logger name=”my_info” additivity=”true” level=”info”>
<appender-ref ref=”MY_INFO_FILE”/>
</logger>

 

<!– 开发环境下的日志配置 这边就是你开发环境的配置–>
<springProfile name=”dev”>
<root level=”INFO”>
<appender-ref ref=”CONSOLE”/>
<appender-ref ref=”SYSTEM_FILE”/>
</root>
</springProfile>

<!– 生产环境下的日志配置 这边就是你生产环境的配置–>
<springProfile name=”prod”>
<root level=”INFO”>
<appender-ref ref=”SYSTEM_FILE”/>
</root>
</springProfile>
</configuration>

 

 

此处主要介绍maven web工程下如何使用 logback + slf4j  进行日志记录。

logback主要包含三个组成部分:Loggers(日志记录器)、Appenders(输出目的在)、Layouts(日志输出格式)

 

slf4j :如jdbc一样,定义了一套接口,是一个日志门面,可实现多个日志系统间快速切换(通过修改配置文件)

logback : 和log4j是同一作者,是log4j的升级版,效果可想而知.

logback 主要分为三个模块,分别是:

  logback-core:提供基础功能,是其他两个模块的基础
  logback-classic : log4j的升级,实现了self4j api
  logback-access:用于与sevlet容器进行集成、提供网络访问日志的功能

 

logback初始化时,默认会去classpath下依次加载如下配置文件(logback.groovy、logback-test.xml、logback.xml),当找不到配置文件时logback将为rootLogger 添加一个 ConsoleAppender ,用于将日志输出到控制台。对于logback的初始化,官网有如下描述

复制代码

Logback tries to find a file called logback.groovy in the classpath.

If no such file is found, logback tries to find a file called logback-test.xml in the classpath.

If no such file is found, it checks for the file logback.xml in the classpath..

If no such file is found, service-provider loading facility (introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Configurator interface by looking up the file META-INF\services\ch.qos.logback.classic.spi.Configurator in the class path. Its contents should specify the fully qualified class name of the desired Configurator implementation.

If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.

复制代码

 

 

编程时可是要如下代码查看logback内部运行情况:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);

对于web项目,可配置sevlet,然后通过网页查看logback内部运行状态,如下:

复制代码

<!-- 通过浏览器以html形式查看logback内部状态 :http://host/yourWebapp/lbClassicStatus -->
    <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>

复制代码

说了一大堆废话,现在开始进入主题:

首先,在pom文件引入相关依赖,如下:

复制代码

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
     <version>1.7.5</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.0.13</version>
</dependency>

复制代码

 

接着,编写logback.xml(位于classpath目录下,此处为src/main/resources目录)

复制代码

<?xml version="1.0" encoding="UTF-8"?>
<!--debug="true" : 打印logback内部状态(默认当logback运行出错时才会打印内部状态 ),配置该属性后打印条件如下(同时满足): 
    1、找到配置文件 2、配置文件是一个格式正确的xml文件 也可编程实现打印内部状态,例如: LoggerContext lc = (LoggerContext) 
    LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); -->
<!-- scan="true" : 自动扫描该配置文件,若有修改则重新加载该配置文件 -->
<!-- scanPeriod="30 seconds" : 配置自动扫面时间间隔(单位可以是:milliseconds, seconds, minutes 
    or hours,默认为:milliseconds), 默认为1分钟,scan="true"时该配置才会生效 -->
<configuration debug="false" scan="true" scanPeriod="30 seconds" packagingData="true">
    <!-- 设置 logger context 名称,一旦设置不可改变,默认为default -->
    <contextName>myAppName</contextName>
    
    <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>
    
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 当前活动日志文件名 -->
        <file>./my_log.log</file>
        <!-- 文件滚动策略根据%d{patter}中的“patter”而定,此处为每天产生一个文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 归档文件名“.zip或.gz结尾”,表示归档文件自动压缩 -->
            <FileNamePattern>./my_log%d{yyyyMMdd}.log.zip</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
       
        <!--rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>renhai%i.log</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>10</maxIndex>
        </rollingPolicy>
        
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>20MB</maxFileSize>
        </triggeringPolicy-->
        
        <!-- <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
          rollover daily
          <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           each file should be at most 30MB, keep 60 days worth of history, but at most 20GB
           <maxFileSize>30MB</maxFileSize>    
           <maxHistory>60</maxHistory>
           <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy> -->
        

        <encoder>
          <pattern>%d{HH:mm:ss.SSS}[%-5level][%thread]%logger{36} - %msg%n</pattern>
          <!-- <pattern>%d{HH:mm:ss.SSS}[%-5level][%thread] - %msg%n</pattern> -->
        </encoder>
    </appender>
    
    <!-- 日志级别若没显示定义,则继承最近的父logger(该logger需显示定义level,直到rootLogger)的日志级别-->
    <!-- logger的appender默认具有累加性(默认日志输出到当前logger的appender和所有祖先logger的appender中),可通过配置 “additivity”属性修改默认行为-->
    <logger name="com.yinz"  level="debug" additivity="false" >
        <appender-ref ref="FILE"/>
    </logger>

    <!-- 至多只能配置一个root -->
    <root level="debug">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

复制代码

 

最后,就可以在程序中使用logback了,例如:

复制代码

package com.yinz.aaa;

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

public class Test {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Test.class);
        logger.debug("test........");
    }
}

复制代码

如上所述,我们使用的slf4j中的api,如此依赖,要想在多个日志系统间切换,只需要提供相应的配置文件就可以了,而不需要修改编码部分。

 

最后有几点需要注意:

1、logger 的日志级别若没显示定义,则继承最近的祖先logger(该logger需显示定义level,直到rootLogger)的日志级别。

  1.1,、logger的父子关系,由logger的名称决定,例如有三个logger,分别为:java.lang.util 、 java.lang  、java

  则,java是java.lang的父logger, 是java.lang.util的祖先logger. 而同时java.lang是java.lang.util的父logger

2、logger的appender默认具有累加性(默认日志输出到当前logger的appender和所有祖先logger的appender中),可通过配置 “additivity”属性修改默认行为

 

logback与spring整合还在研究中。。。。。。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值