Laravel 使用 Elasticsearch 作为日志存储
简介⌗
在实际开发中,我们发现在 Debug 的时候经常需要查询日志。而传统的方式是需要 SSH 到生产环境,然后使用 cat
,tail
和 grep
等命令查询日志,且无法进行日志的统计和分析,深度挖掘这些日志的价值。
本片文章的侧重点在于优雅的让 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() 等方法,实现记录日志的功能。
简单适配⌗
只需要通过修改 config/logging.php
和 .env
文件就可以实现,将日志直接写入 Elasticcsearch:
'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(),
],
],
LOG_CHANNEL=elastic
轮子⌗
会发现当我们在写入日志的时候,Laravel 是单条同步进行的,对于我们使用原创存储来说这将影响一定的性能。所以我们需要在整个生命周期中临时保存所有的日志信息,在请求结束前触发同步或异步将日志批量写入存储。
为此我周末写了一个扩展包 betterde/logger,如果你在使用的过程中有任何问题可以在 Github 上提 Issue 和 PR
安装⌗
$ composer require betterde/logger
$ php artisan vendor:publish --tag=betterde.logger
配置⌗
<?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 的乐趣了。
I hope this is helpful, Happy hacking…