Laravel 使用 Elasticsearch 作为日志存储

Laravel 使用 Elasticsearch 作为日志存储

你是否在开发中发现在查询日志的时候非常不方便,且无法统计日志或对日志做更深层次的分析。那么可以使用 Elasticsearch 加上 Kibana 来实现。

简介

在实际开发中,我们发现在 Debug 的时候经常需要查询日志。而传统的方式是需要 SSH 到生产环境,然后使用 cattailgrep 等命令查询日志,且无法进行日志的统计和分析,深度挖掘这些日志的价值。

本片文章的侧重点在于优雅的让 Laravel 直接将日志写入 Elasticsearch,当然你也可以选择使用 Logstash 采集 Laravel 的本地日志。

环境搭建可以参考 《Elastic Stack 之 Elasticsearch》《Elastic Stack 之 Kibana》 这两篇博文。

所需依赖

  • elasticsearch/elasticsearch
  • betterde/logger(如果需要)

原理分析

monolog

Laravel 使用 monolog/monolog 作为默认日志处理模块。monolog 自带了很多 Handler 其中就有 ElasticsearchHandler,后面我们会进行介绍。

生命周期

  • Illuminate\Foundation\Application 的构造函数中注册基本的服务提供者,其中就有 Illuminate\Log\LogServiceProvider
  • Illuminate\Log\LogServiceProvider 中将 Illuminate\Log\LogManager 注册到容器,此时还没有 Logger。
  • 当我们使用 Illuminate\Support\Facades\Log::info() 的时候,LogManager 会调用内部一系列方法根据配置文件创建 Logger 和其所需的 Handlers
  • 最终调用 Logger 的 info()、error()、debug() 等方法,实现记录日志的功能。

lifecycle

简单适配

只需要通过修改 config/logging.php.env 文件就可以实现,将日志直接写入 Elasticcsearch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'elastic' => [
'driver' => 'monolog',
'level' => 'debug',
'name' => 'Develop',
'tap' => [],
'handler' => ElasticsearchHandler::class,
'formatter' => \Monolog\Formatter\ElasticsearchFormatter::class,
'formatter_with' => [
'index' => 'monolog',
'type' => '_doc'
],
'handler_with' => [
'client' => \Elasticsearch\ClientBuilder::create()->setHosts(['http://localhost:9200'])->build(),
],
],
1
LOG_CHANNEL=elastic

轮子

会发现当我们在写入日志的时候,Laravel 是单条同步进行的,对于我们使用原创存储来说这将影响一定的性能。所以我们需要在整个生命周期中临时保存所有的日志信息,在请求结束前触发同步或异步将日志批量写入存储。

为此我周末写了一个扩展包betterde/logger,如果你在使用的过程中有任何问题可以在Github上提 IssuePR

安装

1
2
$ composer require betterde/logger
$ php artisan vendor:publish --tag=betterde.logger

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?php

return [
/*
* 是否开启批量写入,需要设置中间件
*/
'batch' => false,

/*
* 是否使用队列
*/
'queue' => false,

/*
* 日志级别,值可以参考 Monolog\Logger.php 中的定义
*/
'level' => 200,

/*
* 是否在多个 Handler 中流转日志数据
*/
'bubble' => false,

/*
* Elasticsearch DB
*/
'elasticsearch' => [
'hosts' => [
[
/*
* host 是必填项
*/
'host' => env('ELASTICSEARCH_HOST', 'localhost'),
'port' => env('ELASTICSEARCH_PORT', 9200),
'scheme' => env('ELASTICSEARCH_SCHEME', 'http'),
'user' => env('ELASTICSEARCH_USER', null),
'pass' => env('ELASTICSEARCH_PASS', null)
],
],
'retries' => 2,
/*
* 证书路径
*/
'cert' => ''
],

/*
* Handler 的设置
*/
'options' => [
'index' => 'monolog', // Elastic index name
'type' => '_doc', // Elastic document type
'ignore_error' => false, // Suppress Elasticsearch exceptions
],

/*
* 对于异常日志是否记录追踪详情
*/
'exception' => [
'trace' => false,
],

/*
* 扩展属性,用于区分多个项目使用同一个 Elasticsearch Index,extra 数组里的 Key 都是可以自定义的,我这里只是举例
*/
'extra' => [
'host' => 'example.com',
'php' => '7.3.5',
'laravel' => '6.5.2'
]
];

好了现在可以尽情的享受写 CURD 的乐趣了。

如果你对我的文章感兴趣可以关注我的订阅号

评论