# ELK 分析 Laravel 日志

![](/files/1wy5xaC6fx1P4HRVDpG0)

## **注意 ES 和 Kibana 以及IK分词器 版本要一致 7.2.0**

```
docker pull elasticsearch:7.2.0
docker pull kibana:7.2.0

#docker pull logstash:7.2.0 #通过改Laravel框架来搞 

#ik分词器版本 elasticsearch-analysis-ik-7.2.0.zip
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.2.0/elasticsearch-analysis-ik-7.2.0.zip
```

#### 1 启动es 在浏览器中打开[http://localhost:9200](https://link.segmentfault.com/?enc=zBew536jmGij%2FKODPSlNQQ%3D%3D.u1JyRrr%2FR7cVh8nkLhJKExsV7VBtj6rtSQbpS83%2FkdU%3D) 检查 <a href="#item-2-2" id="item-2-2"></a>

```
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -d elasticsearch:7.2.0
```

#### 2 修改es配置，解决跨域问题 <a href="#item-2-3" id="item-2-3"></a>

首先进入到容器中，然后进入到指定目录修改`elasticsearch.yml`文件

```
docker exec -it elasticsearch /bin/bash
cd /usr/share/elasticsearch/config/
vi elasticsearch.yml
```

在elasticsearch.yml的文件末尾加上

```
http.cors.enabled: true
http.cors.allow-origin: "*"
```

修改配置后重启容器

```
docker restart elasticsearch
```

#### 3 安装ik分词器 <a href="#item-2-4" id="item-2-4"></a>

es自带的分词器对中文分词不是很友好，所以下载开源的IK分词器来解决这个问题。\
首先进入到plugins目录中下载分词器，下载完成后然后解压，再重启es即可。具体步骤如下:\
**注意：**&#x65;lasticsearch的版本和ik分词器的版本需要保持一致，不然在重启的时候会失败。\
可以在 <https://github.com/medcl/elasticsearch-analysis-ik/releases> 查看所有版本

不添加`"analyzer": "ik_max_word",`则是每个字分词，可以在下面kibana安装完成以后尝试一下

```
mkdir -p /usr/share/elasticsearch/plugins/ik
cd /usr/share/elasticsearch/plugins/ik
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.2.0/elasticsearch-analysis-ik-7.2.0.zip
exit
docker restart elasticsearch 
```

然后可以在kibana界面的`dev tools`中验证是否安装成功；

```
POST test/_analyze
{
  "analyzer": "ik_max_word",
  "text": "你好我是benniao"
}
```

#### 4 docker安装kibana <a href="#item-3-5" id="item-3-5"></a>

启动kibana容器使用`--link`连接到elasticsearch容器

```
docker run --name kibana --link=elasticsearch -p 5601:5601 -d kibana:7.2.0

docker start kibana
```

启动以后可以打开浏览器输入 [http://localhost:5601](https://link.segmentfault.com/?enc=2UDcDiGMQNP9cSy5wQa%2FKQ%3D%3D.LNC5f45%2FKsC2jjJaW7MBPNDLOBjGkWafsIafy5xgfW4%3D) 就可以打开kibana的界面了<br>

## 原理

![](/files/8tLelCdTgLKWMlikBQbR)

所需依赖\
`elasticsearch/elasticsearch` \
`betterde/logger`（如果需要） \
\
原理分析 \
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

`config/logging.php`

```php
'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(),
    ],
],
```

.env   增加 `LOG_CHANNEL=elastic`

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

为此直接使用扩展包 `betterde/logger` 解决

### 1 安装依赖 <a href="#e655a4" id="e655a4"></a>

```php
composer require betterde/logger
php artisan vendor:publish --tag=betterde.logger
```

### 2 配置

将如下配置追加到 `config/logging.php` 的 `channels` 中

```php
use Betterde\Logger\ElasticsearchLogger;
'channels' => [
     'elastic' => [
         'driver' => 'custom',
         'via' => ElasticsearchLogger::class,
     ],
 ],
```

将 `\Betterde\Logger\Http\Middleware\BulkCollectionLog` 中间件添加到 `App\Http\Kernel.php` 文件中

```php
/**
 * The application's global HTTP middleware stack.
 *
 * These middleware are run during every request to your application.
 *
 * @var array
 */
 protected $middleware = [
     \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
     \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
     \App\Http\Middleware\TrimStrings::class,
     \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
     \App\Http\Middleware\TrustProxies::class,
     \Betterde\Logger\Http\Middleware\BulkCollectionLog::class
 ];
```

在 `.env` 文件中添加如下配置项

```php
LOG_CHANNEL=elastic
ELASTICSEARCH_HOST=localhost
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_SCHEME=http
ELASTICSEARCH_USER=
ELASTICSEARCH_PASS=
```

修改 `config/logger.php` 配置文件

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

    /*
    * 是否使用队列
    */
    'queue' => [
        'enable' => false,
        'name' => env('LOG_QUEUE_NAME', 'logging')
    ],
    /*
    * 日志级别，值可以参考 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'
    ]
];
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xn--6o0a585a.gitbook.io/devops/docker/centos7/bu-shu-es/elk-fen-xi-laravel-ri-zhi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
