尝试将monolog日志保存到Elasticsearch时出现映射问题,请使用ElasticsearchHandler

时间:2016-04-12 12:32:43

标签: symfony elasticsearch monolog

我尝试使用monolog开始将我的日志发送到弹性搜索。 (我使用Symfony2)。

我已经设置了这样的独白:

monolog:
    handlers:
        elasticsearch:
            elasticsearch:
                host: %logger_elastic_host%
                port: %logger_elastic_port%
            type: elasticsearch
            level: info

它只用了几分钟才发现这个错误消息(致命错误,我删除了无用的东西):

  

创建:/ monolog / logs / AVQKYsGRPmEhlo7mDfrN导致   MapperParsingException [无法解析[context.stack.args]];嵌套:   ElasticsearchIllegalArgumentException [未知属性[class]];

我一直在和我的同事一起寻找解决方法。我们发现的是:

  • 弹性搜索接收第一个日志并自动构建映射
  • 我们发送带有其他映射的新日志,或者与之前发送的内容稍有不同,然后它会中断。
  • 在这种情况下,它在这里打破:context.stack.args。

问题在于背景总是非常不同。

我们想要的是:

  1. 是否有人使用Monolog登录Elasticsearch

  2. 你们如何设法避免这个问题。 (我们如何设法避免它?)

  3. 谢谢你们。

1 个答案:

答案 0 :(得分:1)

这是因为ES从第一个文档创建了一个映射。如果之后插入的任何文档具有相同的属性但具有其他类型/格式,那么ES将抛出错误。

解决方案是创建自定义monolog格式化程序并注册它:

config.yml:

elasticsearch:
    type: elasticsearch
    elasticsearch:
        host: elasticsearch
    ignore_error: true
    formatter: my_elasticsearch_formatter

这一行将使Monolog \ Handler \ ElasticSearchHandler忽略Ruflin的Elastica包中的任何其他错误:

ignore_error: true

然后使用以下名称注册服务:my_elasticsearch_formatter:

    <service id="my_elasticsearch_formatter" class="AppBundle\Services\MyFormatter">
        <argument type="string">monolog</argument>
        <argument type="string">logs</argument>
    </service>

第一个参数是索引名称,第二个参数是类型。

格式化程序类:

<?php

namespace AppBundle\Services;

use function json_encode;
use Monolog\Formatter\ElasticaFormatter;
use function var_dump;

class MyFormatter extends ElasticaFormatter
{
    /**
     * @param string $index
     * @param string $type
     */
    public function __construct($index, $type)
    {
        parent::__construct($index, $type);
    }

    /**
     * @param array $record
     * @return array|\Elastica\Document|mixed|string
     */
    public function format(array $record)
    {
        $record['context'] = json_encode($record['context']);

        return parent::format($record);
    }
}

这个解决方案的缺点是它将json_encode上下文。您将无法按ES中上下文的内部属性进行过滤,但至少您不会丢失有关日志的重要信息。