Skip to content
Snippets Groups Projects
Commit 7b286d62 authored by lechuck's avatar lechuck Committed by lechuck
Browse files

Added plugin for Sentry integration https://github.com/ryanbagwell/wordpress-sentry

parent 17d2edb7
Branches
Tags
No related merge requests found
Showing
with 1325 additions and 0 deletions
wordpress-sentry
================
A WordpRess plugin to handle reporting php error to Django's Sentry
\ No newline at end of file
<?php
require_once( dirname(__FILE__).'/raven/lib/Raven/Client.php' );
require_once( dirname(__FILE__).'/raven/lib/Raven/Compat.php' );
require_once( dirname(__FILE__).'/raven/lib/Raven/ErrorHandler.php' );
require_once( dirname(__FILE__).'/raven/lib/Raven/Stacktrace.php' );
class WP_Raven_Client extends Raven_Client {
function __construct() {
$this->settings = get_option( 'sentry-settings' );
if ( !isset( $this->settings['dsn'] )) return;
if ( $this->settings['dsn'] == '' ) return;
parent::__construct( $this->settings['dsn'] );
$this->setErrorReportingLevel( $this->settings['reporting_level'] );
$this->setHandlers();
}
function setHandlers() {
$error_handler = new Raven_ErrorHandler( $this );
set_error_handler( array( $error_handler, 'handleError' ));
set_exception_handler( array( $error_handler, 'handleException' ));
}
function setErrorReportingLevel( $level = 'E_WARNING' ) {
$errorLevelMap = array(
'E_NONE' => 0,
'E_WARNING' => 2,
'E_NOTICE' => 8,
'E_USER_ERROR' => 256,
'E_USER_WARNING' => 512,
'E_USER_NOTICE' => 1024,
'E_RECOVERABLE_ERROR' => 4096,
'E_ALL' => 8191
);
if ( array_key_exists( $level, $errorLevelMap ) )
$this->_max_error_reporting_level = $errorLevelMap[ $level ];
}
}
?>
\ No newline at end of file
<div class="wrap">
<h2>Sentry Error Reporting Settings</h2>
<form action="" method="post">
<table class="form-table">
<tbody>
<tr valign="top">
<th scope="row">
<label for="sentry_dsn">Sentry DSN</label>
</th>
<td>
<input name="sentry_dsn" type="text" id="sentry-dsn" value="<?php echo $dsn; ?>" class="regular-text">
</td>
</tr>
<tr valign="top">
<th scope="row">
<label for="sentry_dsn">Error Reporting Level</label>
</th>
<td>
<select name="sentry_reporting_level">
<option value="E_NONE" <?php echo ($reporting_level == 'E_NONE') ? 'selected="selected"' : '';?>>None</option>
<option value="E_WARNING" <?php echo ($reporting_level == 'E_WARNING') ? 'selected="selected"' : '';?>>Warnings</option>
<option value="E_NOTICE" <?php echo ($reporting_level == 'E_NOTICE') ? 'selected="selected"' : '';?>>Notices</option>
<option value="E_USER_ERROR" <?php echo ($reporting_level == 'E_USER_ERROR') ? 'selected="selected"' : '';?>>User Errors</option>
<option value="E_USER_WARNING" <?php echo ($reporting_level == 'E_USER_WARNING') ? 'selected="selected"' : '';?>>User Warnings</option>
<option value="E_USER_NOTICE" <?php echo ($reporting_level == 'E_USER_NOTICE') ? 'selected="selected"' : '';?>>User Notices</option>
<option value="E_RECOVERABLE_ERROR" <?php echo ($reporting_level == 'E_RECOVERABLE_ERROR') ? 'selected="selected"' : '';?>>Recoverable Errors</option>
<option value="E_ALL" <?php echo ($reporting_level == 'E_ALL') ? 'selected="selected"' : '';?>>All Errors</option>
</select>
("User Notices" is recommended)
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input type="submit" name="submit" id="submit" class="button-primary" value="Save Changes">
</p>
</form>
</div>
\ No newline at end of file
*.lock
package.xml
/vendor
\ No newline at end of file
language: php
php:
- 5.2
- 5.3
- 5.4
notifications:
irc:
channels: "irc.freenode.org#sentry"
on_success: change
on_failure: change
\ No newline at end of file
The Raven PHP client was originally written by Michael van Tellingen
and is maintained by the Sentry Team.
http://github.com/getsentry/raven-php/contributors
\ No newline at end of file
Copyright (c) 2012 Sentry Team and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the Raven nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
raven-php
=========
.. image:: https://secure.travis-ci.org/getsentry/raven-php.png?branch=master
:target: http://travis-ci.org/getsentry/raven-php
raven-php is an experimental PHP client for `Sentry <http://aboutsentry.com/>`_.
::
// Instantiate a new client with a compatible DSN
$client = new Raven_Client('http://public:secret@example.com/1');
// Capture a message
$event_id = $client->getIdent($client->captureMessage('my log message'));
// Capture an exception
$event_id = $client->getIdent($client->captureException($ex));
// Give the user feedback
echo "Sorry, there was an error!";
echo "Your reference ID is " . $event_id;
// Install error handlers
$error_handler = new Raven_ErrorHandler($client);
$error_handler->registerExceptionHandler();
$error_handler->registerErrorHandler();
Installation
------------
Install with Composer
~~~~~~~~~~~~~~~~~~~~~
If you're using `Composer <https://github.com/composer/composer>`_ to manage
dependencies, you can add Raven with it.
::
{
"require": {
"raven/raven": ">=0.2.0"
}
}
or to get the latest version off the master branch:
::
{
"require": {
"raven/raven": "dev-master"
}
}
Install source from GitHub
~~~~~~~~~~~~~~~~~~~~~~~~~~
To install the source code:
::
$ git clone git://github.com/getsentry/raven-php.git
And include it in your scripts:
::
require_once '/path/to/Raven/library/Raven.php';
Or, alternatively use the autoloader:
::
require_once '/path/to/Raven/library/Raven/Autoloader.php';
Raven_Autoloader::register();
Or, if you're using `Composer <https://github.com/composer/composer>`_:
::
require_once 'vendor/autoload.php';
Resources
---------
* `Bug Tracker <http://github.com/getsentry/raven-php/issues>`_
* `Code <http://github.com/getsentry/raven-php>`_
* `Mailing List <https://groups.google.com/group/getsentry>`_
* `IRC <irc://irc.freenode.net/sentry>`_ (irc.freenode.net, #sentry)
{
"name": "raven/raven",
"type": "library",
"description": "A PHP client for Sentry (http://getsentry.com)",
"keywords": ["log", "logging"],
"homepage": "http://getsentry.com",
"version": "0.2.0",
"license": "Apache License 2",
"authors": [
{
"name": "Michael van Tellingen",
"email": ""
},
{
"name": "David Cramer",
"email": "dcramer@gmail.com"
}
],
"require": {
"php": ">=5.2.4"
},
"autoload": {
"psr-0" : {
"Raven_" : "lib/"
}
}
}
\ No newline at end of file
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Autoloads Raven classes.
*
* @package raven
*/
class Raven_Autoloader
{
/**
* Registers Raven_Autoloader as an SPL autoloader.
*/
static public function register()
{
ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array(new self, 'autoload'));
}
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*
* @return boolean Returns true if the class has been loaded
*/
static public function autoload($class)
{
if (0 !== strpos($class, 'Raven')) {
return;
}
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
require $file;
}
}
}
\ No newline at end of file
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Raven PHP Client
*
* @package raven
*/
class Raven_Client
{
const DEBUG = 10;
const INFO = 20;
const WARN = 30;
const WARNING = 30;
const ERROR = 40;
function __construct($options_or_dsn=null, $options=array())
{
if (is_null($options_or_dsn)) {
// Read from environment
$options_or_dsn = $_SERVER['SENTRY_DSN'];
}
if (!is_array($options_or_dsn)) {
// Must be a valid DSN
$options_or_dsn = self::parseDSN($options_or_dsn);
}
$options = array_merge($options_or_dsn, $options);
$this->servers = (!empty($options['servers']) ? $options['servers'] : null);
$this->secret_key = (!empty($options['secret_key']) ? $options['secret_key'] : null);
$this->public_key = (!empty($options['public_key']) ? $options['public_key'] : null);
$this->project = (isset($options['project']) ? $options['project'] : 1);
$this->auto_log_stacks = (isset($options['auto_log_stacks']) ? $options['auto_log_stacks'] : false);
$this->name = (!empty($options['name']) ? $options['name'] : Raven_Compat::gethostname());
$this->site = (!empty($options['site']) ? $options['site'] : $this->_server_variable('SERVER_NAME'));
$this->_lasterror = null;
}
/**
* Parses a Raven-compatible DSN and returns an array of its values.
*/
public static function parseDSN($dsn)
{
$url = parse_url($dsn);
$scheme = (isset($url['scheme']) ? $url['scheme'] : '');
if (!in_array($scheme, array('http', 'https', 'udp'))) {
throw new InvalidArgumentException('Unsupported Sentry DSN scheme: ' . $scheme);
}
$netloc = (isset($url['host']) ? $url['host'] : null);
$netloc.= (isset($url['port']) ? ':'.$url['port'] : null);
$rawpath = (isset($url['path']) ? $url['path'] : null);
if ($rawpath) {
$pos = strrpos($rawpath, '/', 1);
if ($pos !== false) {
$path = substr($rawpath, 0, $pos);
$project = substr($rawpath, $pos + 1);
}
else {
$path = '';
$project = substr($rawpath, 1);
}
}
else {
$project = null;
$path = '';
}
$username = (isset($url['user']) ? $url['user'] : null);
$password = (isset($url['pass']) ? $url['pass'] : null);
if (empty($netloc) || empty($project) || empty($username) || empty($password)) {
throw new InvalidArgumentException('Invalid Sentry DSN: ' . $dsn);
}
return array(
'servers' => array(sprintf('%s://%s%s/api/store/', $scheme, $netloc, $path)),
'project' => $project,
'public_key' => $username,
'secret_key' => $password,
);
}
/**
* Given an identifier, returns a Sentry searchable string.
*/
public function getIdent($ident)
{
// XXX: We dont calculate checksums yet, so we only have the ident.
return $ident;
}
/**
* Deprecated
*/
public function message($message, $params=array(), $level=self::INFO,
$stack=false)
{
return $this->captureMessage($message, $params, $level, $stack);
}
/**
* Deprecated
*/
public function exception($exception)
{
return $this->captureException($exception);
}
/**
* Log a message to sentry
*/
public function captureMessage($message, $params=array(), $level=self::INFO,
$stack=false)
{
$data = array(
'message' => vsprintf($message, $params),
'level' => $level,
'sentry.interfaces.Message' => array(
'message' => $message,
'params' => $params,
)
);
return $this->capture($data, $stack);
}
/**
* Log an exception to sentry
*/
public function captureException($exception, $culprit=null, $logger=null)
{
$exc_message = $exception->getMessage();
if (empty($exc_message)) {
$exc_message = '<unknown exception>';
}
$data = array(
'message' => $exc_message
);
$data['sentry.interfaces.Exception'] = array(
'value' => $exc_message,
'type' => $exception->getCode(),
'module' => $exception->getFile() .':'. $exception->getLine(),
);
if ($culprit){
$data["culprit"] = $culprit;
}
if ($logger){
$data["logger"] = $logger;
}
/**'sentry.interfaces.Exception'
* Exception::getTrace doesn't store the point at where the exception
* was thrown, so we have to stuff it in ourselves. Ugh.
*/
$trace = $exception->getTrace();
$frame_where_exception_thrown = array(
'file' => $exception->getFile(),
'line' => $exception->getLine(),
);
array_unshift($trace, $frame_where_exception_thrown);
return $this->capture($data, $trace);
}
public function capture($data, $stack)
{
$event_id = $this->uuid4();
if (!isset($data['timestamp'])) $data['timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
if (!isset($data['level'])) $data['level'] = self::ERROR;
// The function getallheaders() is only available when running in a
// web-request. The function is missing when run from the commandline..
$headers = array();
if (function_exists('getallheaders')) {
$headers = getallheaders();
}
$data = array_merge($data, array(
'server_name' => $this->name,
'event_id' => $event_id,
'project' => $this->project,
'site' => $this->site,
'sentry.interfaces.Http' => array(
'method' => $this->_server_variable('REQUEST_METHOD'),
'url' => $this->get_current_url(),
'query_string' => $this->_server_variable('QUERY_STRNG'),
'data' => $_POST,
'cookies' => $_COOKIE,
'headers' => $headers,
'env' => $_SERVER,
)
));
if ((!$stack && $this->auto_log_stacks) || $stack === True) {
$stack = debug_backtrace();
// Drop last stack
array_shift($stack);
}
/**
* PHP's way of storing backstacks seems bass-ackwards to me
* 'function' is not the function you're in; it's any function being
* called, so we have to shift 'function' down by 1. Ugh.
*/
for ($i = 0; $i < count($stack) - 1; $i++) {
$stack[$i]['function'] = $stack[$i + 1]['function'];
}
$stack[count($stack) - 1]['function'] = null;
if ($stack && !isset($data['sentry.interfaces.Stacktrace'])) {
$data['sentry.interfaces.Stacktrace'] = array(
'frames' => Raven_Stacktrace::get_stack_info($stack)
);
}
if (function_exists('mb_convert_encoding')) {
$data = $this->remove_invalid_utf8($data);
}
$this->send($data);
return $event_id;
}
public function send($data)
{
$message = base64_encode(gzcompress(Raven_Compat::json_encode($data)));
foreach($this->servers as $url) {
$timestamp = microtime(true);
$signature = $this->get_signature(
$message, $timestamp, $this->secret_key);
$headers = array(
'X-Sentry-Auth' => $this->get_auth_header(
$signature, $timestamp, 'raven-php/0.1', $this->public_key),
'Content-Type' => 'application/octet-stream'
);
$this->send_remote($url, $message, $headers);
}
}
private function send_remote($url, $data, $headers=array())
{
$parts = parse_url($url);
$parts['netloc'] = $parts['host'].(isset($parts['port']) ? ':'.$parts['port'] : null);
if ($parts['scheme'] === 'udp')
return $this->send_udp($parts['netloc'], $data, $headers['X-Sentry-Auth']);
return $this->send_http($url, $data, $headers);
}
private function send_udp($netloc, $data, $headers)
{
list($host, $port) = explode(':', $netloc);
$raw_data = $headers."\n\n".$data;
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_sendto($sock, $raw_data, strlen($raw_data), 0, $host, $port);
socket_close($sock);
return true;
}
/**
* Send the message over http to the sentry url given
*/
private function send_http($url, $data, $headers=array())
{
$new_headers = array();
foreach($headers as $key => $value) {
array_push($new_headers, $key .': '. $value);
}
$parts = parse_url($url);
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, $new_headers);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_VERBOSE, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$ret = curl_exec($curl);
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$success = ($code == 200);
curl_close($curl);
if (!$success) {
// It'd be nice just to raise an exception here, but it's not very PHP-like
$this->_lasterror = $ret;
}
return $success;
}
/**
* Create a signature
*/
private function get_signature($message, $timestamp, $key)
{
return Raven_Compat::hash_hmac('sha1', sprintf('%F', $timestamp) .' '. $message, $key);
}
private function get_auth_header($signature, $timestamp, $client,
$api_key=null)
{
$header = array(
sprintf("sentry_timestamp=%F", $timestamp),
"sentry_signature={$signature}",
"sentry_client={$client}",
"sentry_version=2.0",
);
if ($api_key) {
array_push($header, "sentry_key={$api_key}");
}
return sprintf('Sentry %s', implode(', ', $header));
}
/**
* Generate an uuid4 value
*/
private function uuid4()
{
$uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
// 16 bits for "time_mid"
mt_rand( 0, 0xffff ),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand( 0, 0x0fff ) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand( 0, 0x3fff ) | 0x8000,
// 48 bits for "node"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
return str_replace('-', '', $uuid);
}
/**
* Return the URL for the current request
*/
private function get_current_url()
{
// When running from commandline the REQUEST_URI is missing.
if ($this->_server_variable('REQUEST_URI') === '') {
return '';
}
$schema = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'
|| $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
return $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
private function _server_variable($key)
{
if (isset($_SERVER[$key])) {
return $_SERVER[$key];
}
return '';
}
private function remove_invalid_utf8($data)
{
foreach ($data as $key => $value) {
if (is_string($key)) {
$key = mb_convert_encoding($key, 'UTF-8', 'UTF-8');
}
if (is_string($value)) {
$value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
}
if (is_array($value)) {
$value = $this->remove_invalid_utf8($value);
}
$data[$key] = $value;
}
return $data;
}
}
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Raven_Compat
{
public static function gethostname()
{
if (function_exists('gethostname')) {
return gethostname();
}
return self::_gethostname();
}
public static function _gethostname()
{
return php_uname('n');
}
public static function hash_hmac($algo, $data, $key, $raw_output=false)
{
if (function_exists('hash_hmac')) {
return hash_hmac($algo, $data, $key, $raw_output);
}
return self::_hash_hmac($algo, $data, $key, $raw_output);
}
/**
* Implementation from 'KC Cloyd'.
* See http://nl2.php.net/manual/en/function.hash-hmac.php
*/
public static function _hash_hmac($algo, $data, $key, $raw_output=false)
{
$algo = strtolower($algo);
$pack = 'H'.strlen($algo('test'));
$size = 64;
$opad = str_repeat(chr(0x5C), $size);
$ipad = str_repeat(chr(0x36), $size);
if (strlen($key) > $size) {
$key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
} else {
$key = str_pad($key, $size, chr(0x00));
}
for ($i = 0; $i < strlen($key) - 1; $i++) {
$opad[$i] = $opad[$i] ^ $key[$i];
$ipad[$i] = $ipad[$i] ^ $key[$i];
}
$output = $algo($opad.pack($pack, $algo($ipad.$data)));
return ($raw_output) ? pack($pack, $output) : $output;
}
/**
* Note that we discard the options given to be compatible
* with PHP < 5.3
*/
public static function json_encode($value, $options=0)
{
if (function_exists('json_encode')) {
return json_encode($value);
}
return self::_json_encode($value);
}
/**
* Implementation taken from
* http://www.mike-griffiths.co.uk/php-json_encode-alternative/
*/
public static function _json_encode($value)
{
static $jsonReplaces = array(
array('\\', '/', "\n", "\t", "\r", "\b", "\f", '"'),
array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
if (is_null($value)) {
return 'null';
}
if ($value === false) {
return 'false';
}
if ($value === true) {
return 'true';
}
if (is_scalar($value)) {
// Always use '.' for floats.
if (is_float($value)) {
return floatval(str_replace(',', '.', strval($value)));
}
if (is_string($value)) {
return sprintf('"%s"',
str_replace($jsonReplaces[0], $jsonReplaces[1], $value));
}
else {
return $value;
}
}
$isList = true;
for ($i = 0, reset($value); true; $i++) {
if (key($value) !== $i) {
$isList = false;
break;
}
}
$result = array();
if ($isList) {
foreach ($value as $v) {
$result[] = self::_json_encode($v);
}
return '[' . join(',', $result) . ']';
}
else {
foreach ($value as $k => $v) {
$result[] = self::_json_encode($k) . ':' . self::_json_encode($v);
}
return '{' . join(',', $result) . '}';
}
}
}
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Event handlers for exceptions and errors
*
* $client = new Raven_Client('http://public:secret/example.com/1');
* $error_handler = new Raven_ErrorHandler($client);
* $error_handler->registerExceptionHandler();
* $error_handler->registerErrorHandler();
*
* @package raven
*/
class Raven_ErrorHandler
{
private $max_error_reporting_level = 2;
function __construct($client) {
$this->client = $client;
if ( $client->_max_error_reporting_level )
$this->max_error_reporting_level = $client->_max_error_reporting_level;
}
function handleException($e, $isError = false) {
$e->event_id = $this->client->getIdent($this->client->captureException($e));
if (!$isError && $this->call_existing_exception_handler && $this->old_exception_handler) {
call_user_func($this->old_exception_handler, $e);
}
}
function handleError($code, $message, $file='', $line=0, $context=array()) {
if ( $code >= $this->max_error_reporting_level )
return;
$e = new ErrorException($message, 0, $code, $file, $line);
$this->handleException($e, $isError = true);
if ($this->call_existing_error_handler && $this->old_error_handler) {
call_user_func($this->old_error_handler, $code, $message, $file, $line, $context);
}
}
function registerExceptionHandler($call_existing_exception_handler = true)
{
$this->old_exception_handler = set_exception_handler(array($this, 'handleException'));
$this->call_existing_exception_handler = $call_existing_exception_handler;
}
function registerErrorHandler($call_existing_error_handler = true, $error_types = E_ALL)
{
$this->old_error_handler = set_error_handler(array($this, 'handleError'), $error_types);
$this->call_existing_error_handler = $call_existing_error_handler;
}
private $old_exception_handler = null;
private $call_existing_exception_handler = false;
private $old_error_handler = null;
private $call_existing_error_handler = false;
}
?>
<?php
/**
* Small helper class to inspect the stacktrace
*
* @package raven
*/
class Raven_Stacktrace
{
public static function get_stack_info($stack)
{
$result = array();
foreach($stack as $frame) {
if (!isset($frame['file'])) {
$args = (is_array($frame['args']) ? implode(',', $frame['args']) : $frame['args']);
if (isset($frame['class'])) {
$context['line'] = sprintf('%s%s%s(%s)',
$frame['class'], $frame['type'], $frame['function'],
$args);
}
else {
$context['line'] = sprintf('%s(%s)', $frame['function'], $args);
}
$abs_path = '';
$context['prefix'] = '';
$context['suffix'] = '';
$context['filename'] = $filename = '[Anonymous function]';
$context['lineno'] = 0;
}
else {
$context = self::read_source_file($frame['file'], $frame['line']);
$abs_path = $frame['file'];
$filename = basename($frame['file']);
}
$module = $filename;
if (isset($frame['class'])) {
$module .= ':' . $frame['class'];
}
array_push($result, array(
'abs_path' => $abs_path,
'filename' => $context['filename'],
'lineno' => $context['lineno'],
'module' => $module,
'function' => $frame['function'],
'vars' => array(),
'pre_context' => $context['prefix'],
'context_line' => $context['line'],
'post_context' => $context['suffix'],
));
}
return array_reverse($result);
}
private static function read_source_file($filename, $lineno)
{
$frame = array(
'prefix' => array(),
'line' => '',
'suffix' => array(),
'filename' => $filename,
'lineno' => $lineno,
);
if ($filename === null || $lineno === null) {
return $frame;
}
// Code which is eval'ed have a modified filename.. Extract the
// correct filename + linenumber from the string.
$matches = array();
$matched = preg_match("/^(.*?)\((\d+)\) : eval\(\)'d code$/",
$filename, $matches);
if ($matched) {
$frame['filename'] = $filename = $matches[1];
$frame['lineno'] = $lineno = $matches[2];
}
// Try to open the file. We wrap this in a try/catch block in case
// someone has modified the error_trigger to throw exceptions.
try {
$fh = fopen($filename, 'r');
if ($fh === false) {
return $frame;
}
}
catch (ErrorException $exc) {
return $frame;
}
$line = false;
$cur_lineno = 0;
while(!feof($fh)) {
$cur_lineno++;
$line = fgets($fh);
if ($cur_lineno == $lineno) {
$frame['line'] = $line;
}
elseif ($lineno - $cur_lineno > 0 && $lineno - $cur_lineno < 3)
{
$frame['prefix'][] = $line;
}
elseif ($lineno - $cur_lineno > -3 && $lineno - $cur_lineno < 0)
{
$frame['suffix'][] = $line;
}
}
fclose($fh);
return $frame;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="test/bootstrap.php"
>
<testsuites>
<testsuite name="Raven Test Suite">
<directory>./test/Raven/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./lib/Raven/</directory>
</whitelist>
</filter>
</phpunit>
\ No newline at end of file
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Raven_Tests_ClientTest extends PHPUnit_Framework_TestCase
{
public function testParseDsnHttp()
{
$result = Raven_Client::parseDsn('http://public:secret@example.com/1');
$this->assertEquals($result['project'], 1);
$this->assertEquals($result['servers'], array('http://example.com/api/store/'));
$this->assertEquals($result['public_key'], 'public');
$this->assertEquals($result['secret_key'], 'secret');
}
public function testParseDsnHttps()
{
$result = Raven_Client::parseDsn('https://public:secret@example.com/1');
$this->assertEquals($result['project'], 1);
$this->assertEquals($result['servers'], array('https://example.com/api/store/'));
$this->assertEquals($result['public_key'], 'public');
$this->assertEquals($result['secret_key'], 'secret');
}
public function testParseDsnPath()
{
$result = Raven_Client::parseDsn('http://public:secret@example.com/app/1');
$this->assertEquals($result['project'], 1);
$this->assertEquals($result['servers'], array('http://example.com/app/api/store/'));
$this->assertEquals($result['public_key'], 'public');
$this->assertEquals($result['secret_key'], 'secret');
}
public function testParseDsnPort()
{
$result = Raven_Client::parseDsn('http://public:secret@example.com:9000/app/1');
$this->assertEquals($result['project'], 1);
$this->assertEquals($result['servers'], array('http://example.com:9000/app/api/store/'));
$this->assertEquals($result['public_key'], 'public');
$this->assertEquals($result['secret_key'], 'secret');
}
public function testParseDsnInvalidScheme()
{
try {
$result = Raven_Client::parseDsn('gopher://public:secret@/1');
$this->fail();
} catch (Exception $e) {
return;
}
}
public function testParseDsnMissingNetloc()
{
try {
$result = Raven_Client::parseDsn('http://public:secret@/1');
$this->fail();
} catch (Exception $e) {
return;
}
}
public function testParseDsnMissingProject()
{
try {
$result = Raven_Client::parseDsn('http://public:secret@example.com');
$this->fail();
} catch (Exception $e) {
return;
}
}
/**
* @expectedException InvalidArgumentException
*/
public function testParseDsnMissingPublicKey()
{
$result = Raven_Client::parseDsn('http://:secret@example.com/1');
}
/**
* @expectedException InvalidArgumentException
*/
public function testParseDsnMissingSecretKey()
{
$result = Raven_Client::parseDsn('http://public@example.com/1');
}
public function testDsnFirstArgument()
{
$client = new Raven_Client('http://public:secret@example.com/1');
$this->assertEquals($client->project, 1);
$this->assertEquals($client->servers, array('http://example.com/api/store/'));
$this->assertEquals($client->public_key, 'public');
$this->assertEquals($client->secret_key, 'secret');
}
public function testDsnFirstArgumentWithOptions()
{
$client = new Raven_Client('http://public:secret@example.com/1', array(
'site' => 'foo',
));
$this->assertEquals($client->project, 1);
$this->assertEquals($client->servers, array('http://example.com/api/store/'));
$this->assertEquals($client->public_key, 'public');
$this->assertEquals($client->secret_key, 'secret');
$this->assertEquals($client->site, 'foo');
}
public function testOptionsFirstArgument()
{
$client = new Raven_Client(array(
'servers' => array('http://example.com/api/store/'),
));
$this->assertEquals($client->servers, array('http://example.com/api/store/'));
}
public function testOptionsFirstArgumentWithOptions()
{
$client = new Raven_Client(array(
'servers' => array('http://example.com/api/store/'),
), array(
'site' => 'foo',
));
$this->assertEquals($client->servers, array('http://example.com/api/store/'));
$this->assertEquals($client->site, 'foo');
}
}
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Raven_Tests_CompatTest extends PHPUnit_Framework_TestCase
{
public function test_gethostname()
{
$this->assertEquals(Raven_Compat::gethostname(), Raven_Compat::_gethostname());
$this->assertTrue(strlen(Raven_Compat::_gethostname()) > 0);
}
public function test_hash_hmac()
{
$result = Raven_Compat::hash_hmac('sha1', 'foo', 'bar');
$this->assertEquals($result, '85d155c55ed286a300bd1cf124de08d87e914f3a');
$result = Raven_Compat::_hash_hmac('sha1', 'foo', 'bar');
$this->assertEquals($result, '85d155c55ed286a300bd1cf124de08d87e914f3a');
}
public function test_json_encode()
{
$result = Raven_Compat::json_encode(array('foo' => array('bar' => 1)));
$this->assertEquals($result, '{"foo":{"bar":1}}');
$result = Raven_Compat::_json_encode(array('foo' => array('bar' => 1)));
$this->assertEquals($result, '{"foo":{"bar":1}}');
}
}
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Raven_Tests_ErrorHandlerTest extends PHPUnit_Framework_TestCase
{
public function testErrorsAreLoggedAsExceptions()
{
$client = $this->getMock('Client', array('captureException', 'getIdent'));
$client->expects($this->once())
->method('captureException')
->with($this->isInstanceOf('ErrorException'));
$handler = new Raven_ErrorHandler($client);
$handler->handleError(E_WARNING, 'message');
}
public function testExceptionsAreLogged()
{
$client = $this->getMock('Client', array('captureException', 'getIdent'));
$client->expects($this->once())
->method('captureException')
->with($this->isInstanceOf('ErrorException'));
$e = new ErrorException('message', 0, E_WARNING, '', 0);
$handler = new Raven_ErrorHandler($client);
$handler->handleException($e);
}
}
<?php
/*
* This file is part of Raven.
*
* (c) Sentry Team
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
error_reporting(E_ALL | E_STRICT);
require_once dirname(__FILE__).'/../lib/Raven/Autoloader.php';
Raven_Autoloader::register();
\ No newline at end of file
<?php
/*
Plugin Name: WordPress Sentry Client
Plugin URI: http://www.hzdg.com
Description: Sends PHP errors to Django Sentry
Author: Ryan Bagwell
Version: 1
Author URI: http://www.ryanbagwell.com
*/
require_once( dirname(__FILE__).'/class.wp-raven-client.php' );
class WPSentry extends WP_Raven_Client {
function WPSentry() {
add_action( 'admin_menu', array( $this, 'addOptionsPage' ));
if ( is_admin() && $_POST )
$this->saveOptions();
parent::__construct();
}
function addOptionsPage() {
add_options_page('Sentry Error Reporting Settings', 'Sentry', 8, 'sentrysettings', array( $this, 'printOptionsHTML' ));
}
function printOptionsHTML() {
extract( $this->settings );
require_once( dirname(__FILE__).'/optionspage.html.php' );
}
function saveOptions() {
if ( !isset( $_POST[ 'sentry_dsn' ] ) || !isset( $_POST[ 'sentry_reporting_level' ]))
return;
update_option('sentry-settings', array(
'dsn' => $_POST[ 'sentry_dsn' ],
'reporting_level' => $_POST[ 'sentry_reporting_level' ]
));
}
}
add_action('plugins_loaded', create_function(null, '$wps = new WPSentry(); ') );
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment