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

Newrelic Logger Bundle Laravel Package

ias/newrelic-logger-bundle

A Symfony bundle that integrates New Relic logging with your application's Monolog setup, forwarding log records to New Relic for centralized visibility and analysis. Simplifies configuring a New Relic log handler so you can correlate application events with observability data without custom wiring.

View on GitHub
Deep Wiki
Context7

Getting Started

Do not add this to composer.json. ias/newrelic-logger-bundle is a Symfony bundle (Bundle class + DI extension + compiler pass), it is archived, and it has 0 stars / 0 dependents. In a Laravel app it will be inert: no package discovery, no config/logging.php driver, no service provider. Pulling it in drags symfony/http-kernel and symfony/dependency-injection along for the sake of one Monolog handler.

Use it the only way it has value: as a ~200-line reference implementation of the New Relic Logs ingestion contract.

Minimal steps:

  1. git clone https://github.com/theias/newrelic-logger-bundle into a scratch directory — do not composer require.
  2. Read the handler class first. That is the transferable artifact: an AbstractProcessingHandler subclass that formats a record and POSTs it to https://log-api.newrelic.com/log/v1 (EU: https://log-api.eu.newrelic.com/log/v1) with a license key.
  3. Read DependencyInjection/Configuration.php next. That is where the real answers live: endpoint/region, API key, minimum log level, batching, and which enrichment attributes get stamped on each record (service.name, host.name, trace.id, span.id).
  4. Skim the compiler pass only to confirm how the handler is attached to Monolog — nothing there transfers to Laravel.
  5. Sanity-check the record envelope against New Relic's Logs API docs before you copy anything: message, timestamp, attributes (flat key/value map), plus per-record metadata. New Relic rejects on shape, not on intent.

First use case: stand up a read-only spike — a Laravel custom logging channel that ships a single test record to New Relic Logs and confirms it is queryable in the UI, correlated with an APM trace. One to two days of work end to end, including tests, and it is throwaway by design.

Before you write a line of handler code, check the two supported paths that probably remove the need for the handler entirely:

  • Agent forwarding (preferred). Emit JSON to stderr/stdout with a JSON formatter in a Stderr channel, and let the New Relic PHP agent forward. Zero custom code, vendor-supported, batching and backpressure included.
  • Official enricher. newrelic/monolog-enricher adds trace.id/span.id correlation to records; pair it with agent forwarding.

Only build a bespoke HTTP sender if agent installation is genuinely impossible (locked-down containers, shared hosting, serverless).

Implementation Patterns

Pattern 1 — Config-channel first, custom driver second

Start with a plain channel in config/logging.php that emits structured JSON. Most teams stop here once the agent is forwarding:

'newrelic' => [
    'driver'    => 'monolog',
    'handler'   => Monolog\Handler\StreamHandler::class,
    'with'      => ['stream' => 'php://stderr'],
    'formatter' => Monolog\Formatter\JsonFormatter::class,
    'level'     => env('LOG_LEVEL', 'info'),
],

If you truly must ship directly, register a custom driver with Log::extend() rather than subclassing anything from the repo:

// app/Providers/LoggingServiceProvider.php
Log::extend('newrelic', function ($app, array $config) {
    $logger = new Monolog\Logger($config['name'] ?? 'newrelic');

    $http = new Monolog\Handler\NewRelicLogsHandler(
        apiKey:   config('services.newrelic.license_key'),
        endpoint: config('services.newrelic.logs_endpoint'), // region-specific
        client:   $app->make(GuzzleHttp\ClientInterface::class), // reuse what you ship
    );

    // Always compose a guaranteed local fallback.
    $fallback = (new Monolog\Handler\StreamHandler(storage_path('logs/newrelic-fallback.log')))
        ->setLevel(Monolog\Logger::ERROR);

    $logger->pushHandler(new Monolog\Handler\WhatFailureGroupHandler([$http, $fallback]));
    return $logger;
});

Pattern 2 — Buffer, don't POST per record

A synchronous HTTP call per log record couples request latency and request reliability to a third-party SaaS. Wrap in a BufferHandler and flush on close/reset, or use a FingersCrossedHandler so you only ship a buffer when something actually goes wrong:

$buffer = new Monolog\Handler\BufferHandler($http, $bufferLimit = 50, $level, true, true);

Cap the buffer. An unbounded in-process buffer is a memory leak with extra steps, and it silently loses everything on deploy/restart.

Pattern 3 — Enrich with trace context via a processor

This is the whole point of the integration: logs that carry trace.id / span.id turn log search into a debugging workflow. Do it in a processor, not in the handler, so it applies to every channel:

$logger->pushProcessor(function (LogRecord $record) {
    $record->extra['service.name'] = config('app.name');
    $record->extra['host.name']    = gethostname();
    if ($traceId = newrelic_get_trace_metadata()['trace_id'] ?? null) {
        $record->extra['trace.id'] = $traceId;
    }
    return $record;
});

Pattern 4 — Filter and redact at the channel boundary

Ingest volume maps directly to the bill, and every attribute you ship leaves the perimeter. Put level filtering and PII redaction in a processor that runs before the transport handler, and keep the redaction rules in-repo under review — an abandoned library gives you nowhere to land that policy.

Workflow order that actually holds up

  1. Quantify current log volume and monthly ingest budget ceiling.
  2. Spike agent-based forwarding in staging; measure log-to-query latency.
  3. If the spike fails, port the handler behind a feature flag with a StreamHandler fallback.
  4. Canary one non-production service for a week; check queryability, cost, and request-latency regression.
  5. Roll per service with an ingest alarm and a documented kill switch (flip the channel back).

Gotchas and Tips

  • Monolog 3 will break naive ports. Code written against Monolog 1/2 does not load on Monolog 3: AbstractProcessingHandler::write() now receives a LogRecord value object, and the record array is gone. Every ported line must be validated against Monolog 3 explicitly.
  • Regional endpoint mismatch fails silently. log-api.newrelic.com vs log-api.eu.newrelic.com — send EU-account logs to the US endpoint and they vanish. This is the single most common "it's logging but nothing shows up" bug.
  • No auto-discovery in Laravel. If you clone code from this repo and drop it in, nothing wires itself. composer require gets you an inert package. There is no service provider, no facade, no config/logging.php integration — that is on you.
  • Never let logging break a request. Sub-second timeout, WhatFailureGroupHandler or equivalent, and a circuit breaker that degrades to local logging on 429/5xx rather than propagating. A log shipper that can 500 a checkout is worse than no log shipper.
  • Silent drops are the default failure mode. License key rotation, wrong region, oversized payload, or API outage all look identical from the app: nothing happens. Alert on ingest volume dropping to zero, not on errors in your app.
  • Truncate before send. Stack traces and large context arrays blow past payload limits and get rejected wholesale. Truncate message and flatten/drop attributes above a size threshold.
  • Keep the license key in secrets, not .env committed to the repo. Ingest keys are scoped to the account and let anyone write to your log stream.
  • Pin everything in a fork. If you vendor the handler, pin PHP and Monolog versions, add an owner, and put a calendar review against your next Monolog/PHP major upgrade. Archived means the next break is yours to fix.
  • Test against a mocked endpoint, not production. Assert the JSON envelope — message, timestamp, service.name, attributes, trace IDs — in a contract test. Do not verify by watching a dashboard.
  • Extension points you actually get: a Monolog processor (enrichment), a formatter (envelope shape), and a handler wrapper (Buffer/FingersCrossed/WhatFailureGroup). There is no supported extension point in the bundle itself — it is a closed, unmaintained unit.
  • Egress rules matter. Confirm TLS and proxy rules to the New Relic endpoint from every environment, including CI and any ephemeral/serverless runtime where the PHP agent may not be installed.
  • The real recommendation: use this as the specification — endpoint, envelope, enrichment fields — and hand the implementation to the vendor-supported path (PHP agent + newrelic/monolog-enricher). You keep the pattern and drop the dependency.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings