Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Graylog Laravel Package

exolnet/laravel-graylog

Exolnet's Laravel Graylog package integrates Graylog with Laravel's logging system via a GELF handler, sending application logs to Graylog. Configure host, port, and transport for centralized log collection and search.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire it up (5 minutes):

composer require exolnet/laravel-graylog:^1.15
php artisan vendor:publish --tag=graylog   # writes config/graylog.php

The service provider is auto-discovered. Add a channel in config/logging.php:

'graylog' => [
    'driver'    => 'graylog',
    'host'      => env('GRAYLOG_HOST', 'localhost'),
    'port'      => env('GRAYLOG_PORT', 12201),
    'transport' => env('GRAYLOG_TRANSPORT', 'udp'),
    'level'     => env('LOG_LEVEL', 'debug'),
    'facility'  => env('GRAYLOG_FACILITY', env('APP_NAME')),
],

Confirm the exact key names against the published config/graylog.php — they are the source of truth, not this snippet.

Where to look first:

  1. config/graylog.php — transport, host/port, facility, default level.
  2. config/logging.php — the channel entry (this is what you actually tune day-to-day).
  3. vendor/exolnet/laravel-graylog/src — the service provider and the handler/transport factory, which is where you go when a message silently disappears.

First use case: dual-write production logs to disk and Graylog, so you keep local fallback when the collector is unreachable:

'stack' => [
    'driver'   => 'stack',
    'channels' => ['single', 'graylog'],
],

Then .env: LOG_CHANNEL=stack, LOG_LEVEL=info. Verify with:

Log::channel('graylog')->info('assessment smoke test', ['order_id' => 42]);

Search Graylog for order_id:42. If nothing appears and the local file has the line, the problem is transport/network, not Laravel.

Version floor: v1.15.0 adds Laravel 12 and PHP 8.4 support and drops Laravel 10. If you're on Laravel 10, stay on ^1.14 — do not float the constraint.

Implementation Patterns

Stack, don't replace. Emit to Graylog alongside single/daily in every environment except local, where the collector usually isn't running. Gate it on config rather than code:

'channels' => env('GRAYLOG_ENABLED', false)
    ? ['single', 'graylog']
    : ['single'],

Request-scoped context via middleware. Graylog's value is structured search, so push correlation data once instead of sprinkling it through every call:

Log::withContext([
    'request_id' => (string) Str::uuid(),
    'user_id'    => optional(auth()->user())->id,
    'route'      => request()->route()?->getName(),
]);

Put this early in the web/api middleware group. It applies to every channel in the stack.

Separate channels for separate streams. Use multiple Graylog channels with different facility values or levels — e.g. a security channel at warning and an audit channel at info — then route Graylog streams off the facility rather than writing complex extractors.

Log::channel('security')->warning('Failed login', ['email' => $email, 'ip' => $ip]);

Exceptions. Keep the default report() behaviour into the stack; you get the exception class, message, file/line in Graylog for free. For noisy third-party exceptions use $dontReport / $this->reportable() rather than filtering downstream.

Testing. Never let tests hit a real collector. In phpunit.xml set GRAYLOG_ENABLED=false, and assert on the channel rather than the wire:

Log::spy();
$this->post('/orders');
Log::shouldHaveReceived('warning')->withArgs(fn ($m) => str_contains($m, 'failed'));

If you need to assert the actual channel name resolves, use Log::channel('graylog') inside a test that swaps the underlying handler for a TestHandler — a misconfigured host will otherwise surface as a slow test, not a failure.

Short-lived processes. CLI commands, queue workers and Octane workers all go through the same channel; there's no batching layer, so a job logging 10k lines issues 10k datagrams. Throttle at the call site or drop to daily files for high-volume jobs and ship those out-of-band.

Gotchas and Tips

  • UDP is lossy and unforgiving. Default udp gives you no delivery guarantee and no error when a datagram is dropped. Also watch size: a fat exception trace plus large context can exceed the datagram/MTU budget and vanish or fragment. Use tcp (or tls) for production and anything with stack traces; reserve udp for low-value high-volume chatter.
  • Laravel 10 is gone in this release. v1.15.0 supports Laravel 11/12 on PHP 8.2–8.4. Pin ^1.14 if you're still on L10, and check your composer constraint isn't ^1.0 on a shared package.
  • env() dies under config:cache. Only reference env vars inside config files (as above). A channel defined inline in a service provider with env() will break in production after php artisan config:cache.
  • Re-run config:cache on deploy after changing hosts, ports, or transport. Stale cached config pointing at the old collector is the #1 "why are logs missing" cause.
  • Level filtering happens client-side first. Anything below the channel level never leaves the app — you cannot recover it in Graylog. Set LOG_LEVEL=debug temporarily via env rather than editing config if you need to widen the net during an incident.
  • GELF extra fields want flat scalars. Nested arrays and objects in the context array are the usual reason a log line arrives but your custom field is missing or mangled. Flatten before logging: ['payload' => json_encode($data)].
  • TLS surprises. Self-signed collectors will fail the TLS transport handshake; you generally need a properly trusted cert or must terminate TLS at a local sidecar. Test the transport in staging before rolling to production.
  • Debugging a black hole. In order: (1) does Log::channel('graylog') resolve without throwing? (2) is the message in storage/logs/laravel.log via the stack? (3) can the host reach GRAYLOG_HOST:GRAYLOG_PORT — nc -zvu host 12201 for UDP, nc -zv for TCP? (4) check the Graylog input is bound to 0.0.0.0, not 127.0.0.1. Only then look at the package source.
  • Extension points. The channel driver is resolved by name from logging.php, so you can register your own driver key pointing at a subclassed handler, or bind a custom GELF publisher/transport in a service provider if you need a proxy, retry logic, or a non-standard transport. Override the formatter if you need extra default fields on every message rather than relying on Log::withContext().
  • No facade. Use Laravel's Log facade with an explicit channel name; there is nothing package-specific to learn beyond the channel config.
  • Upgrade path from 1.14 → 1.15 is low-risk (dependency matrix only, no config or API changes), but verify your Monolog major version aligns with Laravel 12's requirements before bumping.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums