Spring Data Elasticsearch

文章目录

    • 一、 ELK
    • 二、 Elasticsearch简介
    • 三、 Linux安装Elasticsearch
    • 四、SpringData Elasticsearch
        • pom.xml
        • application.yml
        • 创建实体
        • 创建索引 设置映射
        • 简单增删改查
        • 搜索
    • 五、 LogStash
    • 六、 使用Logback向Logstash中输出日志
    • 七、 在Kibana中查看日志信息
    • 八、 搭建日志系统
    • 九、 在Java代码中获取日志信息

一、 ELK

Elasticsearch官网中提供了很多技术,其中一些技术是可以配合使用的,里面比较出名的就是ELK技术栈。
ELK是Elasticsearch、Logstash、Kibana三个软件首字母。
Elasticsearch: 全文检索工具。
Kibana:页面管理工具。可以通过Kibana的管理界面操作Elasticsearch
Logstash:日志收集的工具,通过此工具可以实现日志内容收集及格式转换。

二、 Elasticsearch简介

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式的全文搜索引擎,其对外服务是基于RESTful web接口发布的。Elasticsearch是用Java开发的应用,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到近实时搜索,稳定,可靠,快速,安装使用方便。

1 功能分类

Elasticsearch具备两个主要功能:
搜索。功能和Solr类似。代替目前(海量数据)的MySQL模糊查询。
分析。结合LogStash使用。

2 相关概念

2.1 cluster
集群。Elasticsearch集群由一或多个节点组成,其中有一个主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。Elasticsearch的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部看Elasticsearch集群,在逻辑上是个整体,你与集群中的任何一个节点通信和与整个Elasticsearch集群通信是等价的。也就是说,主节点的存在不会产生单点安全隐患、并发访问瓶颈等问题。
2.2 Index
索引。相当于关系型数据库中的表。其中存储若干相似结构的Document数据。如:客户索引,订单索引,商品索引等。Elasticsearch中的索引不像数据库表格一样有强制的数据结构约束,在理论上,可以存储任意结构的数据。但了为更好的为业务提供搜索数据支撑,还是要设计合适的索引体系来存储不同的数据。
2.3 shards
primary shard:代表索引的主分片,Elasticsearch可以把一个完整的索引分成多个primary shard,这样的好处是可以把一个大的索引拆分成多个分片,分布存储在不同的Elasticsearch节点上,从而形成分布式存储,并为搜索访问提供分布式服务,提高并发处理能。primary shard的数量只能在索引创建时指定,并且索引创建后不能再更改primary shard数量。
2.4 replicas
replica shard:代表索引主分片的副本,Elasticsearch可以设置多个replica shard。replica shard的作用:一是提高系统的容错性,当某个节点某个primary shard损坏或丢失时可以从副本中恢复。二是提高Elasticsearch的查询效率,Elasticsearch会自动对搜索请求进行负载均衡,将并发的搜索请求发送给合适的节点,增强并发处理能力。
2.5 Type
类型。每个索引中都必须有唯一的一个Type,Type是Index中的一个逻辑分类。Elasticsearch中的数据Document是存储在索引下的Type中的。
注意:Elasticsearch5.x及更低版本中,一个Index中可以有多个Type。Elasticsearch6.x版本之后,type概念被弱化,一个index中只能有唯一的一个type。且在7.x版本之后,删除type定义。
2.6 Document
文档。Elasticsearch中的最小数据单元。一个Document就是一条数据,一般使用JSON数据结构表示。每个Index下的Type中都可以存储多个Document。一个Document中可定义多个field,field就是数据字段。如:学生数据({“name”:“张三”, “age”:20, “gender”:“男”})。
2.7 元数据
在Elasticsearch中所有以“_”开头的属性都成为元数据,都有着自己特定的含义。
例如:_index:表示索引
2.8 倒排索引(Elasticsearch搜索原理,面试题)反向索引
对数据进行分析,抽取出数据中的词条,以词条作为key,对应数据的存储位置作为value,实现索引的存储。这种索引称为倒排索引。倒排索引是Document写入Elasticsearch时分析维护的。

3 Elasticsearch常见使用场景

维基百科:全文检索,高亮显示,搜索推荐The Guardian(国外的一个新闻网站),此平台可以对用户的行为(点击、浏览、收藏、评论)、社区网络数据(对新闻的评论等)进行数据分析,为新闻的发布者提供相关的公众反馈。
Stack Overflow(国外的程序异常讨论论坛)
Github(开源代码管理),在千亿级别的代码行中搜索信息电子商务平台等。

三、 Linux安装Elasticsearch

使用的Elasticsearch的版本是7.6.2。Elasticsearch7.x要求Linux内核必须是4+版本以上。
在linux操作系统中,查看内核版本的命令是: uname -a
课堂使用的Linux是CentOS8。内核使用的是4.18。

1 基于Docker安装

1.1.1 拉取Elasticsearch镜像
如果docker还没有开启。需要先开始docker软件
systemctl start docker
拉取Elasticsearch镜像
docker pull elasticsearch:7.6.2
1.1.2 创建并启动容器
docker run --name=elasticsearch -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
discovery.type=single-node 集群模式:单机版
1.1.3 查看日志
docker logs -f elasticsearch
如果日志中出现started状态,说明启动成功
1.1.4 测试结果
curl http://localhost:9200

1.2 基于Docker的Kibana

Kibana的版本必须和ES的版本对应。
1.2.1 拉取镜像
docker pull kibana:7.6.2
1.2.2 新建并启动容器
docker run -d --name kibana --link elasticsearch:elasticsearch -p 5601:5601 kibana:7.6.2
1.2.3 修改Kibana参数
# docker exec -it kibana /bin/bash
# cd config
# vi kibana.yml
选中部分修改成Docker的IP
在这里插入图片描述
重启docker容器
# docker restart kibana
1.2.4 访问
在浏览器输入 http://192.168.8.137:5601

四、SpringData Elasticsearch

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"><modelVersion>4.0.0</modelVersion><groupId>com.bjsxt</groupId><artifactId>ol_data_elasticsearch</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>6.6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>

application.yml

spring:elasticsearch:rest:uris: http://192.168.8.132:9200

创建实体

package com.bjsxt.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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.io.Serializable;/*** 商品类型** Document - 描述当前类型对应一个Elasticsearch中的索引。*  必要属性:*    indexName - 对应的索引命名*  可选属性:*    shards - 主分片数量, 默认1.*    replicas - 副本分片数量,默认1.*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "java_item", shards = 1, replicas = 0)
public class Item implements Serializable {/*** Id - 当前的属性,对应Elasticsearch中索引的_id元数据。代表主键。*      且,当前属性会在Elasticsearch保存的数据结构中。{"id":"", "title":"", "remark":""}*/@Id@Field(name = "id", type = FieldType.Keyword)private String id; // 主键/*** Field - 描述Java类型中的属性的映射*  name - 对应的ES索引中的字段名。默认和属性同名。*  type - 对应的字段类型,默认是FieldType.Auto。建议定义正确的映射类型。避免可能发生的映射错误。*  index - 是否创建索引,text类型创建倒排索引,其他类型创建正排索引。默认true*/@Field(name = "title", type = FieldType.Text, analyzer = "ik_max_word")private String title; // 标题@Field(name = "remark", type = FieldType.Text, analyzer = "ik_smart")private String remark; // 详情@Field(name = "price", type = FieldType.Long)private Long price; // 单价, 单位是分@Field(name = "number", type = FieldType.Integer, index = false)private int num; // 库存数量
}

创建索引 设置映射

@SpringBootTest(classes = {MyDataElasticsearchApplication.class})
@RunWith(SpringRunner.class)
public class TestDataElasticsearch {// 基于HTTP协议,9200端口的RestAPI访问客户端。@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Testpublic void createAndPutMapping(){// 创建索引elasticsearchRestTemplate.indexOps(Item.class).create();// 设置映射elasticsearchRestTemplate.indexOps(Item.class).putMapping(elasticsearchRestTemplate.indexOps(Item.class).createMapping());}

简单增删改查

@SpringBootTest(classes = {MyDataElasticsearchApplication.class})
@RunWith(SpringRunner.class)
public class TestDataElasticsearch {// 基于HTTP协议,9200端口的RestAPI访问客户端。@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;@Testpublic void testGet(){// 主键查询数据Item item = elasticsearchRestTemplate.get("001", Item.class);System.out.println(item);}@Testpublic void testDeleteDocument(){// 主键删除String result = elasticsearchRestTemplate.delete("-P8E8XcBBxUhJQR7_GTO", Item.class);System.out.println(result);}/*** 使用覆盖方式实现更新。就是使用save方法。参数对象的主键有数据,且对应ES中的主键,则是覆盖。*/@Testpublic void testSave(){// 保存单条数据。 返回值就是保存的对象。 如果参数对象中Id主键属性值是null,则返回的对象中Id值是ES生成的主键。Item item = elasticsearchRestTemplate.save(new Item("001", "华为P40", "2020年生产,高端手机", 429900L, 999));System.out.println(item);item = elasticsearchRestTemplate.save(new Item(null, "华为P40 Pro", "华为P40增强版手机", 589900L, 999));System.out.println(item);// 批量新增,返回值特性和保存单条数据一致。List<Item> items = new ArrayList<>();items.add(new Item("003", "华为P40 Pro Plus", "华为P40Pro增强版手机", 629900L, 999));items.add(new Item("004", "小米10", "很贵的暖手宝", 229900L, 999));items.add(new Item("005", "三星", "可以自卫,容易误伤", 329900L, 999));Iterable<Item> results = elasticsearchRestTemplate.save(items);for(Item i : results){System.out.println(i);}}@Testpublic void deleteIndex(){// 所有针对索引的操作都封装在IndexOperations类型中。IndexOperations indexOps = elasticsearchRestTemplate.indexOps(Item.class);indexOps.delete();}

搜索

package com.bjsxt.test;import com.bjsxt.MyDataElasticsearchApplication;
import com.bjsxt.pojo.Item;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;
import java.util.List;@SpringBootTest(classes = {MyDataElasticsearchApplication.class})
@RunWith(SpringRunner.class)
public class TestDataElasticsearch {// 基于HTTP协议,9200端口的RestAPI访问客户端。@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;// 高亮搜索@Testpublic void testHighlight(){// 定义高亮字段HighlightBuilder.Field titleField = new HighlightBuilder.Field("title");titleField.preTags("<span style='color:red'>");titleField.postTags("</span>");titleField.fragmentSize(2);titleField.numOfFragments(1);// withHighlightFields(Field... 高亮字段数组)Query query =new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "华为")).withHighlightFields(titleField).build();SearchHits<Item> hits =elasticsearchRestTemplate.search(query, Item.class);// 注意, Item对象中,不包含高亮数据,需要手工处理。for(SearchHit<Item> hit : hits){Item item = hit.getContent();// 处理高亮的方式// 根据高亮字段名称,获取高亮数据集合。返回结果是List<String>List<String> hlList = hit.getHighlightField("title");if(hlList != null && hlList.size() > 0){// 有高亮数据item.setTitle(hlList.get(0));}System.out.println(item);}}// 排序和分页// withPageable(Pageable) 设置分页+排序// Pageable接口有实现类,类型是PageRequest,静态方法of.// of(int page, int size[, Sort sort]) ; page 第几页,从0开始计数;  size 每页查询多少条数据// Sort 排序类型, 静态方法  Sort.by(Direction 升降序, String... 按照哪一个字段排序)// Sort.by(Sort.Order... 多字段排序方案)  Sort.Order.desc("降序字段名")   Sort.Order.asc("升序字段名")@Testpublic void testSortAndPageable(){Query query =new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).withPageable(PageRequest.of(1, 2,Sort.by(Sort.Order.desc("price"),Sort.Order.asc("title")))).build();SearchHits<Item> hits =elasticsearchRestTemplate.search(query, Item.class);for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// 搜索数据 search// DSL bool@Testpublic void testBool(){// 创建一个bool搜索条件。  bool:{ must:[{match:{field:value}}], must_not:[], should:[] }BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();// 获取bool搜索条件中的Must条件集合。增加到集合中的条件,就是必要条件。List<QueryBuilder> must = queryBuilder.must();must.add(QueryBuilders.rangeQuery("price").gt(100000L));// 其他的搜索条件集合获取方式相似。List<QueryBuilder> mustNot = queryBuilder.mustNot();List<QueryBuilder> should = queryBuilder.should();// 简化设置搜索条件的方式是,下述代码相当于: queryBuilder.should().add(QueryBuilders.matchAllQuery());queryBuilder.should(QueryBuilders.matchAllQuery());Query query = new NativeSearchQueryBuilder().withQuery(queryBuilder).build();SearchHits<Item> hits =elasticsearchRestTemplate.search(query, Item.class);for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// DSL match all@Testpublic void testMatchAll(){SearchHits<Item> hits =elasticsearchRestTemplate.search(new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).build(),Item.class);for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// DSL match phrase@Testpublic void testMatchPhrase(){SearchHits<Item> hits =elasticsearchRestTemplate.search(new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchPhraseQuery("title", "华为P40 Pro")).build(),Item.class);for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// DSL range@Testpublic void testRangeQuery(){SearchHits<Item> hits =elasticsearchRestTemplate.search(new NativeSearchQueryBuilder().withQuery(QueryBuilders.rangeQuery("price").gt(200000L).lt(500000L)).build(),Item.class);for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// DSL match@Testpublic void testMatchQuery(){SearchHits<Item> hits =elasticsearchRestTemplate.search(new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("title", "小米")).build(),Item.class);System.out.println("数据数量: " + hits.getTotalHits());for(SearchHit<Item> hit : hits){System.out.println(hit.getContent());}}// query string search。  在所有的字段中搜索。@Testpublic void testQueryString(){// 所有的搜索逻辑,都是通过search实现的。/** SearchHits<T> search(Query query, Class<T> clazz)* 返回值,就是在Kibana控制台上,搜索的结果JSON转换的Java对象。* 泛型就是搜索结果数据,转换的Java对象类型。* 参数query,就是搜索条件。* 搜索条件,建议使用构建器来创建。** QueryBuilder - 用来描述搜索条件的。在DSL和querystring两种搜索中,有什么搜索方式,就有对应的实现类型。* 如:querystring - QueryStringQueryBuilder* 如:DSL中的match - MatchQueryBuilder* 如:DSL中的range - RangeQueryBuilder*/QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("华为");Query query =new NativeSearchQueryBuilder().withQuery(queryBuilder).build();SearchHits<Item> hits = elasticsearchRestTemplate.search(query, Item.class);System.out.println("总计数据行数: " + hits.getTotalHits());System.out.println(elasticsearchRestTemplate.indexOps(Item.class));// SearchHits类型,本身实现了集合接口|可迭代接口。for(SearchHit<Item> hit : hits){Item item = hit.getContent();System.out.println("SearchHits.toString() - " + hits.toString());System.out.println("SearchHit.toString() - " + hit.toString());System.out.println("_id - " + hit.getId());System.out.println("查询到的商品对象 - " + item);}System.out.println("=====================================================================");for(SearchHit<Item> hit : hits.getSearchHits()){System.out.println("查询到的商品 - " + hit.getContent());}}

五、 LogStash

1 什么是LogStash

官方文字说明:Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。
通俗说明:Logstash是一款强大的数据处理工具,常用作日志处理。
到目前为止,Logstash已经有超过200个可用的插件,以及创建和贡献自己的灵活性。社区生态非常完善,对于我们可以放心的使用。
在这里插入图片描述
在这里插入图片描述

2 为什么使用Logstash

通常当系统发生故障时,工程师需要登录到各个服务器上,使用 grep / sed / awk 等 Linux 脚本工具去日志里查找故障原因。在没有日志系统的情况下,首先需要定位处理请求的服务器,如果这台服务器部署了多个实例,则需要去每个应用实例的日志目录下去找日志文件。每个应用实例还会设置日志滚动策略(如:每天生成一个文件),还有日志压缩归档策略等。
这样一系列流程下来,对于我们排查故障以及及时找到故障原因,造成了比较大的麻烦。因此,如果我们能把这些日志集中管理,并提供集中检索功能,不仅可以提高诊断的效率,同时对系统情况有个全面的理解,避免事后救火的被动。
所以日志集中管理功能就可以使用ELK技术栈进行实现。Elasticsearch只有数据存储和分析的能力,Kibana就是可视化管理平台。还缺少数据收集和整理的角色,这个功能就是Logstash负责的。

3 Logstash工作原理

3.1 Data Source
Logstash 支持的数据源有很多。例如对于日志功能来说只能能有日志记录和日志传递功能的日志都支持,Spring Boot中默认推荐logback支持日志输出功能(输出到数据库、数据出到文件)。
我们就使用logback进行日志输出给Logstash。
3.2 Logstash Pipeline
整个整体就是Logstash的功能。
在Logstash中包含非常重要的三个功能:
a) Input
输入源,一般配置为自己监听的主机及端口。DataSource向指定的ip及端口输出日志,Input 输入源监听到数据信息就可以进行收集。
b) Filter
过滤功能,对收集到的信息进行过滤(额外处理),也可以省略这个配置(不做处理)
c) Output
把收集到的信息发送给谁。在ELK技术栈中都是输出给Elasticsearch,后面数据检索和数据分析的过程就给Elasticsearch了。

最终效果:通过整体步骤就可以把原来一行日志信息转换为Elasticsearch支持的Document形式(键值对形式)的数据进行存储。
在这里插入图片描述

4 安装Logstash
4.1 安装Logstash
docker pull logstash:7.6.2

4.2 启动容器
docker run -it -p 4560:4560 --name logstash -d logstash:7.6.2

4.3 修改配置
进入容器
docker exec -it logstash /bin/bash
修改配置文件
vi /usr/share/logstash/config/logstash.yml
把ip修改成elasticsearch访问地址IP
在这里插入图片描述

4.4 修改输入输出配置
继续在容器命令行输入
vi /usr/share/logstash/pipeline/logstash.conf

配置解释说明:

input:接收日志输入配置
tcp: 协议
mode: logstash服务
port:端口,自己指定。默认4560
output:日志处理输出
elasticsearch: 交给es处理
action:es中index命令。也就是新增命令。
hosts:es的主机
index:存储日志的索引。如果不存在可以自动创建。默认的type名称为doc
一定要先启动编辑状态(点击键盘i键)在粘贴,如果没启用第一行是nput{少个i。

input {tcp {mode => "server"port => 4560}
}
filter {
}
output {elasticsearch {action => "index"hosts  => "192.168.8.128:9200"index  => "test_log"}
}

4.5 重启容器
退出容器命令行,进入到Linux终端,重启logstash容器。
docker restart logstash
在这里插入图片描述

4.6 查看日志
docker logs -f logstash
在这里插入图片描述

六、 使用Logback向Logstash中输出日志

pom.xml

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</version>
</parent>
<dependencies><dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>6.3</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--该日志将日志级别不同的log信息保存到不同的文件中 -->
<configuration><include resource="org/springframework/boot/logging/logback/defaults.xml" /><springProperty scope="context" name="springAppName"source="spring.application.name" /><!-- 日志在工程中的输出位置 --><property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}" /><!-- 控制台的日志输出样式 --><property name="CONSOLE_LOG_PATTERN"value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" /><!-- 控制台输出 --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>INFO</level></filter><!-- 日志输出编码 --><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>utf8</charset></encoder></appender><!-- logstash远程日志配置--><appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender"><destination>192.168.8.132:4560</destination><encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" /></appender><!-- 日志输出级别 --><root level="DEBUG"><appender-ref ref="console" /><appender-ref ref="logstash" /></root>
</configuration>

启动类

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

七、 在Kibana中查看日志信息

1 使用命令方式查看
可以直接在Dev Tools中输入命令查看日志信息。
输入: GET test_log/_search 查看全部。
在这里插入图片描述

八、 搭建日志系统

pom.xml

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</version>
</parent>
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency>
</dependencies>

application.yml

spring:elasticsearch:rest:uris: http://192.168.8.132:9200

新建实体

/*** 对应Elasticsearch中的logstash_log_index索引。*/
@Data
@Document(indexName = "logstash_log_index")
public class MyLogMessage implements Serializable {@Idprivate String id;@Field(name = "host", type = FieldType.Text)private String host;@Field(name = "@version", type = FieldType.Text)private String version;@Field(name = "port", type = FieldType.Long)private Long port;@Field(name = "@timestamp", type = FieldType.Date, format = DateFormat.date_time)private Date timestamp;@Field(name = "message", type = FieldType.Text)private String message;
}

MyLogMessageDao

public interface MyLogMessageDao {/*** 在Message字段中做搜索。 分页处理。* @param page 从0开始的页码* @param rows 每页多少行* @param query 关键字* @return*  key                     value*  total                   总计数据行数*  List<MyLogMessage>      当前页面显示的数据集合,对象中的message高亮处理。*/Map<String, Object> searchByPage(int page, int rows, String query);
}

MyLogMessageDaoImpl

@Repository
public class MyLogMessageDaoImpl implements MyLogMessageDao {@Autowiredprivate ElasticsearchRestTemplate restTemplate;@Overridepublic Map<String, Object> searchByPage(int page, int rows, String query) {HighlightBuilder.Field f = new HighlightBuilder.Field("message");f.preTags("<span style='color:red'>");f.postTags("</span>");f.fragmentSize(Integer.MAX_VALUE);f.numOfFragments(1);SearchHits<MyLogMessage> hits =restTemplate.search(new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("message", query)) // 搜索条件.withPageable(PageRequest.of(page, rows)) // 分页.withHighlightFields(f) // 高亮.build(),MyLogMessage.class);List<MyLogMessage> contents = new ArrayList<>();for(SearchHit<MyLogMessage> hit : hits){MyLogMessage logMessage = hit.getContent();// 处理高亮List<String> hl = hit.getHighlightField("message");if(hl != null && hl.size() > 0){// 有高亮logMessage.setMessage(hl.get(0));}contents.add(logMessage);}Map<String, Object> result = new HashMap<>();result.put("total", hits.getTotalHits());result.put("datas", contents);return result;}
}

新建service及实现类

package com.bjsxt.service;import java.util.Map;public interface MyLogService {Map<String, Object> searchByPage(int page, int rows, String query);
}
@Service
public class MyLogServiceImpl implements MyLogService {@Autowiredprivate MyLogMessageDao logMessageDao;private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic Map<String, Object> searchByPage(int page, int rows, String query) {Map<String, Object> result = logMessageDao.searchByPage(page, rows, query);return result;}
}

新建控制器

@RestController
public class MyLogController {@Autowiredprivate MyLogService logService;@RequestMapping("/find")public Map<String, Object> findByPage(@RequestParam(name = "page", defaultValue = "0") int page,@RequestParam(name = "rows", defaultValue = "10") int rows,@RequestParam(name = "query", defaultValue = "level") String query){return logService.searchByPage(page, rows, query);}
}

启动类

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

测试结果
在浏览器输入: http://localhost:8080/ ?page=1,rows=2

九、 在Java代码中获取日志信息

新建实体类

MessageBody

/*** 是MyLogMessage类型对象中message字符串属性转换后的Java对象类型。*/
@Data
public class MessageBody implements Serializable {// 使用Jackson把Json字符串转成Java对象,默认是同名转换。如果JSON中的属性名和Java对象的属性名不同// 用JsonProperty注解定义JSON中的属性名称。@JsonProperty("@timestamp")private Date timestamp;@JsonProperty("@version")private String version;private String message;@JsonProperty("logger_name")private String loggerName;@JsonProperty("thread_name")private String threadName;private String level;@JsonProperty("level_value")private String levelValue;
}

修改实体类 添加MessageBody

/*** 对应Elasticsearch中的logstash_log_index索引。*/
@Data
@Document(indexName = "logstash_log_index")
public class MyLogMessage implements Serializable {@Idprivate String id;@Field(name = "host", type = FieldType.Text)private String host;@Field(name = "@version", type = FieldType.Text)private String version;@Field(name = "port", type = FieldType.Long)private Long port;@Field(name = "@timestamp", type = FieldType.Date, format = DateFormat.date_time)private Date timestamp;@Field(name = "message", type = FieldType.Text)private String message;private MessageBody body;
}

修改service实现类

@Service
public class MyLogServiceImpl implements MyLogService {@Autowiredprivate MyLogMessageDao logMessageDao;private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic Map<String, Object> searchByPage(int page, int rows, String query) {Map<String, Object> result = logMessageDao.searchByPage(page, rows, query);for(MyLogMessage message : (List<MyLogMessage>)result.get("datas")){// 获取JSON格式字符串String jsonMessage = message.getMessage();MessageBody messageBody = null;try {// 转换字符串为Java对象messageBody = objectMapper.readValue(jsonMessage, MessageBody.class);} catch (JsonProcessingException e) {e.printStackTrace();}// 设置对象message.setBody(messageBody);}return result;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目参与度较低怎么办?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。经过这两天做项目的表现&#xff0c;可以很明显的看的出来学生与学生之间掌握的还是有差距的&#xff0c;组内有的组员是可以为项目贡献代码的&#xff0c;但是有的组员可能只能是贡献素材&#xff0c;…

从 TFS 迁移源代码到 git

准备工具&#xff1a; https://github.com/git-tfs/git-tfs 具体的安装步骤上面的 readme.md 中有说明。通过 Chocolatey 安装&#xff0c;如果本地没有 git &#xff0c;会自动安装 git 到本地。 迁移步骤&#xff1a; 从 Visual Studio 里面进入 Source Control Explorer…

缓存穿透、缓存并发、缓存失效之思路变迁

转载自 缓存穿透、缓存并发、缓存失效之思路变迁 在用缓存的时候&#xff0c;基本上会通用遇到以下三个问题&#xff1a; 缓存穿透缓存并发缓存失效 一、缓存穿透 上面三个图会有什么问题呢&#xff1f; 我们在项目中使用缓存通常都是先检查缓存中是否存在&#xff0c;如果…

jzoj3792,P2062-分队问题【贪心】

前言 题解上说&#xff1a; 然而我的贪心不仅A了&#xff0c;而且 反例也A了 自己的洛谷题解链接&#xff1a;https://www.luogu.org/blog/user52918/solution-p2062 正题 大意 n个人&#xff0c;每个人有一个要求a[i]表示他所在的队伍里不可以少于a[i]个人&#xff0…

.net core 2.0学习笔记(二):Hello World amp;amp; 进阶

官网已经有一个.net core的入手教程&#xff08;https://www.microsoft.com/net/core#windowscmd&#xff09;&#xff0c;但这个教程完全没有顾及全宇宙第一IDE的感受。今天就跟大家体验一下在VS2017上开发.net core程序吧。VS2017开发环境的搭建请参考&#xff1a;http://www…

MyBatis】MyBatis一级缓存和二级缓存

转载自 MyBatis】MyBatis一级缓存和二级缓存 MyBatis自带的缓存有一级缓存和二级缓存 一级缓存 Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。 也就是在同一个SqlSession中&#xff0c;执行相同的查询SQL&#xff…

.net core 2.0学习笔记(一):开发运行环境搭建

期待已久的.net core 2.0终于发布了&#xff01;大家等的花儿都谢了。 不过比预期提前了一个多月&#xff0c;这在微软历史上还真的不多见。按照历史经验看&#xff0c;2.0版本应该比较靠谱&#xff0c;我猜这也是社区非常火爆的原因吧。下面就简单分享一下.net core2.0开发运行…

不好意思,你这个加分理由不行……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。周五了&#xff0c;又该周测了&#xff0c;今天和以往一样&#xff0c;上午前两节课都在上课&#xff0c;第三节课进行测试&#xff0c;这周的填空题有点儿多&#xff0c;所以考试的时间较…

SQL索引一步到位

转载自 SQL索引一步到位 SQL索引在数据库优化中占有一个非常大的比例&#xff0c; 一个好的索引的设计&#xff0c;可以让你的效率提高几十甚至几百倍&#xff0c;在这里将带你一步步揭开他的神秘面纱。 1.1 什么是索引&#xff1f; SQL索引有两种&#xff0c;聚集索引和非聚…

jzoj3794,P1383-高级打字机【欧拉序,离线O(n)】

正题 题目链接&#xff1a;https://www.luogu.org/problemnew/show/P1383 大意 三个操作 T c&#xff1a;加入一个字符c U x&#xff1a;撤销前x次操作&#xff08;只包括T和U&#xff09; Q x&#xff1a;询问当前第x个字符 解题思路 对于50%的数据U不会撤销到U 所以我们可…

你也可以做一个简易抽奖程序!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天给大家分享一个使用winform制作的小案例——随机点名&#xff08;抽奖&#xff09;程序&#xff0c;下面我们来看看运行结果&#xff1a;在班内点名为了公平起见&#xff0c;一直使用的…

ASP.NET Core 2.0 特性介绍和使用指南

ASP.NET Core 2.0 发布日期&#xff1a;2017年8月14日 ASP.NET团队宣布ASP.NET Core 2.0正式发布&#xff0c;发布Visual Studio 2017 15.3支持ASP.NET Core 2.0&#xff0c;提供新的Razor Pages项目模板。 详细发布信息查看.NET Core 2.0.0发布说明文档 最新版SDK下载&…

blog项目中遇到的问题及解决

1、dependencesmangement 只做资源定位 2、多模块开发中mapper扫描 3、lambda表达式简写时&#xff08;使用lombox建造者模式&#xff09; 4、新增评论时 使用mp的自动填充时userid未赋值

你在学校我安排了你没有做到最多凶你一顿,在公司不一样,直接得让走人!...

今天放一部分聊天记录吧~毛帅龙同学穆老师我今天跟着公司做项目了雄雄的小课堂可以呀雄雄的小课堂厉害了雄雄的小课堂好好干哈雄雄的小课堂等有空了出一套若依的文档雄雄的小课堂给大家分享分享毛帅龙同学那个ruoyi视频买了雄雄的小课堂199&#xff1f;毛帅龙同学现在每天看两个…

2018/7/10-纪中某C组题【jzoj3792,jzoj3793,jzoj3794】

前言 由于B组题目太残酷&#xff0c;忒容易爆零&#xff0c;于是我就回到了C组温暖的怀抱 今日说法分数 正题 T1&#xff1a;jzoj3792,P2062-分队问题【贪心】 博客链接&#xff1a;https://blog.csdn.net/mr_wuyongcong/article/details/80988719 T2&#xff1a;jzoj3793,…

ASP.NET Core 源码学习之 Logging[2]:Configure

在上一章中&#xff0c;我们对 ASP.NET Logging 系统做了一个整体的介绍&#xff0c;而在本章中则开始从最基本的配置开始&#xff0c;逐步深入到源码当中去。 默认配置 在 ASP.NET Core 2.0 中&#xff0c;对默认配置做了很大的简化&#xff0c;并把一些基本配置移动到了程序…

两个月拿到N个offer,看看我是如何做到的

转载自 两个月拿到N个offer&#xff0c;看看我是如何做到的 前言&#xff1a; 北京-三年经验-Java&#xff0c;在金三银四这两个月期间&#xff08;在五月初还去面试了几家&#xff0c;主要是三四月份期面试剧居多&#xff09;&#xff0c;我跳槽面试&#xff0c;前前后后我…

“小朋友”们节日快乐呀~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天是六月一日——儿童节&#xff0c;看了看朋友圈&#xff0c;不管是大孩子还是小孩子&#xff0c;都在过节&#xff0c;哈哈哈。最近四班一直在做项目&#xff0c;一共6个小组&#xff…

Entity Framework Core 2.0 全局查询过滤器

本博文翻译自&#xff1a;http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/ Entity Framework Core 2.0 全局查询过滤器 Entity Framework Core 2.0引入了全局查询过滤器&#xff0c;可以在创建模型时应用到实体 。它使得构建多租户应用程序和支持对实体 的软…

SpringCloudGateway

文章目录SpringCloudGateway起步消费端整合SpringCloudGateway静态路由配置内置扩展网关过滤内置网关过滤自定义过滤全局过滤器内置全局过滤器自定义全局过滤器ForwardRoutingFilterNetty全局路由响应式负载均衡代理GatewayMetricsFilter网关度量过滤器&#xff08;服务监控&am…