How to: Laravel Grafana Logging

How to: Laravel Grafana Logging

— 1 min read

The Problem

Tired of remoting into the server to check logs?
Tired of occasionally deleting log files to free up space?
Need to quickly find past log data?

Just send them to Grafana using Loki!

Implementation

Requirements

  1. Working self-hosted grafana & loki solution or the free online version.
  2. Laravel 11
  3. guzzlehttp

Steps to follow

  1. Install using composer
  2. Make App/Logging/LokiHandler.php
  3. Edit the logging.php to add the new loki hander.
  4. Update your .env

Code Snippets

.env

LOKI_URL=https://log-url
LOKI_USER=loki-user
LOKI_PASSWORD=loki-api-key
LOG_CHANNEL=loki

LokiHandler.php

<?php

namespace App\Logging;

use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
use Monolog\LogRecord;

class LokiHandler extends AbstractProcessingHandler
{
    protected Client $client;

    protected string $url;

    protected string $username;

    protected string $password;

    public function __construct($level = Logger::DEBUG, bool $bubble = true)
    {
        parent::__construct($level, $bubble);

        $this->client = new Client;
        $this->url = rtrim(env('LOKI_URL', ''), '/');
        $this->username = env('LOKI_USER', '');
        $this->password = env('LOKI_PASSWORD', '');
    }

    protected function write(LogRecord $record): void
    {
        try {
            // Get current time in nanoseconds using Carbon
            $timestamp = Carbon::now()->timestamp * 1000000000;

            // Construct Loki JSON entry with message and timestamp
            $logEntry = [
                'streams' => [
                    [
                        'stream' => [
                            'job' => 'epi-counter',
                            'level' => strtolower($record->level->getName()),
                        ],
                        'values' => [
                            [(string) $timestamp, $record->message],
                        ],
                    ],
                ],
            ];

            $response = $this->client->post($this->url.'/loki/api/v1/push', [
                'auth' => [$this->username, $this->password],
                'json' => $logEntry,
                'headers' => ['Content-Type' => 'application/json'],
            ]);
        } catch (RequestException $e) {
            // Handle errors if push fails
            error_log('🚨 Loki push failed: '.$e->getMessage());
            if ($e->hasResponse()) {
                error_log('🔍 Response: '.$e->getResponse()->getBody()->getContents());
            }
        }
    }
}

logging.php

        'loki' => [
            'driver' => 'monolog',
            'level' => 'debug',
            'handler' => LokiHandler::class,
            'formatter' => Monolog\Formatter\JsonFormatter::class,
        ],

Affiliate Links

Check out what Pegos suggests for How to: Laravel Grafana Logging!

    No affiliates available for this post!

Related Posts

Thirsty for more? Check out Sudorealm-related posts!