当前位置:   article > 正文

Spring boot admin 日志_springboot admin 日志

springboot admin 日志

前言

以前写过Spring Boot Admin的使用教程,还配置了各种路径参数。最近有留言说client的log怎么查看,其实log这个没写是因为,不能满足性能与管理的需要,ELK技术很成熟,搜索也是,备份管理都有现成的,但是估计有些小公司不需要这样的技术,只需要可以快速查看的日志入口就可以了。下面来试试。

1. SBA log示例

此次使用consul + admin + client

1. 1 consul启动

由于我的电脑是macos,只需要./consul agent -dev即可,win更容易,直接双击启动

1.2 admin server

pom依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring-boot-admin</artifactId>
  7. <groupId>org.example</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>admin-derver</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>de.codecentric</groupId>
  15. <artifactId>spring-boot-admin-starter-server</artifactId>
  16. <version>2.3.0</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. <version>2.3.4.RELEASE</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-actuator</artifactId>
  26. <version>2.3.4.RELEASE</version>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.cloud</groupId>
  30. <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  31. <version>2.2.4.RELEASE</version>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.slf4j</groupId>
  35. <artifactId>slf4j-api</artifactId>
  36. <version>1.7.30</version>
  37. </dependency>
  38. </dependencies>
  39. </project>

bootMain类

  1. package com.feng.admin.server;
  2. import de.codecentric.boot.admin.server.config.EnableAdminServer;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  6. @SpringBootApplication
  7. @EnableAdminServer
  8. @EnableDiscoveryClient
  9. public class ServerMain {
  10. public static void main(String[] args) {
  11. SpringApplication.run(ServerMain.class, args);
  12. }
  13. }

application

  1. server.port=8082
  2. spring.application.name=AdminServer
  3. management.endpoint.health.show-details=always
  4. management.endpoints.web.exposure.include=*
  5. spring.cloud.consul.host=localhost
  6. spring.cloud.consul.port=8500
  7. spring.cloud.consul.discovery.service-name=${spring.application.name}

1.3 admin client

client同理,复制AdminServer,即可去除<artifactId>spring-boot-admin-starter-server</artifactId>依赖即可,去除AdminServer注解,修改端口

查看结果 

2. client log改造

所谓的log实时查看是client提供一个读取本地文件的接口,然后admin定时调用显示,达到实时展示的效果。需要2步即可

2.1 application增加

management.endpoint.logfile.external-file=/Users/huahua/logs/boot.log

还有其他方式,后面说

2.2 增加logback-spring.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3. <property name="APP_Name" value="logback" />
  4.    <contextName>${APP_Name}</contextName>
  5. <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径,请根据需求配置路径-->
  6. <property name="LOG_HOME" value="/Users/huahua/logs/" />
  7. <!-- 彩色日志依赖的渲染类 -->
  8. <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
  9. <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
  10. <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
  11. <!-- 彩色日志格式 -->
  12. <property name="CONSOLE_LOG_PATTERN"
  13. value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(LN:%L){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
  14. <!-- 控制台输出 -->
  15. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  16. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  17. <pattern>${CONSOLE_LOG_PATTERN}</pattern>
  18. <charset>utf8</charset>
  19. </encoder>
  20. </appender>
  21. <!-- 按照每天生成日志文件 -->
  22. <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  23. <file>${LOG_HOME}/boot.log</file>
  24. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  25. <!--日志文件输出的文件名-->
  26. <FileNamePattern>${LOG_HOME}/boot-%d{yyyy-MM-dd}.log</FileNamePattern>
  27. <!--日志文件保留天数-->
  28. <MaxHistory>3</MaxHistory>
  29. </rollingPolicy>
  30. <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
  31. <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
  32. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
  33. </encoder>
  34. </appender>
  35. <logger name="org.springframework.boot.actuate.endpoint.web.servlet" level="trace"/>
  36. <!-- 日志输出级别 ,注意:如果不写<appender-ref ref="FILE" /> ,将导致springbootadmin找不到文件,无法查看日志 -->
  37. <root level="INFO">
  38. <appender-ref ref="STDOUT" />
  39. <appender-ref ref="FILE" />
  40. </root>
  41. </configuration>

注意这个,必须为trace,可以打印actuator的HTTP requestmapping信息

<logger name="org.springframework.boot.actuate.endpoint.web.servlet" level="trace"/>

重点关注logfile接口,这个接口必须配置参数才能出现

2.3 效果如下

F12可以看到,页面在定时请求

3. 原理分析

根源在一个自动配置上

  1. public class LogFile {
  2. public static final String FILE_NAME_PROPERTY = "logging.file.name";
  3. public static final String FILE_PATH_PROPERTY = "logging.file.path";
  4. package org.springframework.boot.actuate.autoconfigure.logging;
  5. import org.springframework.beans.factory.ObjectProvider;
  6. import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
  7. import org.springframework.boot.actuate.logging.LogFileWebEndpoint;
  8. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  9. import org.springframework.boot.autoconfigure.condition.ConditionMessage;
  10. import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
  11. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  12. import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
  13. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  14. import org.springframework.boot.logging.LogFile;
  15. import org.springframework.context.annotation.Bean;
  16. import org.springframework.context.annotation.ConditionContext;
  17. import org.springframework.context.annotation.Conditional;
  18. import org.springframework.context.annotation.Configuration;
  19. import org.springframework.core.env.Environment;
  20. import org.springframework.core.type.AnnotatedTypeMetadata;
  21. import org.springframework.util.StringUtils;
  22. /**
  23. * {@link EnableAutoConfiguration Auto-configuration} for {@link LogFileWebEndpoint}.
  24. *
  25. * @author Andy Wilkinson
  26. * @author Christian Carriere-Tisseur
  27. * @since 2.0.0
  28. */
  29. @Configuration(proxyBeanMethods = false)
  30. @ConditionalOnAvailableEndpoint(endpoint = LogFileWebEndpoint.class)
  31. @EnableConfigurationProperties(LogFileWebEndpointProperties.class)
  32. public class LogFileWebEndpointAutoConfiguration {
  33. @Bean
  34. @ConditionalOnMissingBean
  35. //条件式,很关键,默认条件是false
  36. @Conditional(LogFileCondition.class)
  37. public LogFileWebEndpoint logFileWebEndpoint(ObjectProvider<LogFile> logFile,
  38. LogFileWebEndpointProperties properties) {
  39. return new LogFileWebEndpoint(logFile.getIfAvailable(), properties.getExternalFile());
  40. }
  41. private static class LogFileCondition extends SpringBootCondition {
  42. @Override
  43. //条件判定
  44. public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
  45. Environment environment = context.getEnvironment();
  46. String config = getLogFileConfig(environment, LogFile.FILE_NAME_PROPERTY);
  47. ConditionMessage.Builder message = ConditionMessage.forCondition("Log File");
  48. if (StringUtils.hasText(config)) {
  49. return ConditionOutcome.match(message.found(LogFile.FILE_NAME_PROPERTY).items(config));
  50. }
  51. config = getLogFileConfig(environment, LogFile.FILE_PATH_PROPERTY);
  52. if (StringUtils.hasText(config)) {
  53. return ConditionOutcome.match(message.found(LogFile.FILE_PATH_PROPERTY).items(config));
  54. }
  55. config = environment.getProperty("management.endpoint.logfile.external-file");
  56. if (StringUtils.hasText(config)) {
  57. return ConditionOutcome.match(message.found("management.endpoint.logfile.external-file").items(config));
  58. }
  59. return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
  60. }
  61. private String getLogFileConfig(Environment environment, String configName) {
  62. return environment.resolvePlaceholders("${" + configName + ":}");
  63. }
  64. }
  65. }

所以logging.file.name、logging.file.path、management.endpoint.logfile.external-file都可以开启条件

logging.file.path配置要注意,这个是个坑,会默认spring.log的文件,logging.file.name不会

  1. public String toString() {
  2. return StringUtils.hasLength(this.file) ? this.file : (new File(this.path, "spring.log")).getPath();
  3. }

另外可以看到LogFileWebEndpointProperties这个配置

所以management.endpoint.logfile.externalFile也是可以的,实际上

Spring在解析properties时会在Spring缓存的Map中,把management.endpoint.logfile.external-file的key会转换成management.endpoint.logfile.externalFile。

 

最终的结果是实例化LogFileWebEndpoint,创建endpoint的requestmapping接口映射

  1. /*
  2. * Copyright 2012-2019 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.boot.actuate.logging;
  17. import java.io.File;
  18. import org.apache.commons.logging.Log;
  19. import org.apache.commons.logging.LogFactory;
  20. import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
  21. import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
  22. import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
  23. import org.springframework.boot.logging.LogFile;
  24. import org.springframework.core.io.FileSystemResource;
  25. import org.springframework.core.io.Resource;
  26. /**
  27. * Web {@link Endpoint @Endpoint} that provides access to an application's log file.
  28. *
  29. * @author Johannes Edmeier
  30. * @author Phillip Webb
  31. * @author Andy Wilkinson
  32. * @since 2.0.0
  33. */
  34. @WebEndpoint(id = "logfile")
  35. public class LogFileWebEndpoint {
  36. private static final Log logger = LogFactory.getLog(LogFileWebEndpoint.class);
  37. private File externalFile;
  38. private final LogFile logFile;
  39. public LogFileWebEndpoint(LogFile logFile, File externalFile) {
  40. this.externalFile = externalFile;
  41. this.logFile = logFile;
  42. }
  43. @ReadOperation(produces = "text/plain; charset=UTF-8")
  44. //最终是requestmapping,访问这个方法,本质是读取文件
  45. public Resource logFile() {
  46. Resource logFileResource = getLogFileResource();
  47. if (logFileResource == null || !logFileResource.isReadable()) {
  48. return null;
  49. }
  50. return logFileResource;
  51. }
  52. private Resource getLogFileResource() {
  53. if (this.externalFile != null) {
  54. return new FileSystemResource(this.externalFile);
  55. }
  56. if (this.logFile == null) {
  57. logger.debug("Missing 'logging.file.name' or 'logging.file.path' properties");
  58. return null;
  59. }
  60. return new FileSystemResource(this.logFile.toString());
  61. }
  62. }

 

总结

其实Spring Boot Admin显示client的日志原理很简单,client暴露HTTP,admin定时调用。client端取日志需要配置才能开启,是读取本地文件。

源码分析也验证了上面的观点。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/102024
推荐阅读
相关标签
  

闽ICP备14008679号