PHP frameworks: Integrating support for New Relic

This document is aimed at the developers or maintainers of PHP frameworks. It suggests ways to extend your framework by adding support for New Relic.

The PHP agent supports frameworks by figuring out where in the framework code web transactions can be appropriately named, and naming web transactions based on information found in the class / function call etc. This solution is fragile and subject to the developers altering their code. New Relic encourages framework developers to put in the few calls needed to improve the out-of-box user experience with the framework they maintain.

Helping your users

New Relic can identify the web transaction name and where to insert JavaScript headers and footers for page load timing. However, to improve end users' experience, increase performance, and make code maintenance easier, framework developers should do this work themselves.

It is up to the developers of the various frameworks to decide if they want to help their users by adding native support for New Relic. In almost all cases adding support for New Relic involves inserting 3 API calls somewhere in the framework code.

Terminology

In order to understand how to best add support for New Relic, it is useful to understand some of the key points of interaction.

Term Definiton
Web transactions Web transactions are asset requests (or user hits) to your site. With frameworks, this is often handled by an MVC dispatching mechanism.
Metrics Metrics are named entities that report timing information. New Relic uses these metrics to display dashboards for your application and server health. For example, we instrument calls to MySQL and generate metrics called Database/select or Database/update whenever a user selects or updates data. Note: Metrics only contain timing data.
Transaction traces During every harvest period (once each minute), New Relic records the slowest web transaction that falls below a user-defined threshold. This is a transaction trace. It has more detail than simple metrics. If enabled, it will include a detailed call graph of exactly what functions were called and how long they took. For slow SQL statements, it obfuscates all data in the call.

Naming transactions

How you name your web transactions will affect the quality of the user experience.

Examples:

If you have a blog-style framework, you would name the various transactions based on the user activity: display, edit, login, etc.

If you use an MVC architecture, then an appropriate naming convention is controller/action. Do not include any request-specific data in the transaction name. For example, using the actual request URL leads to metric grouping issues.

Platform Transaction naming example
Drupal 7 The dispatching is done in menu_execute_active_handler(). This calls call_user_func_array(), with the first argument being the name of the action. That is what to set as the web transaction name.
CakePHP 1.3 CakePHP has a Dispatcher class with an _invoke method. This calls the appropriate controller class with a given action, and the transaction is named controller/action where controller is the name of the controller class.

At the point where you want to route code to a specific controller and action (if you are using MVC) or to an action (if you are not using MVC), insert code similar to this:

Controller and action (when using MVC):

if (extension_loaded ('newrelic')) {
  newrelic_name_transaction ($controller . '/' . $action);
}

Action only (not using MVC):

if (extension_loaded ('newrelic')) {
  newrelic_name_transaction ($action);
}

Inserting the JavaScript header and footer

For page load timing (sometimes referred to as real user monitoring or RUM), insert the JavaScript header and footer. This allows you to monitor the end users' experience of the generated page.

  • Recommendation: If your framework has a central function that generates all page headers and footers, install the JavaScript code here.
  • For frameworks that are template-driven, insert these in your header and footer templates.

Inserting in a page generator function

The header must be inserted as close to the top of the generated page as possible. Immediately after the <meta http-equiv....> tag is the ideal place. It should precede any JavaScript, CSS stylesheets or other linked or embedded content.

if (extension_loaded ('newrelic')) {
  newrelic_get_browser_timing_header();
}

newrelic_get_browser_timing_header() takes an optional bool argument that defaults to true. It indicates whether or not the returned string should be enclosed by script tags.

Recommendation: Insert the footer immediately before the </body> page close tag as the very last thing on the generated page.

if (extension_loaded ('newrelic')) {
    newrelic_get_browser_timing_footer();
}

newrelic_get_browser_timing_footer() takes an optional bool that defaults to true. It indicates whether or not the returned string should be enclosed by script tags.

Inserting in templates

Use this header template as an example:

<?php if (extension_loaded ('newrelic')) {
  echo newrelic_get_browser_timing_header();
} ?>

Use this footer template as an example:

<?php if (extension_loaded ('newrelic')) {
  echo newrelic_get_browser_timing_footer();
} ?>

For more help

Additional documentation resources include:

If you need additional help, get support at support.newrelic.com.