integração de cliente elk com springboot

Adquira o hábito de escrever juntos! Este é o 11º dia da minha participação no "Nuggets Daily New Plan · April Update Challenge", clique para ver os detalhes do evento .

Através do estudo acima, acredito que você tenha sincronizado os logs impressos pelo springboot para elasticsearch​, e então você precisa consultar os dados correspondentes no módulo do sistema de acordo com as condições. Como as necessidades do blogueiro aqui são relativamente simples e os cenários de uso são únicos, o start fornecido pelo spring é usado como cliente. Como integrar é descrito abaixo.

1. Sintaxe de consulta ElasticsearchTemplate

Ao usar o ElasticsearchTemplate, você só precisa dominar a API fornecida. Veja a seguir um resumo das APIs de consulta comumente usadas para pequenos parceiros usarem.

        // 返回对象
        Result<List<ActionLogVO>> result = new Result();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
 
 
        //must为and的语法
        //matchPhraseQuery为将type分词 然后将第二个参数匹配 可以模糊查询使用
        bool.must(QueryBuilders.matchPhraseQuery("Type", "日志"));
 
        //wildcardQuery模糊查询使用  但是字段需要未英文 
        bool.must(QueryBuilders.wildcardQuery("userName", "*admin*"));
 
        
        //通过时间筛选
        List<QueryBuilder> filters = bool.filter();                           
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse("2021-01-19 17:28:41"))
        .lte(sd.parse("2021-01-19 17:28:43")));
  
 
        //分页(第一个参数PageNum从第0页开始 第二个参数pageSize)
        builder.withPageable(PageRequest.of(1, 10));
 
        //排序
        builder.withSort(SortBuilders.fieldSort("time").order(SortOrder.ASC));
 
 
        // 构造查询条件
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        Iterable<XXXVO> resultIter = XXXXService.search(query);
复制代码

2. Consulta condicional

1. Modifique o arquivo pom

        <!-- elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <version>2.3.7.RELEASE</version>
        </dependency>
复制代码

2. Modifique application.yml

spring: 
 elasticsearch:
    rest:
      uris: ip:9200
      #上文安装时配置的账号密码
      username: xxxx      
      password: xxxx
  data:
    elasticsearch:
      repositories:
        enabled: true
      client:
        reactive:
#          username: xxx 这种写法是不对的
#          password: xxx 这种写法是不对的
#          endpoints: ip:9200 这种写法是不对的
          use-ssl: false
复制代码

Perceber:

  1. O endereço es de configuração deve ser escrito na localização do proprietário, caso contrário, o padrão será localhost: 9200. Se o es estiver instalado em outros servidores, a conexão falhará.
  2. Ao contrário da configuração da versão antiga, o número da porta aberta é 9200.

3. Novo arquivo de configuração

Se os seguintes arquivos não forem adicionados, haverá java.lang.IllegalStateException: availableProcessors já está definido como [4], rejeitando a exceção [4].

@Configuration
public class ElasticSearchConfig {
    /**
     * 防止netty的bug
     * java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]
     */
    @PostConstruct
    void init() {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }
}

复制代码

4. Escrita da interface

Chame principalmente a API em ElasticsearchRestTemplate, consulte os comentários abaixo para obter uma explicação detalhada.

    @Autowired
    ElasticsearchRestTemplate elasticsearchTemplate;

    @Log(operationName = "日志-查询登录日志")
    @PostMapping("/selectLoginLog")
    public Result<List<LoginLogVO>> selectLoginLog(@RequestBody LoginLogInputVO loginLogInputVO) throws ParseException {
        // 日期格式化
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        // 返回对象
        Result<List<LoginLogVO>> result = new Result();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        // 用户名不为空
        if (!CommonUtil.isEmpty(loginLogInputVO.getUserName())) {
            bool.must(QueryBuilders.wildcardQuery("userName", "*" + loginLogInputVO.getUserName() + "*"));
        }
        // 时间不为空
        if (!CommonUtil.isEmpty(loginLogInputVO.getBeginTime()) && !CommonUtil.isEmpty(loginLogInputVO.getEndTime())) {
            List<QueryBuilder> filters = bool.filter();
            filters.add(QueryBuilders.rangeQuery("time")
                .gte(sd.parse(loginLogInputVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat()))
                .lte(sd.parse(loginLogInputVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat())));
        }
        // 分页查询
        if (!CommonUtil.isEmpty(loginLogInputVO.getPageSize()) && !CommonUtil.isEmpty(loginLogInputVO.getPageNum())) {
            // 从第0页开始
            builder.withPageable(PageRequest.of(loginLogInputVO.getPageNum() - 1, loginLogInputVO.getPageSize()));
        }
        builder.withSort(SortBuilders.fieldSort("time").order(SortOrder.ASC));
        // 构造查询条件
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        //查询的索引
        IndexCoordinates indexCoordinates = IndexCoordinates.of("loginlog-*");
        //执行查询
        SearchHits<LoginLogVO> resultIter = elasticsearchTemplate.search(query, LoginLogVO.class, indexCoordinates);
        // 格式化输出
        List<LoginLogVO> resultList = new ArrayList<>();
        List<SearchHit<LoginLogVO>> SearchHitList = resultIter.getSearchHits();
        for (SearchHit<LoginLogVO> loginLogVOSearchHit : SearchHitList) {
            resultList.add(loginLogVOSearchHit.getContent());
        }
        // 分页返回
        if (!CommonUtil.isEmpty(loginLogInputVO.getPageSize()) && !CommonUtil.isEmpty(loginLogInputVO.getPageNum())) {
            result.setTotal(resultIter.getTotalHits());
            result.setPageNum(loginLogInputVO.getPageNum());
            result.setPageSize(loginLogInputVO.getPageSize());
        }
        result.setData(resultList);
        return result;
    }
复制代码

Os índices loginlog-* aqui se referem a todos os índices que começam com loginlog-.

5. Classe de entidade

1. Uso de consulta do cliente Elasticsearch

Uma classe de entidade especial é necessária ao executar o método elasticsearchTemplate.search.

@Document(indexName = "loginlog-*", shards = 1, replicas = 0)
public class LoginLogVO {

    @Id
    private String id;

    /**
     * 信息
     */
    @Field(type = FieldType.Keyword, analyzer = "ik_max_word")
    private String message;

    @Field(type = FieldType.Date, store = true, format = DateFormat.date_time)
    private Date time;
}
复制代码

A explicação é a seguinte:

  • @Document: indica o objeto de domínio mapeado para o documento Elasticsearch, em que indexName representa o nome do índice, shards representa o número padrão de shards e replicas representa o número padrão de réplicas.
  • @Id: indica o id do documento, e o documento pode ser considerado como o conceito de linha da tabela no mysql
  • @Field: O tipo do campo no documento, onde o analisador representa o tipo de tokenizador, o formato representa o tipo de formatação e os tipos de tipo incluem Texto (tipo de caractere que será segmentado e indexado), Inteiro, Longo, Data, Flutuante, Duplo, espera booleana.

2. Digite o pedido

Para uma classe de entidade comum, passe parâmetros de consulta.

public class LoginLogInputVO extends BaseEntity {

    /**
     * 用户账号
     */
    private String userName;

    /**
     * 开始时间
     */
    private String beginTime;

    /**
     * 结束时间
     */
    private String endTime;
}

复制代码

Como o tipo de hora acordado pelos front-end e back-ends do proprietário é string, é necessário converter o tipo e depois devolvê-lo.

6. Preste atenção

elasticsearchTemplate só pode consultar 10.000 itens por vez. Portanto, não é recomendado retornar todas as páginas, mas usar o seguinte método de paginação. Consulte o Baidu.insira a descrição da imagem aqui

3. Exporte os dados dentro do intervalo de tempo

1. Escrita da interface

    @ApiOperation(value = "导出详细日志接口", notes = "导出详细日志接口")
    @PostMapping("/exportDetailLog")
    public void exportDetailLog(@ApiParam(name = "导出详细日志接口输入参数实体", value = "导出详细日志接口输入参数实体",
        required = false) @RequestBody HandleDetailLogVO handleDetailLogVO) throws IOException, ParseException {
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        String beginTime = handleDetailLogVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat();
        String endTime = handleDetailLogVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat();
        String path = handleDetailLogVO.getPath() + "/" + handleDetailLogVO.getBeginTime() + "-"
            + handleDetailLogVO.getEndTime() + ".txt";
        // 根据时间查询
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        List<QueryBuilder> filters = bool.filter();
        //构建查询条件
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse(beginTime)).lte(sd.parse(endTime)));
        builder.withQuery(bool);
        NativeSearchQuery query = builder.build();
        //查询的索引
        IndexCoordinates indexCoordinates = IndexCoordinates.of("loginlog-*");
        // 查询前1w条
        SearchScrollHits<DetailLogVO> scroll =
            elasticsearchTemplate.searchScrollStart(3000, query, DetailLogVO.class, indexCoordinates);
        List<SearchHit<DetailLogVO>> resultList = new ArrayList<>();
        while (scroll.hasSearchHits()) {
            List<SearchHit<DetailLogVO>> searchHitList = scroll.getSearchHits();
            resultList.addAll(searchHitList);
            scroll = elasticsearchTemplate.searchScrollContinue(scroll.getScrollId(), 3000, DetailLogVO.class,
                indexCoordinates);
        }
        // 导出为text流
        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path, true), "utf-8"));
        for (int i = 0; i < resultList.size(); i++) {
            out.write(resultList.get(i).getContent().getMessage());
            out.write("\r\n");
        }
        out.flush();
        out.close();
        // 删除索引
        elasticsearchTemplate.delete(query, DetailLogVO.class, indexCoordinates);
    }
复制代码

Observação: como há um limite de consulta de 1 w, a consulta é repetida. Mas os logs em todos os lugares não podem exceder 8g.

2. Classe de entidade

É principalmente a condição de que o parâmetro de entrada carregue o tempo de consulta.

public class HandleDetailLogVO {
 
    /**
     * 结束时间
     */
    @ApiModelProperty(value = "结束时间", name = "结束时间")
    private String endTime;
 
    /**
     * 开始时间
     */
    @ApiModelProperty(value = "开始时间", name = "开始时间")
    private String beginTime;
 
    /**
     * 导出路径
     */
    @ApiModelProperty(value = "导出路径", name = "导出路径")
    private String path;
}
复制代码

4. Exclua os dados no período de tempo

1. Escrita da interface

Exclua também os dados no período de tempo por meio da API. Consulte os comentários do código para obter detalhes.

    @ApiOperation(value = "清除详细日志接口", notes = "清除详细日志接口")
    @PostMapping("/clearDetailLog")
    public void clearDetailLog(@ApiParam(name = "清除详细日志接口输入参数实体", value = "清除详细日志接口输入参数实体",
        required = false) @RequestBody HandleDetailLogVO handleDetailLogVO) throws IOException, ParseException {
        SimpleDateFormat sd = new SimpleDateFormat(DateFormatEnum.YYYY_MM_DD_HH_MM_SS.getFormat());
        String beginTime = handleDetailLogVO.getBeginTime() + DateFormatEnum.BEGIN_HH_MM_SS.getFormat();
        String endTime = handleDetailLogVO.getEndTime() + DateFormatEnum.END_HH_MM_SS.getFormat();
        // 根据时间查询
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        List<QueryBuilder> filters = bool.filter();
        filters.add(QueryBuilders.rangeQuery("time").gte(sd.parse(beginTime)) .lte(sd.parse(endTime)));
        builder.withQuery(bool);
        //构建查询条件
        NativeSearchQuery query = builder.build();
        //指定删除索引的名称
        IndexCoordinates indexCoordinates = IndexCoordinates.of("datalog-*");
        // 调用API删除索引
        elasticsearchTemplate.delete(query, DetailLogVO.class, indexCoordinates);
    }
复制代码

2. Classe de entidade

A entidade de entrada que carrega as condições de consulta.

public class HandleDetailLogVO {
 
        /**
         * 结束时间
         */
        @ApiModelProperty(value = "结束时间", name = "结束时间")
        private String endTime;
 
        /**
         * 开始时间
         */
        @ApiModelProperty(value = "开始时间", name = "开始时间")
        private String beginTime;
}
复制代码

Acho que você gosta

Origin juejin.im/post/7085352486495584293
Recomendado
Clasificación