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 Bundle Laravel Package

webgriffe/newrelic-bundle

Symfony bundle that integrates the New Relic PHP agent, automatically naming transactions after routes and reporting exceptions, custom metrics, and deployment markers so you can monitor performance and errors in New Relic APM.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is a Symfony 2/3-era wrapper around the New Relic PHP agent. It ships listeners, a Monolog handler, a Twig extension, a NewRelicInteractorInterface abstraction over the newrelic_* functions, and a deployment-notification console command. Treat it as glue code, not a framework feature — most of the value is in the transaction naming, exception forwarding, and custom parameters it wires up for you.

  1. Verify the prerequisites before anything else. You need the newrelic PHP extension installed and newrelic.appname/license configured in newrelic.ini, plus a Symfony version the bundle's composer.json actually allows (this fork targets Symfony 2.x). Check php -m | grep newrelic and composer why-not webgriffe/newrelic-bundle first — most "it doesn't work" reports are a version-constraint or missing-extension problem, not a bundle bug.

  2. Install and register.

    composer require webgriffe/newrelic-bundle
    
    // app/AppKernel.php
    public function registerBundles()
    {
        $bundles = [
            // ...
            new Ekino\NewRelicBundle\EkinoNewRelicBundle(),
        ];
    }
    

    Note the namespace: the package is a fork of the Ekino bundle, so the PHP namespace and the DI config root (ekino_new_relic) are inherited from upstream even though the Composer name is webgriffe/*. Read the bundle's DependencyInjection/Configuration.php in vendor/ — it is the single source of truth for the option names in your installed version.

  3. Minimal config. Turn on only what you need; every listener has a cost on every request.

    # app/config/config.yml
    ekino_new_relic:
        application_name: "%newrelic_app_name%"
        api_key:          "%newrelic_api_key%"      # only for deployment notifications
        license_key:      "%newrelic_license_key%"
        instrument:       true
        exceptions:       true
        commands:         true
        twig:             true
    
    # app/config/config_dev.yml
    ekino_new_relic:
        instrument: false     # keep dev traffic out of your APM dashboards
    
  4. First use case: name your transactions. Out of the box the request listener names transactions after the route. The first thing worth doing is replacing the default naming with something meaningful for your domain, so the New Relic "Web transactions" chart maps onto business concepts (checkout, search, export) instead of URL paths:

    $interactor = $this->get('ekino.new_relic.interactor');
    $interactor->nameTransaction('checkout.submit');
    $interactor->addCustomParameter('cart.items', count($cart));
    

    Then look at the Transactions → Web transactions view in New Relic. If you see the route name there, the wiring works and you can move on to parameters.

Implementation Patterns

Inject the interactor, never call newrelic_* directly. The interface is what makes the code testable and what degrades to a no-op when the extension is missing.

use Ekino\NewRelicBundle\NewRelic\NewRelicInteractorInterface;

class OrderProcessor
{
    private $newRelic;

    public function __construct(NewRelicInteractorInterface $newRelic)
    {
        $this->newRelic = $newRelic;
    }

    public function process(Order $order)
    {
        $this->newRelic->addCustomParameter('order.id', $order->getId());
        $this->newRelic->addCustomParameter('order.total', $order->getTotal());
        // ...
    }
}

The service id is ekino.new_relic.interactor; alias it or use a compiler pass if you want autowiring-style injection in a modern-ish container.

Name transactions at the boundary, not deep inside services. Do it in a controller, a kernel/request listener, or a thin Voter-like layer so the name is stable and cheap. Naming inside a domain service couples your business code to the route lifecycle and produces names that vary per call site.

Use custom events for sub-transaction work. If a job runs several expensive phases, record them rather than pretending they're separate transactions:

$this->newRelic->addCustomEvent('OrderExport', [
    'rows'      => $count,
    'duration'  => $elapsed,
]);

This keeps the parent web transaction intact while giving you queryable data in New Relic.

Instrument console workers deliberately. The command listener names CLI transactions per command, but long-running workers (queue consumers) become one giant transaction unless you segment. Call nameTransaction() per job and periodically endTransaction() / start a new one; otherwise your worker's memory graph is a single flat line with no per-job detail.

Forward only the logs you care about through Monolog. The bundle ships a handler that pushes records into New Relic. Scope it to a dedicated channel instead of the whole app channel, and set the level to error:

monolog:
    handlers:
        newrelic:
            type: service
            id: ekino.new_relic.monolog_handler
            channels: ["newrelic"]
            level: error

Then log to the newrelic channel from the places where context is genuinely valuable (payment failures, third-party timeouts). This gives you a New Relic error with parameters attached, without paying for every info line.

Deployment notifications belong in CI, not in code. The bundle exposes a console command for deployment markers; call it from your deploy pipeline after cache warmup:

php app/console ekino:newrelic:notify-deployment \
    --app-name="$APP_NAME" \
    --app-id="$NEWRELIC_APP_ID" \
    --user="$DEPLOY_USER" \
    --revision="$GIT_SHA" \
    --description="Deploy $GIT_SHA"

This is the highest-value-per-line integration: deploy markers on your charts make every "it got slow at 14:32" conversation answerable in seconds.

Wrap the interactor in your own decorator. Whether you need a kill-switch (disable APM for a tenant or a request type), a scrubber for PII in parameters, or a buffer for tests, a decorator is cleaner than branching on config everywhere. Because the interface is small and stable, this is the safest extension point in the whole bundle.

Gotchas and Tips

It is a Symfony 2-era package with near-zero adoption. Zero dependents and a 0.06 score mean you are on your own — no upstream fixes, no community stack traces. Expect composer update friction on Symfony 3.4+, and near-certain failure on Symfony 4+/PHP 8. If you are on a modern stack, budget for a fork or a ~200-line replacement rather than fighting this. The replacement surface (an interface, five listener classes, a Monolog handler, a Twig extension) is small enough that forking is often cheaper than adapting.

The extension being absent must not break the app. Depending on version, the bundle swaps in a no-op interactor when newrelic isn't loaded, but don't rely on it silently — verify in a CI environment without the agent. A fatal Call to undefined function newrelic_name_transaction() during a deploy is the classic failure mode of "it worked on the APM-enabled staging box."

Config root is inherited, not renamed. You install webgriffe/newrelic-bundle but configure ekino_new_relic:. This trips up everyone for the first twenty minutes — the error is "Unrecognized option under ekino_new_relic" (good case) or your config silently being ignored because it sits under the wrong root (bad case). Always confirm against vendor/webgriffe/newrelic-bundle/DependencyInjection/Configuration.php.

Double instrumentation is easy to create. If you name a transaction manually and leave the default request listener enabled, you can end up with a transaction named after the route with your custom name lost. Either keep the listener and only add parameters, or disable the automatic naming and take ownership of it — don't do both half-way.

Transaction names get truncated. New Relic caps transaction names (around 255 characters) and rolls up anything with high cardinality. Never interpolate user IDs, emails, or URLs with query strings into a transaction name; put those into addCustomParameter() instead. A transaction name with an order ID in it will silently destroy your aggregate metrics.

Custom parameters have hard limits and no PII policy. New Relic stores a limited number of parameters per transaction and keeps them for the retention window. Scrub emails, tokens, card data, and full request bodies before they leave the process — do it in your decorator so it's enforced in one place.

Monolog handler recursion. If the New Relic handler logs its own failures back through Monolog's app channel, you get a recursive flush that hangs the request. Keep the handler scoped to a dedicated channel and set bubble: false if you notice duplicates or loops.

Browser-side RUM needs two things. The Twig integration injects the browser agent snippet, but it only appears if (a) the account has Browser monitoring enabled and (b) the response is HTML — JSON API responses will never get the header. If your app is API-first, RUM is a non-feature and you should simply turn twig off and ignore that slice of the bundle.

Deployment API changed over time. notify-deployment posts to the New Relic deployments API; the required key is the REST API key (api_key), not the license key and not an Insights insert key. A 403 on the command almost always means you pasted the wrong key type, and older versions use the v1 endpoint, so an account migrated to newer API keys may need --api-url overrides or a manual curl call in CI.

Testing: assert on the interactor, not the agent. In unit tests, replace ekino.new_relic.interactor with a spy implementing the interface, and assert nameTransaction('checkout.submit') and addCustomParameter('cart.items', 3) were called. Never let integration tests talk to the real agent — it will pollute your APM data with CI traffic and make dashboards untrustworthy. Add instrument: false in config_test.yml as a belt-and-braces measure.

Debugging when nothing shows up: check in this order — php -m for the extension, newrelic.ini app name vs the application_name you configured, whether instrument is false in the current env, whether the transaction is a CLI command (different view in the UI), and whether an upstream proxy is stripping the daemon connection. The bundle is thin; if a metric is missing, the problem is almost never the bundle.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console