0

Monolog contains elastic search handler and formatter, but it's implementation to laravel as a custom channel is not as straightforward as described on Laravel documentation web site.

Max Shaian
  • 418
  • 4
  • 11
  • It shouldn't be a custom channel. It should be a [monolog channel](https://laravel.com/docs/8.x/logging#creating-monolog-handler-channels) and `with` should have the named parameters you're passing to it. Can you share how you tried to implement it? – apokryfos Jun 01 '21 at 09:42
  • It's the question with an answer below. With is not enough as Handler and Formatter constructors require additional parameters which are not compatible with configuration caching. – Max Shaian Jun 01 '21 at 09:51

1 Answers1

4

Here's a brief step by step instruction how to do that.

  1. Create a config file for your elastic search logging.
config/elastic_log.php

with the next content:

<?php

return [
    'host' => env('ELASTIC_HOST'),
    'index' => 'index_name',
    'prefix' => 'index_prefix',
    'type' => '_doc',
];

You can change your index name and prefix to any string values.

  1. In your .env file put your elastic host address:
ELASTIC_HOST=your_elastic_host:port
  1. Install elasticsearch/elasticsearch official package
composer require elasticsearch/elasticsearch
  1. Create ElasticLogging service provider
php artisan make:provider ElasticLogProvider

With the following content:

<?php

namespace App\Providers;

use Elasticsearch\Client;
use Elasticsearch\ClientBuilder;
use Illuminate\Support\ServiceProvider;
use Monolog\Formatter\ElasticsearchFormatter;
use Monolog\Handler\ElasticsearchHandler;

class ElasticLogProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        $index = rtrim(config('elastic_log.prefix'), '_') . '_' . config('elastic_log.index');
        $type = config('elastic_log.type');
        
        $this->app->bind(Client::class, function ($app) {
            return ClientBuilder::create()->setHosts([config('elastic_log.host')])->build();
        });

        $this->app->bind(ElasticsearchFormatter::class, function ($app) use ($index, $type) {
            return new ElasticsearchFormatter($index, $type);
        });

        $this->app->bind(ElasticsearchHandler::class, function ($app) use ($index, $type) {
            return new ElasticsearchHandler($app->make(Client::class), [
                'index'        => $index,
                'type'         => $type,
                'ignore_error' => false,
            ]);
        });
    }
}

Add this provider to your app.php config file to the providers array:

App\Providers\ElasticLogProvider::class,
  1. Create a command for elastic logging settings on the server. This command creates an index on the server if it doesn't exist yet. Now for the preparation of your server, just run elastic:log_setup;
php artisan make:command ElasticLogSetup

With the following content:

<?php

namespace App\Console\Commands;

use Elasticsearch\Client;
use Illuminate\Console\Command;

class ElasticLogSetup extends Command
{
    /**
     * @var Client
     */
    protected $client;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'elastic:log_setup';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Setup elastic log index';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct(Client $client)
    {
        $this->client = $client;
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $index = rtrim(config('elastic_log.prefix'), '_') . '_' . config('elastic_log.index');

        if (!$this->client->indices()->exists(['index' => $index])) {
            $this->client->indices()->create([
                'index' => $index,
            ]);
        }
    }
}

  1. In the file config/logging.php add this element to 'channels' array and import the related classes:
use Monolog\Formatter\ElasticsearchFormatter;
use Monolog\Handler\ElasticsearchHandler;

'elastic' => [
    'driver' => 'monolog',
    'handler' => ElasticsearchHandler::class,
    'level' => 'debug',
    'formatter' => ElasticsearchFormatter::class,
];
  1. Now you can use the channel 'elastic' or change it in your .env settings as a default channel:
LOG_CHANNEL=elastic

From now on, you can use standard laravel Log facade to send the information to your ElasticSearch server

Max Shaian
  • 418
  • 4
  • 11