Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

6.4. Log4j2 + Gelf + Logstash

https://logging.paluch.biz/examples/log4j-2.x.html

6.4.1. Maven 配置

			
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<!-- Exclude the Tomcat dependency -->
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
				<!-- 禁用 logback -->
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- 添加Log4j2 依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>biz.paluch.logging</groupId>
			<artifactId>logstash-gelf</artifactId>
			<version>1.15.0</version>
		</dependency>		
			
			

6.4.2. log4j2.xml 配置

			
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<properties>
		<property name="log.pattern">[%d{yyyy-MM-dd HH:mm:ss}] [${hostName}] [%p] [%t] %l - %m%n</property>
		<property name="log.dir">/tmp/logs</property>
		<property name="log.level">info</property>
	</properties>
	<Appenders>
		<!-- 控制台 -->
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout pattern="${log.pattern}" />
		</Console>

		<!-- INFO级别日志 -->
		<RollingFile name="RollingFileInfo" fileName="${log.dir}/info.log" filePattern="${log.dir}/info.%d{yyyy-MM-dd}.log">
			<Filters>
				<ThresholdFilter level="INFO" />
				<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL" />
			</Filters>
			<PatternLayout pattern="${log.pattern}" />
			<Policies>
				<TimeBasedTriggeringPolicy interval="1" modulate="false" />
			</Policies>
		</RollingFile>

		<!-- WARN级别日志 -->
		<RollingFile name="RollingFileWarn" fileName="${log.dir}/warn.log" filePattern="${log.dir}/warn.%d{yyyy-MM-dd}.log">
			<Filters>
				<ThresholdFilter level="WARN" />
				<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL" />
			</Filters>
			<PatternLayout pattern="${log.pattern}" />
			<Policies>
				<TimeBasedTriggeringPolicy interval="1" modulate="false" />
			</Policies>
		</RollingFile>

		<!-- ERROR级别日志 -->
		<RollingFile name="RollingFileError" fileName="${log.dir}/error.log" filePattern="${log.dir}/error.%d{yyyy-MM-dd}.log">
			<Filters>
				<ThresholdFilter level="ERROR" />
			</Filters>
			<PatternLayout pattern="${log.pattern}" />
			<Policies>
				<TimeBasedTriggeringPolicy interval="1" modulate="false" />
			</Policies>
		</RollingFile>

		<Gelf name="Gelf" host="udp:172.18.200.10" port="12201" version="1.1" extractStackTrace="true" filterStackTrace="true" mdcProfiling="true" includeFullMdc="true" maximumMessageSize="8192" originHost="%host{fqdn}">
			<Field name="timestamp" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}" />
			<Field name="logger" pattern="%logger" />
			<Field name="level" pattern="%level" />
			<Field name="class" pattern="%C{1}" />
			<Field name="method" pattern="%M" />
			<Field name="line" pattern="%L" />
			<Field name="marker" pattern="%marker" />
			<Filters>
				<MarkerFilter marker="finance" onMatch="ACCEPT" onMismatch="NEUTRAL" />
				<MarkerFilter marker="market" onMatch="ACCEPT" onMismatch="DENY" />
			</Filters>
		</Gelf>
	</Appenders>
	<Loggers>
		<Root level="${sys:log.level}">
			<AppenderRef ref="Console" />
			<AppenderRef ref="Gelf" />
			<!-- <AppenderRef ref="RollingFileInfo" /> <AppenderRef ref="RollingFileWarn" /> <AppenderRef ref="RollingFileError" /> -->
		</Root>
	</Loggers>
</Configuration>			
			
			

6.4.3. Java 测试代码

			
	@GetMapping("/log")
	public String log() {
		Marker finance = MarkerFactory.getMarker(LogMarker.finance.toString());
		Marker customer = MarkerFactory.getMarker(LogMarker.customer.toString());
		Marker market = MarkerFactory.getMarker(LogMarker.market.toString());
		logger.info("常规日志");
		logger.info(finance, "test");
		logger.info(finance, "finance");
		logger.info(customer, "customer");
		logger.info(market, "market");
		return "OK!!!\r\n";
	}

	@GetMapping("/log/marker")
	public String marker(@RequestParam("marker") String marker, @RequestParam("msg") String msg) {
		logger.info(MarkerFactory.getMarker(marker), msg);
		msg += "\r\n";
		return msg;
	}			
			
			

6.4.4. Logstash 配置

			
[root@netkiller log]# cat /etc/logstash/conf.d/file.conf 
input {
  tcp {
	port => 4567 
	codec => json_lines
  }
  gelf {
    port => 12201
    use_udp => true
    #use_tcp => true
  }
}

filter {
	ruby {
	    code => "event.set('datetime', event.get('@timestamp').time.localtime.strftime('%Y-%m-%d %H:%M:%S'))"
	}
}

output {

    file {
    	path => "/opt/log/%{marker}.%{+yyyy}-%{+MM}-%{+dd}.log"
    	codec => line { format => "[%{datetime}] %{level} %{message}"}
    }
   
    file {
        path => "/opt/log/origin.%{+yyyy}-%{+MM}-%{+dd}.log.gz"
		codec => json_lines
        gzip => true
    }

}			
			
			

6.4.5. 测试结果

			
[root@netkiller log]# ls
finance.2022-11-16.log  market.2022-11-16.log  origin.2022-11-16.log.gz

[root@netkiller log]# cat finance.2022-11-16.log 
[2022-11-16 15:02:36] INFO test
[2022-11-16 15:02:36] INFO finance
[2022-11-16 15:21:34] INFO test
[2022-11-16 15:21:34] INFO finance

[root@netkiller log]# cat market.2022-11-16.log 
[2022-11-16 15:02:36] INFO market
[2022-11-16 15:21:34] INFO market

[root@netkiller log]# zcat origin.2022-11-16.log.gz |jq
{
  "datetime": "2022-11-16 15:21:34",
  "timestamp": "2022-11-16 15:21:34.185",
  "message": "market",
  "host": "macbook-pro-neo.local",
  "level": "INFO",
  "line": 53,
  "@version": "1",
  "@timestamp": "2022-11-16T07:21:34.185Z",
  "marker": "market",
  "logger": "cn.netkiller.controller.HomeController",
  "version": "1.1",
  "method": "log",
  "class": "HomeController",
  "source_host": "172.18.5.142",
  "facility": "logstash-gelf"
}
{
  "datetime": "2022-11-16 15:21:34",
  "timestamp": "2022-11-16 15:21:34.143",
  "message": "test",
  "host": "macbook-pro-neo.local",
  "level": "INFO",
  "line": 49,
  "@version": "1",
  "@timestamp": "2022-11-16T07:21:34.143Z",
  "marker": "finance",
  "logger": "cn.netkiller.controller.HomeController",
  "version": "1.1",
  "method": "log",
  "class": "HomeController",
  "source_host": "172.18.5.142",
  "facility": "logstash-gelf"
}
{
  "datetime": "2022-11-16 15:21:34",
  "timestamp": "2022-11-16 15:21:34.184",
  "message": "finance",
  "host": "macbook-pro-neo.local",
  "level": "INFO",
  "line": 51,
  "@version": "1",
  "@timestamp": "2022-11-16T07:21:34.184Z",
  "marker": "finance",
  "logger": "cn.netkiller.controller.HomeController",
  "version": "1.1",
  "method": "log",
  "class": "HomeController",
  "source_host": "172.18.5.142",
  "facility": "logstash-gelf"
}
			
			
			

6.4.6. Log4j2 更多技巧

多环境配置

方案一

			
logging:
  config: classpath:log4j2-${spring.profiles.active}.xml
			
				

方案二

				
@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private Environment env;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... param) {
        if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
            Configurator.initialize(null, "/path/to/log4j2-dev.xml");
        } else {
            Configurator.initialize(null, "/path/to/log4j2.xml");
        }
    }
}				
				
				
控制 class 日志输出级别
				
#日志配置 无特殊需求无需更改
logging:
  config:  classpath:log4j2.xml
  level:
    root: INFO
    javax.activation: info
    org.apache.catalina: INFO
    org.apache.commons.beanutils.converters: INFO
    org.apache.coyote.http11.Http11Processor: INFO
    org.apache.http: INFO
    org.apache.tomcat: INFO
    org.springframework: INFO
    com.chinamobile.cmss.bdpaas.resource.monitor: DEBUG				
				
				
日志输出级别
			
    <Loggers>
        <Logger name="com.ensd.service.sharding.MonthShardingAlgorithm" level="ERROR" />
        <Root level="${sys:log.level}">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
            <AppenderRef ref="Logstash"/>
        </Root>
    </Loggers>			
			
				
读取系统变量/环境变量
				
${sys:catalina.home}/logs
${env:log.home}/logs
				
				
读取 spring 配置

引入依赖

				
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-spring-boot</artifactId>
		</dependency>				
				
				

例子

				 
<Configuration name="ConfigTest" status="ERROR" monitorInterval="5">
	<properties>
		<property name="applicationName">${spring:spring.application.name}</property>
	</properties>
	<Appenders>
	
	<SpringProfile name="dev | staging">
		<Console name="Out">
			<PatternLayout pattern="%m%n"/>
		</Console>
	</SpringProfile>
	<SpringProfile name="prod">
		<List name="Out">
		</List>
	</SpringProfile>
	
	</Appenders>
	<Loggers>
		<Logger name="org.apache.test" level="trace" additivity="false">
		<AppenderRef ref="Out"/>
		</Logger>
		<Root level="error">
		<AppenderRef ref="Out"/>
		</Root>
	</Loggers>
</Configuration>								  
				
				

读取方法 ${spring:spring.profiles.active}

				
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<properties>
		<property name="log.pattern">[%d{yyyy-MM-dd HH:mm:ss}] [${hostName}] [%p] [%t] %l - %m%n</property>
		<property name="log.home">/tmp/logs</property>
		<property name="log.level">info</property>
	</properties>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout pattern="${log.pattern}" />
		</Console>
		<Gelf name="dev" host="udp:172.18.200.10" port="12201" version="1.1" extractStackTrace="true" filterStackTrace="true" mdcProfiling="true" includeFullMdc="true" maximumMessageSize="8192" originHost="%host{fqdn}">
			<Field name="timestamp" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}" />
			<Field name="logger" pattern="%logger" />
			<Field name="level" pattern="%level" />
			<Field name="class" pattern="%C{1}" />
			<Field name="method" pattern="%M" />
			<Field name="line" pattern="%L" />
			<Field name="marker" pattern="%marker" />
			<Filters>
				<MarkerFilter marker="finance" onMatch="ACCEPT" onMismatch="NEUTRAL" />
				<MarkerFilter marker="market" onMatch="ACCEPT" onMismatch="DENY" />
			</Filters>
		</Gelf>
	</Appenders>
	<Loggers>
		<Root level="${sys:log.level}">
			<AppenderRef ref="Console" />
			<AppenderRef ref="${spring:spring.profiles.active:-dev}" />
		</Root>
	</Loggers>
</Configuration>				
				
				

Spring 2.1.4 无法获取配置,解决方法使用 sys,同时启动的时候增加系统配置项 java -Dspring.application.name=netkiller -Dspring.profiles.active=dev -jar netkiller.jar

				 
<property name="service">${sys:spring.application.name}</property>
<property name="environment">${sys:spring.profiles.active}</property>				
				
				
变量默认值

格式是 ${变量名:-默认值}

<property name="service">${sys:spring.application.name:-dev}</property> <property name="environment">${sys:spring.profiles.active:-dev}</property>