我被问到如何从作为Oozie的Java动作运行的Spring Boot应用程序中捕获日志输出。
我最初的想法是,可以编辑一些log4j属性以捕获YARN或Oozie中的应用程序日志。然后我想到,对于在各种群集节点上运行的特定应用程序而言,Kafka将是捕获和聚合日志消息的简便得多的方法。通过订阅主题来监视分布式系统比通过日志文件进行钓鱼要容易得多。
我注意到Kafka有一个log4j附加程序,因此我尝试创建一个最小的可复制示例(发布在github上:https : //github.com/alexwoolford/spring-boot-log-to- kafka-example)。这是来自的片段pom.xml:
pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-log4j-appender</artifactId> <version>0.10.0.0</version> </dependency> <dependency> <groupId>net.logstash.log4j</groupId> <artifactId>jsonevent-layout</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> </dependencies>
我的log4j.properties文件如下所示:
log4j.rootLogger=INFO log4j.appender.KAFKA=org.apache.kafka.log4jappender.KafkaLog4jAppender log4j.appender.KAFKA.layout=net.logstash.log4j.JSONEventLayoutV1 log4j.appender.KAFKA.topic=logs log4j.appender.KAFKA.brokerList=hdp-single-node:6667 log4j.appender.KAFKA.syncSend=true log4j.appender.KAFKA.producer.type=async log4j.logger.io.woolford=INFO, KAFKA
除产生警告外,此方法有效:
log4j:WARN No appenders could be found for logger (org.apache.kafka.clients.producer.ProducerConfig). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
即使此应用程序可以运行并且可以满足我的需要,但警告提示我配置错误。您可以看到需要更改的内容吗?
另外,我注意到默认情况下Spring Boot使用Logback,并且我注意到有一个开源项目logback-kafka- appender,它允许Logback追加到Kafka。Kafka log4j附加程序是Spring Boot登录到Kafka的最佳方式吗?
Log4j2具有Kafka附加程序。必须将spring-boot-starter-log4j2和jackson-databind工件添加到pom.xml:
spring-boot-starter-log4j2
jackson-databind
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>logback-classic</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-log4j-appender</artifactId> <version>0.10.0.0</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.6</version> </dependency> </dependencies>
然后,我创建了一个XML格式的log4j2.xml文件:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="info" name="spring-boot-log-to-kafka-example" packages="io.woolford"> <Appenders> <Kafka name="kafkaAppender" topic="logs"> <JSONLayout /> <Property name="bootstrap.servers">hdp-single-node:6667</Property> </Kafka> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="kafkaAppender"/> </Root> <Logger name="org.apache.kafka" level="WARN" /> </Loggers> </Configuration>
记录消息以JSON格式发送到Kafka,例如
{ "timeMillis": 1485736022854, "thread": "Thread-1", "level": "INFO", "loggerName": "org.springframework.context.annotation.AnnotationConfigApplicationContext", "message": "Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@20140db9: startup date [Sun Jan 29 17:26:52 MST 2017]; root of context hierarchy", "endOfBatch": false, "loggerFqcn": "org.apache.commons.logging.impl.SLF4JLocationAwareLog", "threadId": 19, "threadPriority": 5 }