y0ngb1n

Aben Blog

欢迎来到我的技术小黑屋ヾ(◍°∇°◍)ノ゙
github

使用 ELK 集中管理 Spring Boot 應用日誌

項目已托管於 GitHub:y0ngb1n/spring-boot-samples,歡迎 Star, Fork 😘


日誌的重要性#

為什麼重要#

  • 運維:醫生給病人看病,日誌就是病人對自己病情的陳述
  • 惡意攻擊、惡意註冊、刷單、惡意密碼猜測等

面對的挑戰#

  • 關注點很多,任何一個點都有可能引起問題
  • 日誌分散在很多機器,出了問題時,才發現日誌被刪了
  • 很多運維人員是消防員,哪裡有問題去哪裡

集中化日誌管理#

日誌搜索 > 格式化分析 > 檢索與可視化 > 風險告警

快速搭建 ELK 集成環境#

技術選型#

那麼,ELK 到底是什麼呢?“ELK” 是三個開源項目的首字母縮寫,這三個項目分別是:

  • E(Elasticsearch)是一個搜索和分析引擎。
  • L(Logstash)是伺服器端數據處理管道,能夠同時從多個來源採集數據,轉換數據,然後將數據發送到諸如 Elasticsearch 等 “存儲庫” 中。
  • K(Kibana)則可以讓用戶在 Elasticsearch 中使用圖形和圖表對數據進行可視化。

快速部署#

使用 Docker 部署上面的基礎環境,參考配置文件 docker-compose.yml,輸入以下命令進行一鍵部署:

# 檢查配置
docker-compose config
# 啟動服務(-d 背景啟動)
docker-compose up -d
# 停止並清除服務
docker-compose down

配置 Logstash#

參考配置文件 logstash-config.conf,示例如下:

input {
  tcp {
    mode => "server"
    host => "0.0.0.0"
    port => 8080
    codec => json_lines
  }
}
output {
  elasticsearch {
    hosts => "elasticsearch:9200"
    # 索引名需參考 index templates 的配置,如:logs-*-*
    # index => "app-logs-%{app_name}-%{+YYYY.MM.dd}"
    index => "app-logs-%{+YYYY.MM.dd}"
  }
}

Spring Boot 集成 ELK 進行日誌管理#

添加依賴 Maven Central#

<dependency>
  <groupId>net.logstash.logback</groupId>
  <artifactId>logstash-logback-encoder</artifactId>
  <version>${logstash-logback-encoder.version}</version>
</dependency>

添加 logback 配置#

方式一:通過 logback-spring.xml 配置#

參考配置文件 logback-spring.xml,示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <include resource="org/springframework/boot/logging/logback/base.xml" />

  <!-- 默認會被序列化到日誌文檔中 -->
  <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>

  <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <destination>192.168.50.88:8880</destination>
    <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" >
      <!-- customFields 的作用是在 Logstash 配置中指定索引名字時的可選參數,日誌文檔中會添加這個字段 -->
      <customFields>{"app_name":"${APP_NAME}"}</customFields>
    </encoder>
  </appender>

  <root level="INFO">
    <appender-ref ref="LOGSTASH" />
    <appender-ref ref="CONSOLE" />
  </root>

</configuration>

方式二:通過 Java Config 配置(可定制 starter)#

@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "elk.logstash", name = "enabled", havingValue = "true")
public class LogstashLogbackConfig {

  private static final String LOGSTASH_APPENDER_NAME = "LOGSTASH";
  private static final String LOGSTASH_ASYNC_APPENDER_NAME = "ASYNC_LOGSTASH";

  @Value("${spring.application.name}")
  private String appName;

  @Autowired
  private LogstashProperties logstash;

  @Bean
  @ConfigurationProperties(prefix = "elk.logstash")
  public LogstashProperties logstash() {
    return new LogstashProperties();
  }

  @PostConstruct
  private void addLogstashAppender() {
    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();

    log.info("Initializing LogstashAppender");
    final LogstashTcpSocketAppender logstashAppender = new LogstashTcpSocketAppender();
    logstashAppender.setName(LOGSTASH_APPENDER_NAME);
    logstashAppender.setContext(loggerContext);
    logstashAppender.addDestinations(
      new InetSocketAddress(this.logstash.getHost(), this.logstash.getPort())
    );

    // https://github.com/logstash/logstash-logback-encoder
    final LogstashEncoder logstashEncoder = new LogstashEncoder();
    logstashEncoder.setIncludeContext(false);
    String customFields = "{\"app_name\":\"" + this.appName +"\",\"idol\":\"yangbin\"}";
    logstashEncoder.setCustomFields(customFields);

    final ShortenedThrowableConverter throwableConverter = new ShortenedThrowableConverter();
    throwableConverter.setRootCauseFirst(true);

    logstashEncoder.setThrowableConverter(throwableConverter);
    logstashAppender.setEncoder(logstashEncoder);
    logstashAppender.start();

    // Wrap the appender in an Async appender for performance
    final AsyncAppender asyncLogstashAppender = new AsyncAppender();
    asyncLogstashAppender.setContext(loggerContext);
    asyncLogstashAppender.setName(LOGSTASH_ASYNC_APPENDER_NAME);
    asyncLogstashAppender.setQueueSize(this.logstash.getQueueSize());
    asyncLogstashAppender.addAppender(logstashAppender);
    asyncLogstashAppender.start();
    loggerContext.getLogger("ROOT").addAppender(asyncLogstashAppender);
  }
}

通過定時器模擬隨機日誌#

...
2021-07-25 23:00:36.552  INFO 15928 --- [           main] i.g.y.s.e.config.LogstashLogbackConfig   : Initializing LogstashAppender
2021-07-25 23:00:36.813  INFO 15928 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-07-25 23:00:37.017  INFO 15928 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
2021-07-25 23:00:37.084  INFO 15928 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-25 23:00:37.095  INFO 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [4a2fa762-9390-48f3-8478-4fcdbf6ba017] mock log event, log something...
2021-07-25 23:00:37.097  WARN 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [c859978e-5150-4fe4-979f-9acd7957a55a] mock log event, log something...
2021-07-25 23:00:37.097 ERROR 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [7625e2e6-62e9-4bbf-a998-1e741723f824] mock log event, log something...
2021-07-25 23:00:37.599  INFO 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [54ba65f2-05d7-4f27-ab63-bd19a0165b6b] mock log event, log something...
2021-07-25 23:00:37.599  WARN 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [901ca6a0-fc7b-4749-8661-4c81f7c4701d] mock log event, log something...
2021-07-25 23:00:37.599 ERROR 15928 --- [   scheduling-1] i.g.y.s.elk.scheduler.MockLogScheduler   : [e2010eda-3f63-49ec-bb97-1157a2b11f01] mock log event, log something...
...

通過 Kibana 管理日誌#

查看由 Logstash 自動創建的索引#

indices

添加 index 索引#

create index pattern

define an index pattern

configure settings

通過 Discover 查看日誌索引信息#

discover logs

參考連結#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。