Spring Boot 与 Elasticsearch 日志管理系统

Spring Boot 与 Elasticsearch 日志管理系统

本笔记将详细介绍 Elasticsearch 的基本概念、在 Spring Boot 项目中的配置,以及如何构建一个基于 Elasticsearch 的日志管理系统。这个日志系统能够记录每条日志的级别(如 INFO、ERROR)、服务名称、IP 地址、消息内容和创建时间,并支持日志级别过滤、服务名称过滤和时间范围查询等功能。


一、Elasticsearch 简介

1. 什么是 Elasticsearch

Elasticsearch 是一个基于 Lucene 构建的分布式搜索和分析引擎,主要用于处理大规模的数据搜索和分析任务。它广泛应用于日志管理、应用监控、电子商务、社交媒体分析等场景,支持全文搜索、结构化数据查询、实时分析等操作。

2. Elasticsearch 的核心概念

在 Elasticsearch 中,以下几个核心概念有助于理解其架构和数据存储方式:

  • 节点(Node):Elasticsearch 集群中的一个服务器实例,负责存储数据和处理查询。每个节点包含 Elasticsearch 实例,具备查询、索引、存储等功能。

  • 集群(Cluster):由多个节点组成的集群协同工作来存储和处理大规模数据。集群中的节点共享数据和负载,以提供高可用性和容错性。

  • 索引(Index):相当于数据库中的“表”,用于存储数据的逻辑集合。每个索引包含多个文档,文档结构相似,并按照索引名称管理。

  • 文档(Document):Elasticsearch 中的最小数据单元,类似于关系数据库中的“行”,每个文档以 JSON 格式存储,并包含多个字段。文档记录了具体的数据信息,如日志记录。

  • 分片(Shard):为了提升性能和分布式存储能力,Elasticsearch 将一个索引划分为多个分片,每个分片包含索引的一部分数据。分片可以独立存储和查询,提升数据存取效率。

  • 副本(Replica):每个分片的备份,用于提升数据的高可用性。分片不可用时,其副本可以继续提供服务。

3. Elasticsearch 数据类型

Elasticsearch 支持丰富的数据类型,每种类型有特定的用途:

  • Text:用于全文检索的字符串数据,适合需要分词的字段,如日志信息和描述内容。
  • Keyword:不进行分词的字符串数据,适合用于精确匹配的字段,如用户名、标签等。
  • Date:日期数据类型,支持时间范围查询,常用于日志时间字段。
  • Integer、Long、Float、Double:数值类型,用于存储整数和小数数据。
  • Boolean:布尔类型,用于存储 truefalse 的数据。
  • Ip:IP 地址类型,专门用于存储和查询 IPv4 地址。

4. Elasticsearch 特性

  • 分布式架构:Elasticsearch 是分布式系统,可以将数据存储在不同节点和分片中,实现数据的高可用性和负载均衡。
  • 强大的全文搜索功能:基于 Lucene 构建,支持高效的全文检索、分词、相似度计算和高级查询。
  • 实时分析:提供实时的统计和分析功能,适合监控和日志管理。
  • 近实时(NRT):Elasticsearch 支持近实时的数据写入和查询,数据写入后几秒钟内即可查询。

5. 常见应用场景

  • 日志管理:集中存储和分析应用程序的日志,支持快速检索、过滤和统计。
  • 全文搜索:用于电商和社交应用中的文本搜索。
  • 实时监控:收集、存储和分析系统和应用性能数据。
  • 大数据分析:对大数据集进行快速聚合和分析。

二、项目结构与需求

我们将构建一个日志管理系统,基于 Spring Boot 和 Elasticsearch 实现。项目需求包括:

  1. 记录日志:保存新的日志条目,记录日志级别、服务名称、IP 地址、消息内容和创建时间。
  2. 查询日志:支持根据日志级别、服务名称和时间范围的条件查询。
  3. 删除日志:根据日志的唯一 ID 删除日志条目。

项目文件结构

src/
└── main/
    ├── java/
    │   └── com/
    │       └── example/
    │           └── logsystem/
    │               ├── config/
    │               │   └── ElasticsearchConfig.java          # Elasticsearch 配置类
    │               ├── domain/
    │               │   └── LogEntry.java                     # 日志实体类
    │               ├── repository/
    │               │   └── LogRepository.java                # Elasticsearch 仓库接口
    │               ├── service/
    │               │   ├── LogService.java                   # 日志服务接口
    │               │   └── LogServiceImpl.java               # 日志服务实现类
    │               └── controller/
    │                   └── LogController.java                # 日志控制器
    └── resources/
        └── application.yml                                  # Spring Boot 配置文件

三、Elasticsearch 配置

为了让 Spring Boot 项目能够连接到 Elasticsearch,我们需要在 application.yml 中配置 Elasticsearch 的 URI 和其他连接信息,并在项目中创建配置类以生成 RestHighLevelClient 实例。

1. application.yml 配置文件

文件位置src/main/resources/application.yml

spring:
  elasticsearch:
    uris: http://localhost:9200           # Elasticsearch 服务器地址
    connection-timeout: 5s                # 连接超时时间
    socket-timeout: 3s                    # 读写超时时间
    username: elastic                     # 用户名(如有配置)
    password: password                    # 密码(如有配置)

配置说明

  • spring.elasticsearch.uris:指定 Elasticsearch 的 URI 地址,通常为 http://localhost:9200
  • spring.elasticsearch.connection-timeoutspring.elasticsearch.socket-timeout:定义连接和数据传输的超时时间。
  • spring.elasticsearch.usernamepassword:用于认证,确保只有合法用户能访问 Elasticsearch 数据。

2. 配置类 ElasticsearchConfig.java

文件位置src/main/java/com/example/logsystem/config/ElasticsearchConfig.java

配置类 ElasticsearchConfig 使用 @Configuration 注解,生成一个 RestHighLevelClient 的 Spring Bean,便于项目中的依赖注入。

package com.example.logsystem.config;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticsearchConfig {

    @Value("${spring.elasticsearch.uris}")
    private String elasticsearchUri;

    @Value("${spring.elasticsearch.username}")
    private String username;

    @Value("${spring.elasticsearch.password}")
    private String password;

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        // 将 URI 字符串拆分为主机和端口号
        String[] uriParts = elasticsearchUri.replace("http://", "").split(":");
        String hostname = uriParts[0];
        int port = Integer.parseInt(uriParts[1]);

        // 配置认证信息
        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

        // 构建 RestClient,并配置连接池参数
        RestClientBuilder builder = RestClient.builder(new HttpHost(hostname, port, "http"))
            .setHttpClientConfigCallback(httpClientBuilder -> 
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                                 .setMaxConnTotal(30)        // 最大连接数
                                 .setMaxConnPerRoute(10));   // 每个路由的最大连接数

        return new RestHighLevelClient(builder);  // 返回 RestHighLevelClient 实例
    }
}

四、定义日志实体类

LogEntry 类定义了日志的字段和数据结构,使用 @Document 注解将其映射到 Elasticsearch 索引中。

LogEntry.java

文件位置src/main/java/com/example/logsystem/domain/LogEntry.java

package com.example.logsystem.domain;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.time.LocalDateTime;

@Document(indexName = "log_entries")
public class LogEntry {

    @Id
    private String id;

    @Field(type = FieldType.Keyword)
    private String level

;

    @Field(type = FieldType.Keyword)
    private String serviceName;

    @Field(type = FieldType.Ip)
    private String ipAddress;

    @Field(type = FieldType.Text)
    private String message;

    @Field(type = FieldType.Date)
    private LocalDateTime timestamp;

    // Getters and Setters
}

代码说明

  • @Document(indexName = "log_entries"):将 LogEntry 类映射到 Elasticsearch 索引 log_entries
  • 字段定义
    • levelserviceName 使用 Keyword 类型,用于精确匹配。
    • ipAddress 使用 Ip 类型,适合存储 IP 地址。
    • message 使用 Text 类型,支持全文检索。
    • timestamp 使用 Date 类型,支持时间范围查询。

五、定义 Repository 接口

LogRepository 继承 ElasticsearchRepository,提供了 CRUD 操作和自定义查询功能。

LogRepository.java

文件位置src/main/java/com/example/logsystem/repository/LogRepository.java

package com.example.logsystem.repository;

import com.example.logsystem.domain.LogEntry;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface LogRepository extends ElasticsearchRepository<LogEntry, String> {

    // 自定义查询方法:根据日志级别查询
    List<LogEntry> findByLevel(String level);

    // 自定义查询方法:根据服务名称和时间范围查询
    List<LogEntry> findByServiceNameAndTimestampBetween(String serviceName, LocalDateTime start, LocalDateTime end);
}

六、定义服务接口和实现类

服务接口 LogService.java

文件位置src/main/java/com/example/logsystem/service/LogService.java

package com.example.logsystem.service;

import com.example.logsystem.domain.LogEntry;

import java.time.LocalDateTime;
import java.util.List;

public interface LogService {

    LogEntry saveLog(LogEntry logEntry);

    List<LogEntry> getAllLogs();

    List<LogEntry> getLogsByLevel(String level);

    List<LogEntry> getLogsByServiceAndTime(String serviceName, LocalDateTime start, LocalDateTime end);

    void deleteLog(String id);
}

服务实现类 LogServiceImpl.java

文件位置src/main/java/com/example/logsystem/service/LogServiceImpl.java

package com.example.logsystem.service;

import com.example.logsystem.domain.LogEntry;
import com.example.logsystem.repository.LogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class LogServiceImpl implements LogService {

    @Autowired
    private LogRepository logRepository;

    @Override
    public LogEntry saveLog(LogEntry logEntry) {
        logEntry.setTimestamp(LocalDateTime.now());  // 设置时间戳为当前时间
        return logRepository.save(logEntry);
    }

    @Override
    public List<LogEntry> getAllLogs() {
        return (List<LogEntry>) logRepository.findAll();  // 返回所有日志
    }

    @Override
    public List<LogEntry> getLogsByLevel(String level) {
        return logRepository.findByLevel(level);  // 根据级别过滤日志
    }

    @Override
    public List<LogEntry> getLogsByServiceAndTime(String serviceName, LocalDateTime start, LocalDateTime end) {
        return logRepository.findByServiceNameAndTimestampBetween(serviceName, start, end);  // 根据服务和时间过滤日志
    }

    @Override
    public void deleteLog(String id) {
        logRepository.deleteById(id);  // 删除指定 ID 的日志
    }
}

七、定义控制器

LogController 提供 RESTful API,用于处理前端或客户端的日志操作请求。

LogController.java

文件位置src/main/java/com/example/logsystem/controller/LogController.java

package com.example.logsystem.controller;

import com.example.logsystem.domain.LogEntry;
import com.example.logsystem.service.LogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@RestController
@RequestMapping("/api/logs")
public class LogController {

    @Autowired
    private LogService logService;

    // 保存新的日志条目
    @PostMapping
    public LogEntry saveLog(@RequestBody LogEntry logEntry) {
        return logService.saveLog(logEntry);
    }

    // 查询所有日志条目
    @GetMapping
    public List<LogEntry> getAllLogs() {
        return logService.getAllLogs();
    }

    // 根据日志级别查询日志
    @GetMapping("/level/{level}")
    public List<LogEntry> getLogsByLevel(@PathVariable String level) {
        return logService.getLogsByLevel(level);
    }

    // 根据服务名称和时间范围查询日志
    @GetMapping("/service")
    public List<LogEntry> getLogsByServiceAndTime(
            @RequestParam String serviceName,
            @RequestParam LocalDateTime start,
            @RequestParam LocalDateTime end) {
        return logService.getLogsByServiceAndTime(serviceName, start, end);
    }

    // 删除日志条目
    @DeleteMapping("/{id}")
    public void deleteLog(@PathVariable String id) {
        logService.deleteLog(id);
    }
}

总结

  1. 配置类ElasticsearchConfig 中配置 RestHighLevelClient,用于连接 Elasticsearch。
  2. 实体类LogEntry 定义日志的字段和数据类型。
  3. 仓库接口LogRepository 提供日志的基本操作。
  4. 服务接口和实现LogServiceLogServiceImpl 实现日志的存储和查询功能。
  5. 控制器LogController 提供 RESTful API,用于对外提供日志管理服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值