[GH-ISSUE #818] Official ElasticSearch PHP client for handler #314

Closed
opened 2026-03-04 02:14:03 +03:00 by kerem · 4 comments
Owner

Originally created by @adambro on GitHub (Jul 12, 2016).
Original GitHub issue: https://github.com/Seldaek/monolog/issues/818

I know there's ElasticSearchHandler already, but it uses Elastica client to communicate with ES server. I'd rather use ES bulk API directly using some HTTP lib or official ElasticSearch client that I'm using in my app anyway. I saw handler author @skymeyer mentioned using official client, but it was almost 3 years ago.

Would you be interested switching to official ES client or having 2nd implementation of handler?

Originally created by @adambro on GitHub (Jul 12, 2016). Original GitHub issue: https://github.com/Seldaek/monolog/issues/818 I know there's `ElasticSearchHandler` already, but it uses Elastica client to communicate with ES server. I'd rather use ES bulk API directly using some HTTP lib or [official ElasticSearch client](https://github.com/elastic/elasticsearch-php) that I'm using in my app anyway. I saw handler author @skymeyer mentioned using official client, but it was [almost 3 years ago](https://github.com/Seldaek/monolog/pull/227#issuecomment-26242623). Would you be interested switching to official ES client or having 2nd implementation of handler?
kerem closed this issue 2026-03-04 02:14:04 +03:00
Author
Owner

@Seldaek commented on GitHub (Aug 1, 2016):

Given that the current handler uses Elastica and supports bulk sending, I would say it's fine as is, but feel free to publish a third party package using the official ES client API, I just don't want to add new ones in core monolog that have external dependencies.

<!-- gh-comment-id:236575456 --> @Seldaek commented on GitHub (Aug 1, 2016): Given that the current handler uses Elastica and supports bulk sending, I would say it's fine as is, but feel free to publish a third party package using the official ES client API, I just don't want to add new ones in core monolog that have external dependencies.
Author
Owner

@adambro commented on GitHub (Aug 16, 2016):

I just don't want to add new ones in core monolog that have external dependencies.

Fair enough. The case is both client libraries are using HTTP interface of ElasticSearch. So actually the ElasticSearch handler could use any generic HTTP client (even built-in CURL extension).

Other handlers also could benefit from generic HTTP implementation. For example HipChat, CouchDB are doing their own HTTP implementation. There's no generic way to handle errors or async / bulk processing.

I guess the topic is more for mailing list discussion, not issue comments, but I haven't found any mailing list for Monolog.

<!-- gh-comment-id:240024083 --> @adambro commented on GitHub (Aug 16, 2016): > I just don't want to add new ones in core monolog that have external dependencies. Fair enough. The case is both client libraries are using HTTP interface of ElasticSearch. So actually the ElasticSearch handler could use any generic HTTP client (even built-in CURL extension). Other handlers also could benefit from generic HTTP implementation. For example HipChat, CouchDB are doing their own HTTP implementation. There's no generic way to handle errors or async / bulk processing. I guess the topic is more for mailing list discussion, not issue comments, but I haven't found any mailing list for Monolog.
Author
Owner

@adambro commented on GitHub (Oct 20, 2016):

For reference: such extensions seems to exist, but haven't seen an update in a while:
https://packagist.org/packages/atrapalo/monolog-elasticsearch

<!-- gh-comment-id:255054550 --> @adambro commented on GitHub (Oct 20, 2016): For reference: such extensions seems to exist, but haven't seen an update in a while: https://packagist.org/packages/atrapalo/monolog-elasticsearch
Author
Owner

@fhferreira commented on GitHub (Oct 1, 2021):

I created my own, because the Standard was failing when the LOG has an associative array.

<?php

namespace App\Helpers;

use Elasticsearch\ClientBuilder;
use Monolog\Handler\ElasticsearchHandler;
use Log;
use Monolog\Logger;

class CustomLogger
{
    /**
     * Create a custom Monolog instance.
     *
     * @param  array  $config
     * @return \Monolog\Logger
     */
    public function __invoke(array $config)
    {
        $hosts = [
            [
                'host'    => config('services.elastic_search.host'),
                'port'    => config('services.elastic_search.port'),
                'index'   => config('services.elastic_search.index'),
                'scheme'  => config('services.elastic_search.scheme'),
                'user'    => config('services.elastic_search.user'),
                'pass'    => config('services.elastic_search.pass'),
                'type'    => '_doc',
                'retries' => 10,
            ]
        ];

        $client = ClientBuilder::create()
            ->setHosts($hosts)
            ->build();

        $options = array(
            'index' => config('services.elastic_search.index'),
            'type'  => '_doc',
        );

        $handler = new ElasticsearchHandler($client, $options);
        $handler->setFormatter(new MyFormatter($options['index'], $options['type']));

        $monolog = new Logger('application');

        return $monolog->pushHandler($handler);
    }
}

<?php

namespace App\Helpers;

use Monolog\Formatter\ElasticsearchFormatter;
use function json_encode;

class MyFormatter extends ElasticsearchFormatter
{
    /**
     * @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'], JSON_PRETTY_PRINT);

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

'custom' => [
            'driver' => 'custom',
            'via' => \App\Helpers\CustomLogger::class,
            'formatter' => \App\Helpers\MyFormatter::class,
],

LOG_CHANNEL=custom

<!-- gh-comment-id:932452704 --> @fhferreira commented on GitHub (Oct 1, 2021): I created my own, because the Standard was failing when the LOG has an associative array. ``` <?php namespace App\Helpers; use Elasticsearch\ClientBuilder; use Monolog\Handler\ElasticsearchHandler; use Log; use Monolog\Logger; class CustomLogger { /** * Create a custom Monolog instance. * * @param array $config * @return \Monolog\Logger */ public function __invoke(array $config) { $hosts = [ [ 'host' => config('services.elastic_search.host'), 'port' => config('services.elastic_search.port'), 'index' => config('services.elastic_search.index'), 'scheme' => config('services.elastic_search.scheme'), 'user' => config('services.elastic_search.user'), 'pass' => config('services.elastic_search.pass'), 'type' => '_doc', 'retries' => 10, ] ]; $client = ClientBuilder::create() ->setHosts($hosts) ->build(); $options = array( 'index' => config('services.elastic_search.index'), 'type' => '_doc', ); $handler = new ElasticsearchHandler($client, $options); $handler->setFormatter(new MyFormatter($options['index'], $options['type'])); $monolog = new Logger('application'); return $monolog->pushHandler($handler); } } ``` ``` <?php namespace App\Helpers; use Monolog\Formatter\ElasticsearchFormatter; use function json_encode; class MyFormatter extends ElasticsearchFormatter { /** * @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'], JSON_PRETTY_PRINT); return parent::format($record); } } ``` ``` 'custom' => [ 'driver' => 'custom', 'via' => \App\Helpers\CustomLogger::class, 'formatter' => \App\Helpers\MyFormatter::class, ], ``` LOG_CHANNEL=custom
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/monolog#314
No description provided.