【ElasticSearch系列(四)】为 Laravel 适配 ElasticSearch 日志驱动 - zobeen的个人空间 - OSCHINA - 中文开源技术交流社区


本站和网页 https://my.oschina.net/zobeen/blog/2250157 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

【ElasticSearch系列(四)】为 Laravel 适配 ElasticSearch 日志驱动 - zobeen的个人空间 - OSCHINA - 中文开源技术交流社区
首页
资讯
摸鱼
专区
问答
GOTC2023
活动
开源活动
开源创新大赛
软件库
2022年度评选
Tool
博客
Gitee
首页
资讯
摸鱼
专区
问答
GOTC2023
活动
开源活动
开源创新大赛
软件库
2022年度评选
Tool
博客
Gitee
OSCHINA 小程序 —— 关注技术领域的头条文章
聚合全网技术文章,根据你的阅读喜好进行个性推荐
登录
注册
开源博客
写博客
zobeen的个人空间
后端技术
正文
【ElasticSearch系列(四)】为 Laravel 适配 ElasticSearch 日志驱动
原创
zobeen
后端技术
2018/10/21 11:58
阅读数 3.6K
本文被收录于专区
开发技能
进入专区参与更多专题讨论
1、概述
1.1、为什么要用 Elasticsearch 存储 Laravel 日志而不是直接使用默认的文件存储?
当PHP部署在多台服务器时,如果需要查找日志则要在每台服务器上面进行查找。
通常日志是按天分割的,如果不确定是哪一天还需要在好几个文件里面进行查找,然后需要查找的文件数就变成了不确定的天数*负载均衡的服务器数量。
在服务器上面直接通过命令行查询查找日志内容真的不方便。
1.2、ElasticSearch 服务器
参见《【ElasticSearch系列(一)】环境准备》。
2、环境
2.1、版本介绍
Laravel 5.5
ElasticSearch 6.3.0
PHP Lib elasticsearch/elasticsearch 6.0
2.2、配置
在 Laravel 项目中引入 ElasticSearch 库
composer require elasticsearch/elasticsearch
3、开始适配
3.1、.env 配置
ELASTIC_HOST=192.168.20.129:9200 # 这里是你的 ElasticSearch 服务器 IP 及端口号
ELASTIC_LOG_INDEX=bf_log # ElasticSearch 索引
ELASTIC_LOG_TYPE=log # ElasticSearch 类型
3.2、ElasticSearch 配置文件
文件位置
/config/elasticsearch.php
代码
<?php
return [
'hosts' => [
env('ELASTIC_HOST')
],
'log_index' => env('ELASTIC_LOG_INDEX'),
'log_type' => env('ELASTIC_LOG_TYPE'),
];
3.3、ElasticSearch 驱动接口
作用
定义 ElasticSearch 驱动要实现的功能。
文件位置
/app/Contracts/ElasticSearchClient.php
代码
<?php
namespace App\Contracts;
interface ElasticSearchClient
/**
* 获取 ElasticSearch 客户端
* @return mixed
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function getClient();
/**
* 添加日志
* @param array $document
* @return mixed
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function addDocument(array $document);
/**
* 获取所有已添加日志
* @return mixed
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function getDocuments();
3.4、ElasticSearch 驱动实现
作用
实现 ElasticSearch 驱动接口定义的功能。
文件位置
/app/Contracts/Foundation/ElasticSearchClient.php
代码
<?php
namespace App\Contracts\Foundation;
use Elasticsearch\ClientBuilder;
use App\Contracts\ElasticSearchClient as IElasticSearchClient;
class ElasticSearchClient implements IElasticSearchClient
protected $client;
protected $documents = [];
public function __construct()
$hosts = config('elasticsearch.hosts');
$this->client = ClientBuilder::create()->setHosts($hosts)->build(); // 实例化一个客户端
/**
* 获取 ElasticSearch 客户端
* @return \Elasticsearch\Client
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function getClient()
return $this->client;
/**
* 添加日志
* @param array $document
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function addDocument(array $document)
$this->documents[] = $document;
/**
* 获取所有已添加日志
* @return array
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function getDocuments()
return $this->documents;
3.5、ElasticSearch 门面
作用
为了更优雅的使用 ElasticSearch 驱动,我们定义该门面,以静态形式使用 ElasticSearch 驱动。
文件位置
/app/Facades/ElasticSearchClient.php
代码
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class ElasticSearchClient extends Facade {
protected static function getFacadeAccessor()
return 'App\Contracts\ElasticSearchClient';
3.6、ElasticSearch 句柄
作用
该句柄提供给 Monolog 使用,以让 Monolog 识别 ElasticSearch 并作为日志驱动。
文件位置
/app/Contracts/Foundation/ElasticSearchLogHandler.php
代码
<?php
namespace App\Contracts\Foundation;
use Monolog\Handler\AbstractProcessingHandler;
use App\Facades\ElasticSearchClient;
class ElasticSearchLogHandler extends AbstractProcessingHandler
protected function write(array $record)
if ($record['level'] >= 200) {
ElasticSearchClient::addDocument($record);
3.7、ElasticSearch 服务提供者
作用
为了更优雅的使用 ElasticSearch 驱动,我们以服务的方式实例化 ElasticSearch 驱动。
文件位置
/app/Providers/ElasticSearchClientProvider.php
代码
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Log;
use App\Contracts\Foundation\ElasticSearchLogHandler;
class ElasticSearchClientProvider extends ServiceProvider
/**
* Bootstrap any application services.
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function boot()
/**
* 修改 Laravel 默认的 Log 存储方式为 Elasticsearch。
*/
$monolog = Log::getMonolog();
$elasticSearchLogHandler = new ElasticSearchLogHandler();
// $monolog->popHandler(); // 把默认的文件存储去掉,否则会将日志同时存储到文件和ElasticSearch
$monolog->pushHandler($elasticSearchLogHandler); // 添加 ElasticSearch 日志存储句柄
/**
* Register any application services.
* @return void
*/
public function register()
$this->app->singleton('App\Contracts\ElasticSearchClient', function ($app) {
return new \App\Contracts\Foundation\ElasticSearchClient();
});
注册服务提供者 /config/app.php
<?php
return [
// ......
'providers' => [
// ......
App\Providers\ElasticSearchClientProvider::class,
// ......
],
// ......
];
3.8、ElasticSearch 任务队列
作用
为了提高日志写入效率及并发,我们将日志写入操作加入到任务队列。
文件位置
/app/Jobs/ElasticSearchLog.php
代码
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Elasticsearch\Client;
use App\Facades\ElasticSearchClient;
class ElasticSearchLog implements ShouldQueue
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $params;
/**
* Create a new job instance.
* ElasticSearchLog constructor.
* @param array $records
*/
public function __construct(array $records)
$this->params['body'] = [];
foreach ($records as $record) {
unset($record['context']);
unset($record['extra']);
$record['datetime'] = $record['datetime']->format('Y-m-d H:i:s');
$this->params['body'][] = [
'index' => [
'_index' => config('elasticsearch.log_index'),
'_type' => config('elasticsearch.log_type'),
],
];
$this->params['body'][] = $record;
/**
* Execute the job.
* @return void
*/
public function handle()
$client = ElasticSearchClient::getClient();
if ($client instanceof Client) {
$client->bulk($this->params);
3.9、ElasticSearch 中间件
作用
每写一次日志就会与 ElasticSearch 服务器创建连接并写入日志数据,这样性能会很低,于是我们打算搜集一次 http 请求过程中产生的所有日志,在请求得到响应后统计所有日志数据统一写入到 ElasticSearch 系统中。为了所有的请求都能使用到该中间件,我们将其加入到全局中间件中。
文件位置
/app/Http/Middleware/ElasticSearchLog.php
代码
<?php
namespace App\Http\Middleware;
use Closure;
use App\Jobs\ElasticSearchLog as JElasticSearchLog;
use App\Facades\ElasticSearchClient;
class ElasticSearchLog
/**
* Handle an incoming request.
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
return $next($request);
/**
* @param $request
* @param $response
* Written by Zhou Yubin(zhouyb@fengrongwang.com)
*/
public function terminate($request, $response)
$documents = ElasticSearchClient::getDocuments();
// 需要判断是否有日志
if (count($documents) > 0) {
dispatch(new JElasticSearchLog($documents));
配置中间件 /app/Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
// ......
protected $middleware = [
// ......
\App\Http\Middleware\ElasticSearchLog::class,
];
// ......
3.10、http 请求被异常中断
作用
当一次 http 请求被异常中断,浏览器便得不到正确的响应,因此我们在中间件中用来处理 ElasticSearch 日志任务触发的命令也就不会起作用。为此,我们需要在 Laravel 处理异常的地方来触发 ElasticSearch 日志任务。
文件位置
/app/Exception/Handler.php
代码
// ......
public function report(Exception $exception)
try {
$logs = ElasticSearchClient::getLogs();
// 需要判断是否有日志
if (count($logs) > 0) {
dispatch(new JElasticSearchLog($logs));
} catch (\Exception $e) {
Log::error($e->getMessage());
parent::report($exception);
// ......
3.11、执行命令 composer du
4、测试
4.1、测试 ElasticSearch 连接情况
文件位置
/routes/web.php
代码
Route::get('/test/elastic', function () {
$hosts = [
'192.168.20.129:9200',
];
$client = \Elasticsearch\ClientBuilder::create()->setHosts($hosts)->build();
try {
$response = $client->info();
return $response;
} catch (\Exception $e) {
return 'error: ' . $e->getMessage();
});
执行结果
在浏览器中访问 http:xxx.com/test/elastic,将有以下信息出现。
"name": "HfQ36uo",
"cluster_name": "docker-cluster",
"cluster_uuid": "879oaeOoT0CDPO02_vhaHA",
"version": {
"number": "6.3.0",
"build_flavor": "default",
"build_type": "tar",
"build_hash": "424e937",
"build_date": "2018-06-11T23:38:03.357887Z",
"build_snapshot": false,
"lucene_version": "7.3.1",
"minimum_wire_compatibility_version": "5.6.0",
"minimum_index_compatibility_version": "5.0.0"
},
"tagline": "You Know, for Search"
至此,说明我们已经成功连接 ElasticSearch 服务器,并且获取到的 ElasticSearch 服务器的基本信息。
4.2、测试 ElasticSearch 日志驱动
文件位置
/routes/web.php
代码
use Illuminate\Support\Facades\Log;
Route::get('/test/log', function () {
// 日志同时写入 文件系统 和 ElasticSearch 系统
Log::info('写入成功啦,日志同时写入 文件系统 和 ElasticSearch 系统', ['code' => 0, 'msg' => '成功了,日志同时写入 文件系统 和 ElasticSearch 系统', 'data' => [1,2,3,4,5]]);
});
执行结果
在浏览器中访问 http:xxx.com/test/log后,我们去看两个位置是否有相应的日志内容。
第一个位置:文件系统日志文件 /storage/logs/laravel-2018-08-23.log,内容如下
[2018-08-23 11:03:02] local.INFO: 写入成功啦,日志同时写入 文件系统 和 ElasticSearch 系统 {"code":0,"msg":"成功了,日志同时写入 文件系统 和 ElasticSearch 系统","data":[1,2,3,4,5]}
第二个位置:ElasticSearch 服务器,可以通过下面的方式查看
http://192.168.20.129:9200/bf_log/log/_search/
返回的数据如下:
"took": 13,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
"_index": "bf_log",
"_type": "log",
"_id": "0Xv4ZGUBMpjJDxlj_ikn",
"_score": 1,
"_source": {
"message": "写入成功啦,日志同时写入 文件系统 和 ElasticSearch 系统",
"level": 200,
"level_name": "INFO",
"channel": "local",
"datetime": "2018-08-23 11:03:02",
"formatted": "[2018-08-23 11:03:02] local.INFO: 写入成功啦,日志同时写入 文件系统 和 ElasticSearch 系统 {\"code\":0,\"msg\":\"成功了,日志同时写入 文件系统 和 ElasticSearch 系统\",\"data\":[1,2,3,4,5]} []\n"
至此,我们已经成功的适配了 Laravel 的 ElasticSearch 日志驱动。
如果不想同时将日志写入文件系统,可以将下面的注释打开:
/app/Providers/ElasticSearchClientProvider.php
<?php
// ......
public function boot()
// ......
$monolog->popHandler(); // 把默认的文件存储去掉,否则会将日志同时存储到文件和ElasticSearch
// ......
// ......
5、安装 Kibana
下载 Kibana
注意和 ElasticSearch 版本保持一致
配置 Kibana
config/kibana.yml
elasticsearch.url: "http://192.168.20.129:9200"
启动 Kibana 服务
$ bin/kibana (或 $ bin\kibana.bat)
展开阅读全文
ElasticSearchLaravel
著作权归作者所有
举报
加载中
点击引领话题📣
取消
发布
0" class="recommend-box">
作者的其它热门文章
{{formatHtml(o.title)}}
0 赞
0 收藏
微信
QQ
微博
分享
关于作者
zobeen
关注
私信
提问
文章
20
经验值
33
粉丝
关注
作者的专辑
全部
后端技术(10)
服务器(5)
管理(1)
金融(1)
源创计划
立即入驻
自媒体入驻开源社区,
获百万流量,打造个人技术品牌
推荐关注
换一批
yoby
文章 1
访问 8.9K
hello-java-maker
文章 45
访问 41.2W
美团技术团队
文章 286
访问 71.8W
咖啡拿铁的技术分享
文章 179
访问 31.4W
沈浪熊猫儿
文章 2
访问 892
打赏
0 评论
0 收藏
0 赞
微信
QQ
微博
分享
选择专区和圈子:{{title}}
{{o.name}}
{{m.name}}
取消
确定
OSCHINA 社区
关于我们
联系我们
加入我们
合作伙伴
Open API
在线工具
Gitee.com
企业研发管理
CopyCat-代码克隆检测
实用在线工具
国家反诈中心APP下载
攻略
项目运营
Awesome 软件(持续更新中)
QQ群
530688128
公众号
视频号
OSCHINA 小程序
聚合全网技术文章,根据你的阅读喜好进行个性推荐
OSC小程序
©OSCHINA(OSChina.NET)
工信部
开源软件推进联盟
指定官方社区
社区规范
深圳市奥思网络科技有限公司版权所有
粤ICP备12009483号
顶部