Installation
Raygun4PHP provider
A library you can easily add to your PHP-based website, which then allows you to transmit all errors and exceptions to your Raygun Crash Reporting dashboard. Installation is painless, and configuring your site to start real time error monitoring and crash reporting takes only 5 minutes.
Raygun4PHP is designed to send both classical PHP errors and Exception objects by providing Send() functions. You can add a set of tags (as an array of strings) to identify certain errors, add custom user data, and customize how errors are grouped.
Installation
Step 1 - Add Raygun4PHP
With Composer
Composer is a package management tool for PHP which automatically fetches dependencies and also supports autoloading - this is a low-impact way to get Raygun4PHP into your site.
- If you use a *nix environment, follow the instructions to install Composer. Windows users can run this installer to automatically add it to the path etc.
- Inside your project's root directory create a
composer.json
file, containing:
{
"require": {
"mindscape/raygun4php": "^2.0"
}
}
- From your shell run
php composer.phar install
(*nix) orcomposer install
(Windows). This will download Raygun4PHP and create the appropriate autoload data. - Then in a PHP file just add this, and the library will be ready for use:
require_once 'vendor/autoload.php'
Manually with Git
Clone the Raygun4PHP repository and copy the folder src/Raygun4php
into an appropriate subdirectory in your project, such as /vendor/Raygun4php
. Then add the following require
definitions for RaygunClient.php
inside the file you want to make a call to Send()
.
Step 2 - Usage
You can send both PHP errors and object-oriented exceptions to Raygun. An easy way to accomplish this is to create a file containing exception and error handlers which make calls to the appropriate Raygun4php functions. As above, import Raygun4php - if you're using Composer, just add require_once 'vendor/autoload.php'
, or if not manually import RaygunClient.php. Then, create handlers that look like this:
<?php
namespace {
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use Raygun4php\RaygunClient;
use Raygun4php\Transports\GuzzleAsync;
$httpClient = new Client([
'base_uri' => 'https://api.raygun.com',
'headers' => [
'X-ApiKey' => 'paste_your_api_key_here'
]
]);
$transport = new GuzzleAsync($httpClient);
$raygunClient = new RaygunClient($transport);
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($raygunClient) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function($exception) use ($raygunClient) {
$raygunClient->SendException($exception);
});
register_shutdown_function(function() use ($raygunClient) {
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
[$type, $message, $file, $line] = $lastError;
$raygunClient->SendError($type, $message, $file, $line);
}
});
register_shutdown_function([$transport, 'wait']);
}
Note that if you are placing it inside a file with a namespace of your choosing, the above code should be declared to be within the global namespace (thus the namespace { }
is required). You will also need whichever requires statement as above (autoload or manual) before the $raygunClient
instantiation. Copy your application's API key from the Raygun Crash Reporting dashboard, and place it in the constructor call as above (do not include the curly brackets). If the handlers reside in their own file, just import it in every file where you'd like exceptions and errors to be sent, and they will be delivered to Raygun Crash Reporting.
Step 3 - Release
Deploy Raygun into your production environment for best results, or raise a test exception. Once we detect your first error event, the Raygun app will automatically update.
Manually sending exceptions
You can manually send exceptions at any time with the stack trace like this:
<?php
require_once "vendor/autoload.php"; // if using Composer
// ...
try {
throw new Exception("Your message");
} catch (Exception $e) {
$raygunClient->SendException($e);
}
Adding tags
Tags can be added to error data to provide extra information and to help filtering errors within Raygun. They are provided as an array of strings or numbers passed as the 5th argument to the SendError
function and as the 2nd argument to the SendException
function.
The declaration of the exception and error handlers using tags could look something like this:
<?php
// ...
$raygunClient = new RaygunClient($transport);
$tags = ['staging-environment', 'machine-4'];
set_error_handler(function ($errno, $errstr, $errfile, $errline) use ($raygunClient, $tags) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline, $tags);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function ($exception) use ($raygunClient, $tags) {
$_tags = array_merge($tags, ['uncaught-exception', 'fatal']);
$raygunClient->SendException($exception, $_tags);
});
register_shutdown_function(function () use ($raygunClient, $tags) {
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
[$type, $message, $file, $line] = $lastError;
$_tags = array_merge($tags, ['fatal']);
$raygunClient->SendError($type, $message, $file, $line, $_tags);
}
});
// ...
If you would prefer more specific tagging, error constants can be mapped to strings. This approach does not require the reflection API, though be wary of changes to the error constants. A mapping such as:
<?php
const E_CONST_TAG = [
E_ERROR => "error",
E_WARNING => "warning",
E_PARSE => "parse-error",
E_NOTICE => "notice",
E_CORE_ERROR => "core-error",
E_CORE_WARNING => "core-warning",
E_COMPILE_ERROR => "compile-error",
E_COMPILE_WARNING => "compile-warning",
E_USER_ERROR => "user-error",
E_USER_WARNING => "user-warning",
E_USER_NOTICE => "user-notice",
E_STRICT => "strict",
E_RECOVERABLE_ERROR => "recoverable-error",
E_DEPRECATED => "deprecated",
E_USER_DEPRECATED => "user-deprecated",
];
Could be incorporated into your handlers like so:
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($raygunClient) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline, [E_CONST_TAG[$errno]]);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function($exception) use ($raygunClient) {
$raygunClient->SendException($exception, ['uncaught-exception', 'fatal']);
});
register_shutdown_function(function() use ($raygunClient) {
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
[$type, $message, $file, $line] = $lastError;
$raygunClient->SendError($type, $message, $file, $line, [E_CONST_TAG[$type], 'fatal']);
}
});
Synchronous usage
The provider includes two Guzzle interfaces for transporting data; asynchronous and synchronous. We recommend that you have cURL installed on your server. If it is not installed, Guzzle will use a PHP stream wrapper.
The asynchronous usage above is recommended, but you can use the GuzzleSync
transport instead.
Example
The transport POSTs the message, blocks and receives the HTTP response from the Raygun API.
<?php
namespace {
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use Raygun4php\RaygunClient;
use Raygun4php\Transports\GuzzleSync;
$httpClient = new Client([
'base_uri' => 'https://api.raygun.com',
'headers' => [
'X-ApiKey' => 'paste_your_api_key_here'
]
]);
$transport = new GuzzleSync($httpClient);
$raygunClient = new RaygunClient($transport);
$tags = ['synchronous-transport'];
set_error_handler(function ($errno, $errstr, $errfile, $errline) use ($raygunClient, $tags) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline, $tags);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function ($exception) use ($raygunClient, $tags) {
$_tags = array_merge($tags, ['uncaught-exception', 'fatal']);
$raygunClient->SendException($exception, $_tags);
});
register_shutdown_function(function () use ($raygunClient, $tags) {
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
[$type, $message, $file, $line] = $lastError;
$_tags = array_merge($tags, ['fatal']);
$raygunClient->SendError($type, $message, $file, $line, $_tags);
}
});
}
HTTP Proxy
You can make Raygun4PHP post through an HTTP proxy of your choice like this:
<?php
// ...
$httpClient = new Client([
'base_uri' => 'https://api.raygun.com',
'proxy' => 'https://someproxy:8080',
'headers' => [
'X-ApiKey' => 'paste_your_api_key_here'
]
]);
See Guzzle's proxy documentation for more options.
Debugging with a logger
We recommend using a logger which is compatible with the PSR-3 LoggerInterface (e.g. Monolog).
Expanding on the asynchronous usage example above, you can set a logger to be used by the transport like so:
<?php
namespace {
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use Raygun4php\RaygunClient;
use Raygun4php\Transports\GuzzleAsync;
use Monolog\Handler\FirePHPHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
$httpClient = new Client([
'base_uri' => 'https://api.raygun.com',
'headers' => [
'X-ApiKey' => 'paste_your_api_key_here'
]
]);
$transport = new GuzzleAsync($httpClient);
// Create logger
$logger = new Logger('my_logger');
$logger->pushHandler(new StreamHandler(__DIR__ . '/debug.log'));
$logger->pushHandler(new FirePHPHandler());
// Attach logger to transport
$transport->setLogger($logger);
$raygunClient = new RaygunClient($transport);
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($raygunClient) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function($exception) use ($raygunClient) {
$raygunClient->SendException($exception, ['uncaught-exception', 'fatal']);
});
register_shutdown_function(function() use ($raygunClient) {
$lastError = error_get_last();
if (!is_null($lastError) && $lastError['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
[$type, $message, $file, $line] = $lastError;
$raygunClient->SendError($type, $message, $file, $line, ['fatal']);
}
});
register_shutdown_function([$transport, 'wait']);
}
Response codes
- 202: Message received by Raygun API correctly
- 400: Bad Request. This may indicate an invalid payload - please contact us if you continue to see this.
- 403: Invalid API key. API keys can be found in your Raygun Application Settings
Version numbers
You can transmit the version number of your PHP project along with the message by calling SetVersion()
on your RaygunClient after it is instantiated - this is optional but recommended as the version number is considered to be first-class data for a message.
<?php
$raygunClient = new RaygunClient($transport);
$raygunClient->SetVersion('1.0.0.0');
Adding custom data
Custom data can be added as an associative array to a particular error report, or attached to all error reports.
Attaching data to a caught exception
<?php
try {
$dataFromClient = json_decode($jsonString);
} catch(Exception $e) {
$customData = [
"clientId" => "abc123"
];
$raygunClient->SendException($e, null, $customData);
}
Attaching data to all error reports
In your Raygun set-up script:
<?php
// ...
$raygunClient = new RaygunClient($transport);
$tags = [];
$customData = [
"myKey" => "some value"
];
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($raygunClient, $tags, $customData) {
$raygunClient->SendError($errno, $errstr, $errfile, $errline, $tags, $customData);
}, E_ALL ^ (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)); // Fatal errors will be sent before shutdown
set_exception_handler(function($exception) use ($raygunClient, $tags, $customData) {
$_tags = array_merge($tags, ['uncaught-exception', 'fatal']);
$raygunClient->SendException($exception, $_tags, $customData);
});
// ...
Custom grouping
Error instances are grouped automatically using the Raygun4PHP hasher logic.
Grouping is, by default, based (in part) on the message (i.e.,
$errstr
). So it is best to not include identifiers in$errstr
(when using$raygunClient->SendError()
).e.g., "User 12345 does not have permissions to launch rocket" would get put in a different group for every user You can use the
$userCustomData
parameter, to include per instance unique values. Alternatively:
You can override this by passing a callback and manually group instances together by passing the same key for the errors/exceptions. The callback's signature can take in the error payload, stack trace and then return a string which functions as the key before mentioned.
<?php
$raygunClient->SetGroupingKey(function($payload, $stackTrace) {
// Inspect the above parameters and return a hash from the properties
return $payload->Details->Error->Message; // Naive message-based grouping only
});
If the callback doesn't return a string, the error will be grouped automatically.
User tracking
Users are tracked automatically by setting a random UUID, stored as a cookie. You can provide your own details about the user by passing a string (either username or email address) when calling the SetUser($user)
method. That information will then be visible in the dashboard.
If the user logs in or out, be sure to call it again passing in the new user (or just call $raygunClient->SetUser()
to assign a new random identifier).
<?php
$raygunClient->SetUser($user);
This feature can be used in CLI mode by calling SetUser(string)
at the start of your session.
The string properties on a User have a maximum length of 255 characters. Users who have fields that exceed this amount will not be processed.
Additional Data (Since 1.5)
Extra information can be passed, used to provide an affected user count and reports.
<?php
$raygunClient->SetUser($user, $firstName, $fullName, $email, $isAnonymous, $uuid);
In this case $user
should be a unique identifier used to identify your users. If you set this to their email address, be sure to also set the $email
parameter too.
Sensitive data filtering
Some error data will be too sensitive to transmit to an external service, such as credit card details or passwords. Since this data is very application specific, Raygun doesn't filter out anything by default. You can configure to either replace or otherwise transform specific values based on their keys. These transformations apply to form data ($_POST
), custom user data, HTTP headers, and environment data ($_SERVER
). It does not filter the URL or its $_GET
parameters, or custom message strings. Since Raygun doesn't log method arguments in stack traces, those don't need filtering. All key comparisons are case insensitive.
<?php
$raygunClient->setFilterParams(array(
'password' => true,
'creditcardnumber' => true,
'ccv' => true,
'php_auth_pw' => true, // filters basic auth from $_SERVER
));
// Example input: array('Username' => 'myuser','Password' => 'secret')
// Example output: array('Username' => 'myuser','Password' => '[filtered]')
You can also define keys as regular expressions:
<?php
$raygunClient->setFilterParams(array(
'/^credit/i' => true,
));
// Example input: array('CreditCardNumber' => '4111111111111111','CreditCardCcv' => '123')
// Example output: array('CreditCardNumber' => '[filtered]','CreditCardCcv' => '[filtered]')
In case you want to retain some hints on the data rather than removing it completely, you can also apply custom transformations through PHP's anonymous functions. The following example truncates all keys starting with "Email".
<?php
$raygunClient->setFilterParams(array(
'Email' => function($key, $val) {return substr($val, 0, 5) . '...';}
));
// Example input: array('Email' => 'test@test.com')
// Example output: array('Email' => 'test@...')
Note that when any filters are defined, the Raygun error will no longer contain the raw HTTP data, since there's no effective way to filter it.
Sample apps
For more detailed examples, and to see how Raygun works before integrating it into your code, download the sample apps available in the Raygun4PHP repository.
The provider is open source and available at the Raygun4PHP repository.