From 8698d597943753ea4177069bf3c169856ac67f1c Mon Sep 17 00:00:00 2001
From: Kevin Krieger
Date: Tue, 19 Sep 2017 21:31:43 +0200
Subject: [PATCH 1/4] update sentry lib
---
.../Hackathon/LoggerSentry/Model/Sentry.php | 2 +-
lib/sentry/raven/.travis.yml | 30 -
lib/sentry/raven/AUTHORS | 4 -
lib/sentry/raven/CHANGES | 52 -
lib/sentry/raven/README.rst | 273 --
lib/sentry/raven/composer.json | 35 -
lib/sentry/raven/docs/advanced.rst | 58 -
.../raven/docs/integrations/laravel.rst | 66 -
.../raven/docs/integrations/symfony2.rst | 89 -
lib/sentry/raven/docs/usage.rst | 180 --
lib/sentry/raven/lib/Raven/Client.php | 915 -------
lib/sentry/raven/lib/Raven/ErrorHandler.php | 178 --
lib/sentry/raven/lib/Raven/Processor.php | 20 -
.../raven/lib/Raven/SanitizeDataProcessor.php | 119 -
lib/sentry/raven/lib/Raven/Serializer.php | 77 -
.../raven/test/Raven/Tests/ClientTest.php | 635 -----
.../raven/test/Raven/Tests/CompatTest.php | 46 -
.../test/Raven/Tests/ErrorHandlerTest.php | 87 -
.../raven/test/Raven/Tests/SerializerTest.php | 48 -
.../raven/test/Raven/Tests/StacktraceTest.php | 262 --
.../raven/test/Raven/Tests/resources/b.php | 3 -
lib/sentry/sentry/.gitattributes | 3 +
lib/sentry/{raven => sentry}/.gitignore | 1 +
lib/sentry/{raven => sentry}/.gitmodules | 0
lib/sentry/{raven => sentry}/.php_cs | 0
lib/sentry/sentry/.scrutinizer.yml | 19 +
lib/sentry/sentry/.travis.yml | 47 +
lib/sentry/sentry/AUTHORS | 4 +
lib/sentry/sentry/CHANGELOG.md | 177 ++
lib/sentry/{raven => sentry}/LICENSE | 4 +-
lib/sentry/{raven => sentry}/Makefile | 8 +-
lib/sentry/sentry/README.md | 162 ++
.../{raven/bin/raven => sentry/bin/sentry} | 10 +-
lib/sentry/sentry/composer.json | 60 +
lib/sentry/{raven => sentry}/docs/Makefile | 0
lib/sentry/{raven => sentry}/docs/conf.py | 14 +-
lib/sentry/{raven => sentry}/docs/config.rst | 129 +-
lib/sentry/{raven => sentry}/docs/index.rst | 21 +-
.../docs/integrations/index.rst | 0
.../sentry/docs/integrations/laravel.rst | 315 +++
.../docs/integrations/monolog.rst | 20 +-
.../sentry/docs/integrations/symfony2.rst | 42 +
lib/sentry/{raven => sentry}/docs/make.bat | 0
lib/sentry/sentry/docs/sentry-doc-config.json | 42 +
lib/sentry/sentry/docs/usage.rst | 311 +++
lib/sentry/sentry/examples/vanilla/README.md | 6 +
lib/sentry/sentry/examples/vanilla/index.php | 39 +
.../lib/Raven/Autoloader.php | 6 +-
lib/sentry/sentry/lib/Raven/Breadcrumbs.php | 76 +
.../lib/Raven/Breadcrumbs/ErrorHandler.php | 45 +
.../lib/Raven/Breadcrumbs/MonologHandler.php | 101 +
lib/sentry/sentry/lib/Raven/Client.php | 1438 +++++++++++
.../{raven => sentry}/lib/Raven/Compat.php | 69 +-
.../{raven => sentry}/lib/Raven/Context.php | 13 +
.../lib/Raven/CurlHandler.php | 22 +-
lib/sentry/sentry/lib/Raven/ErrorHandler.php | 195 ++
lib/sentry/sentry/lib/Raven/Exception.php | 4 +
lib/sentry/sentry/lib/Raven/Processor.php | 45 +
.../Processor/RemoveCookiesProcessor.php | 35 +
.../Processor/RemoveHttpBodyProcessor.php | 30 +
.../Raven/Processor/SanitizeDataProcessor.php | 160 ++
.../SanitizeHttpHeadersProcessor.php | 64 +
.../Processor/SanitizeStacktraceProcessor.php | 39 +
.../sentry/lib/Raven/ReprSerializer.php | 41 +
.../lib/Raven/SanitizeDataProcessor.php | 19 +
lib/sentry/sentry/lib/Raven/Serializer.php | 144 ++
.../lib/Raven/Stacktrace.php | 186 +-
.../sentry/lib/Raven/TransactionStack.php | 54 +
.../{raven => sentry}/lib/Raven/Util.php | 7 +-
.../lib/Raven/data/cacert.pem | 0
lib/sentry/{raven => sentry}/phpunit.xml | 3 +-
.../Tests/Breadcrumbs/ErrorHandlerTest.php | 29 +
.../Raven/Tests/Breadcrumbs/MonologTest.php | 72 +
.../test/Raven/Tests/BreadcrumbsTest.php | 38 +
.../sentry/test/Raven/Tests/ClientTest.php | 2226 +++++++++++++++++
.../sentry/test/Raven/Tests/CompatTest.php | 113 +
.../test/Raven/Tests/ErrorHandlerTest.php | 246 ++
.../test/Raven/Tests/IntegrationTest.php | 69 +
.../Processor/RemoveCookiesProcessorTest.php | 78 +
.../Processor/RemoveHttpBodyProcessorTest.php | 121 +
.../Processor}/SanitizeDataProcessorTest.php | 119 +-
.../SanitizeHttpHeadersProcessorTest.php | 83 +
.../SanitizeStacktraceProcessorTest.php | 113 +
.../test/Raven/Tests/ReprSerializerTest.php | 112 +
.../test/Raven/Tests/SerializerTest.php | 147 ++
.../test/Raven/Tests/StacktraceTest.php | 248 ++
.../test/Raven/Tests/TransactionStackTest.php | 35 +
.../test/Raven/Tests/UtilTest.php | 0
.../test/Raven/Tests/resources/a.php | 2 -
.../sentry/test/Raven/Tests/resources/b.php | 2 +
.../captureExceptionInLatin1File.php | 4 +
.../{raven => sentry}/test/bootstrap.php | 0
lib/sentry/sentry/test/data/binary | Bin 0 -> 128 bytes
93 files changed, 7921 insertions(+), 3345 deletions(-)
delete mode 100644 lib/sentry/raven/.travis.yml
delete mode 100644 lib/sentry/raven/AUTHORS
delete mode 100644 lib/sentry/raven/CHANGES
delete mode 100644 lib/sentry/raven/README.rst
delete mode 100644 lib/sentry/raven/composer.json
delete mode 100644 lib/sentry/raven/docs/advanced.rst
delete mode 100644 lib/sentry/raven/docs/integrations/laravel.rst
delete mode 100644 lib/sentry/raven/docs/integrations/symfony2.rst
delete mode 100644 lib/sentry/raven/docs/usage.rst
delete mode 100644 lib/sentry/raven/lib/Raven/Client.php
delete mode 100644 lib/sentry/raven/lib/Raven/ErrorHandler.php
delete mode 100644 lib/sentry/raven/lib/Raven/Processor.php
delete mode 100644 lib/sentry/raven/lib/Raven/SanitizeDataProcessor.php
delete mode 100644 lib/sentry/raven/lib/Raven/Serializer.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/ClientTest.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/CompatTest.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/ErrorHandlerTest.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/SerializerTest.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/StacktraceTest.php
delete mode 100644 lib/sentry/raven/test/Raven/Tests/resources/b.php
create mode 100644 lib/sentry/sentry/.gitattributes
rename lib/sentry/{raven => sentry}/.gitignore (78%)
rename lib/sentry/{raven => sentry}/.gitmodules (100%)
rename lib/sentry/{raven => sentry}/.php_cs (100%)
create mode 100644 lib/sentry/sentry/.scrutinizer.yml
create mode 100644 lib/sentry/sentry/.travis.yml
create mode 100644 lib/sentry/sentry/AUTHORS
create mode 100644 lib/sentry/sentry/CHANGELOG.md
rename lib/sentry/{raven => sentry}/LICENSE (83%)
rename lib/sentry/{raven => sentry}/Makefile (73%)
create mode 100644 lib/sentry/sentry/README.md
rename lib/sentry/{raven/bin/raven => sentry/bin/sentry} (89%)
create mode 100644 lib/sentry/sentry/composer.json
rename lib/sentry/{raven => sentry}/docs/Makefile (100%)
rename lib/sentry/{raven => sentry}/docs/conf.py (95%)
rename lib/sentry/{raven => sentry}/docs/config.rst (56%)
rename lib/sentry/{raven => sentry}/docs/index.rst (77%)
rename lib/sentry/{raven => sentry}/docs/integrations/index.rst (100%)
create mode 100644 lib/sentry/sentry/docs/integrations/laravel.rst
rename lib/sentry/{raven => sentry}/docs/integrations/monolog.rst (69%)
create mode 100644 lib/sentry/sentry/docs/integrations/symfony2.rst
rename lib/sentry/{raven => sentry}/docs/make.bat (100%)
create mode 100644 lib/sentry/sentry/docs/sentry-doc-config.json
create mode 100644 lib/sentry/sentry/docs/usage.rst
create mode 100644 lib/sentry/sentry/examples/vanilla/README.md
create mode 100644 lib/sentry/sentry/examples/vanilla/index.php
rename lib/sentry/{raven => sentry}/lib/Raven/Autoloader.php (76%)
create mode 100644 lib/sentry/sentry/lib/Raven/Breadcrumbs.php
create mode 100644 lib/sentry/sentry/lib/Raven/Breadcrumbs/ErrorHandler.php
create mode 100644 lib/sentry/sentry/lib/Raven/Breadcrumbs/MonologHandler.php
create mode 100644 lib/sentry/sentry/lib/Raven/Client.php
rename lib/sentry/{raven => sentry}/lib/Raven/Compat.php (57%)
rename lib/sentry/{raven => sentry}/lib/Raven/Context.php (68%)
rename lib/sentry/{raven => sentry}/lib/Raven/CurlHandler.php (84%)
create mode 100644 lib/sentry/sentry/lib/Raven/ErrorHandler.php
create mode 100644 lib/sentry/sentry/lib/Raven/Exception.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor/RemoveCookiesProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor/RemoveHttpBodyProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor/SanitizeDataProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor/SanitizeHttpHeadersProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Processor/SanitizeStacktraceProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/ReprSerializer.php
create mode 100644 lib/sentry/sentry/lib/Raven/SanitizeDataProcessor.php
create mode 100644 lib/sentry/sentry/lib/Raven/Serializer.php
rename lib/sentry/{raven => sentry}/lib/Raven/Stacktrace.php (52%)
create mode 100644 lib/sentry/sentry/lib/Raven/TransactionStack.php
rename lib/sentry/{raven => sentry}/lib/Raven/Util.php (75%)
rename lib/sentry/{raven => sentry}/lib/Raven/data/cacert.pem (100%)
rename lib/sentry/{raven => sentry}/phpunit.xml (89%)
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Breadcrumbs/ErrorHandlerTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Breadcrumbs/MonologTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/BreadcrumbsTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/ClientTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/CompatTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/ErrorHandlerTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/IntegrationTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Processor/RemoveCookiesProcessorTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Processor/RemoveHttpBodyProcessorTest.php
rename lib/sentry/{raven/test/Raven/Tests => sentry/test/Raven/Tests/Processor}/SanitizeDataProcessorTest.php (52%)
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeHttpHeadersProcessorTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeStacktraceProcessorTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/ReprSerializerTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/SerializerTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/StacktraceTest.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/TransactionStackTest.php
rename lib/sentry/{raven => sentry}/test/Raven/Tests/UtilTest.php (100%)
rename lib/sentry/{raven => sentry}/test/Raven/Tests/resources/a.php (82%)
create mode 100644 lib/sentry/sentry/test/Raven/Tests/resources/b.php
create mode 100644 lib/sentry/sentry/test/Raven/Tests/resources/captureExceptionInLatin1File.php
rename lib/sentry/{raven => sentry}/test/bootstrap.php (100%)
create mode 100644 lib/sentry/sentry/test/data/binary
diff --git a/app/code/community/Hackathon/LoggerSentry/Model/Sentry.php b/app/code/community/Hackathon/LoggerSentry/Model/Sentry.php
index 47f6fa2..eb38469 100644
--- a/app/code/community/Hackathon/LoggerSentry/Model/Sentry.php
+++ b/app/code/community/Hackathon/LoggerSentry/Model/Sentry.php
@@ -1,6 +1,6 @@
`_.
-
-.. code-block:: php
-
- // 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'));
- if ($client->getLastError() !== null) {
- printf('There was an error sending the event to Sentry: %s', $client->getLastError());
- }
-
- // Capture an exception
- $event_id = $client->getIdent($client->captureException($ex));
-
- // Provide some additional data with an exception
- $event_id = $client->getIdent($client->captureException($ex, array(
- 'extra' => array(
- 'php_version' => phpversion()
- ),
- )));
-
- // Give the user feedback
- echo "Sorry, there was an error!";
- echo "Your reference ID is " . $event_id;
-
- // Install error handlers and shutdown function to catch fatal errors
- $error_handler = new Raven_ErrorHandler($client);
- $error_handler->registerExceptionHandler();
- $error_handler->registerErrorHandler();
- $error_handler->registerShutdownFunction();
-
-Installation
-------------
-
-Install with Composer
-~~~~~~~~~~~~~~~~~~~~~
-
-If you're using `Composer `_ to manage
-dependencies, you can add Raven with it.
-
-::
-
- $ composer require raven/raven:$VERSION
-
-(replace ``$VERSION`` with one of the available versions on `Packagist `_)
-or to get the latest version off the master branch:
-
-::
-
- $ composer require raven/raven:dev-master
-
-Note that using unstable versions is not recommended and should be avoided. Also
-you should define a maximum version, e.g. by doing ``>=0.6,<1.0`` or ``~0.6``.
-
-Alternatively, use the ``^`` operator for specifying a version, e.g.,
-
-::
-
- $ composer require raven/raven:^0.11.0
-
-Composer will take care of the autoloading for you, so if you require the
-``vendor/autoload.php``, you're good to go.
-
-
-Install source from GitHub
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To install the source code:
-
-::
-
- $ git clone git://github.com/getsentry/raven-php.git
-
-And including it using the autoloader:
-
-.. code-block:: php
-
- require_once '/path/to/Raven/library/Raven/Autoloader.php';
- Raven_Autoloader::register();
-
-Testing Your Connection
------------------------
-
-The PHP client includes a simple helper script to test your connection and credentials with
-the Sentry master server:
-
-.. code-block:: bash
-
- $ bin/raven test https://public:secret@app.getsentry.com/1
- Client configuration:
- -> server: [https://sentry.example.com/api/store/]
- -> project: 1
- -> public_key: public
- -> secret_key: secret
-
- Sending a test event:
- -> event ID: f1765c9aed4f4ceebe5a93df9eb2d34f
-
- Done!
-
-.. note:: The CLI enforces the synchronous option on HTTP requests whereas the default configuration is asyncrhonous.
-
-Configuration
--------------
-
-Several options exist that allow you to configure the behavior of the ``Raven_Client``. These are passed as the
-second parameter of the constructor, and is expected to be an array of key value pairs:
-
-.. code-block:: php
-
- $client = new Raven_Client($dsn, array(
- 'option_name' => 'value',
- ));
-
-``name``
-~~~~~~~~
-
-A string to override the default value for the server's hostname.
-
-Defaults to ``Raven_Compat::gethostname()``.
-
-``tags``
-~~~~~~~~
-
-An array of tags to apply to events in this context.
-
-.. code-block:: php
-
- 'tags' => array(
- 'php_version' => phpversion(),
- )
-
-
-``curl_method``
-~~~~~~~~~~~~~~~
-
-Defaults to 'sync'.
-
-Available methods:
-
-- sync (default): send requests immediately when they're made
-- async: uses a curl_multi handler for best-effort asynchronous submissions
-- exec: asynchronously send events by forking a curl process for each item
-
-``curl_path``
-~~~~~~~~~~~~~
-
-Defaults to 'curl'.
-
-Specify the path to the curl binary to be used with the 'exec' curl method.
-
-
-``trace``
-~~~~~~~~~
-
-Set this to ``false`` to disable reflection tracing (function calling arguments) in stacktraces.
-
-
-``logger``
-~~~~~~~~~~
-
-Adjust the default logger name for messages.
-
-Defaults to ``php``.
-
-``ca_cert``
-~~~~~~~~~~~
-
-The path to the CA certificate bundle.
-
-Defaults to the common bundle which includes getsentry.com: ./data/cacert.pem
-
-Caveats:
-
-- The CA bundle is ignored unless curl throws an error suggesting it needs a cert.
-- The option is only currently used within the synchronous curl transport.
-
-``curl_ssl_version``
-~~~~~~~~~~~~~~~~~~~~
-
-The SSL version (2 or 3) to use.
-By default PHP will try to determine this itself, although in some cases this must be set manually.
-
-``message_limit``
-~~~~~~~~~~~~~~~~~
-
-Defaults to 1024 characters.
-
-This value is used to truncate message and frame variables. However it is not guarantee that length of whole message will be restricted by this value.
-
-``processors``
-~~~~~~~~~~~~~~~~~
-
-An array of classes to use to process data before it is sent to Sentry. By default, Raven_SanitizeDataProcessor is used
-
-``processorOptions``
-~~~~~~~~~~~~~~~~~
-Options that will be passed on to a setProcessorOptions() function in a Raven_Processor sub-class before that Processor is added to the list of processors used by Raven_Client
-
-An example of overriding the regular expressions in Raven_SanitizeDataProcessor is below:
-
-.. code-block:: php
-
- 'processorOptions' => array(
- 'Raven_SanitizeDataProcessor' => array(
- 'fields_re' => '/(user_password|user_token|user_secret)/i',
- 'values_re' => '/^(?:\d[ -]*?){15,16}$/'
- )
- )
-
-Providing Request Context
--------------------------
-
-Most of the time you're not actually calling out to Raven directly, but you still want to provide some additional context. This lifecycle generally constists of something like the following:
-
-- Set some context via a middleware (e.g. the logged in user)
-- Send all given context with any events during the request lifecycle
-- Cleanup context
-
-There are three primary methods for providing request context:
-
-.. code-block:: php
-
- // bind the logged in user
- $client->user_context(array('email' => 'foo@example.com'));
-
- // tag the request with something interesting
- $client->tags_context(array('interesting' => 'yes'));
-
- // provide a bit of additional context
- $client->extra_context(array('happiness' => 'very'));
-
-
-If you're performing additional requests during the lifecycle, you'll also need to ensure you cleanup the context (to reset its state):
-
-.. code-block:: php
-
- $client->context->clear();
-
-
-Contributing
-------------
-
-First, make sure you can run the test suite. Install development dependencies :
-
-::
-
- $ composer install
-
-You may now use phpunit :
-
-::
-
- $ vendor/bin/phpunit
-
-
-
-Resources
----------
-
-* `Bug Tracker `_
-* `Code `_
-* `Mailing List `_
-* `IRC `_ (irc.freenode.net, #sentry)
diff --git a/lib/sentry/raven/composer.json b/lib/sentry/raven/composer.json
deleted file mode 100644
index a31b582..0000000
--- a/lib/sentry/raven/composer.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "name": "raven/raven",
- "type": "library",
- "description": "A PHP client for Sentry (http://getsentry.com)",
- "keywords": ["log", "logging"],
- "homepage": "http://getsentry.com",
- "license": "BSD",
- "authors": [
- {
- "name": "David Cramer",
- "email": "dcramer@gmail.com"
- }
- ],
- "require-dev": {
- "fabpot/php-cs-fixer": "^1.8.0",
- "phpunit/phpunit": "^4.6.6"
- },
- "require": {
- "php": ">=5.2.4",
- "ext-curl": "*"
- },
- "bin": [
- "bin/raven"
- ],
- "autoload": {
- "psr-0" : {
- "Raven_" : "lib/"
- }
- },
- "extra": {
- "branch-alias": {
- "dev-master": "0.13.x-dev"
- }
- }
-}
diff --git a/lib/sentry/raven/docs/advanced.rst b/lib/sentry/raven/docs/advanced.rst
deleted file mode 100644
index 4ecdc9b..0000000
--- a/lib/sentry/raven/docs/advanced.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-Advanced Topics
-===============
-
-This covers various advanced usage topics for the PHP client.
-
-.. _raven-php-advanced-installation:
-
-Advanced Installation
----------------------
-
-This covers all methods of installation and a bit more detail.
-
-Install with Composer
-`````````````````````
-
-If you're using `Composer `_ to manage
-dependencies, you can add Raven with it.
-
-.. code-block:: json
-
- {
- "require": {
- "raven/raven": "$VERSION"
- }
- }
-
-(replace ``$VERSION`` with one of the available versions on `Packagist
-`_) or to get the latest
-version off the master branch:
-
-.. code-block:: json
-
- {
- "require": {
- "raven/raven": "dev-master"
- }
- }
-
-Note that using unstable versions is not recommended and should be
-avoided. Also you should define a maximum version, e.g. by doing
-``>=0.6,<1.0`` or ``~0.6``.
-
-Composer will take care of the autoloading for you, so if you require the
-``vendor/autoload.php``, you're good to go.
-
-Install Source from GitHub
-``````````````````````````
-
-To install the source code::
-
- $ git clone git://github.com/getsentry/raven-php.git
-
-And including it using the autoloader:
-
-.. code-block:: php
-
- require_once '/path/to/Raven/library/Raven/Autoloader.php';
- Raven_Autoloader::register();
diff --git a/lib/sentry/raven/docs/integrations/laravel.rst b/lib/sentry/raven/docs/integrations/laravel.rst
deleted file mode 100644
index b56ff8f..0000000
--- a/lib/sentry/raven/docs/integrations/laravel.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-Laravel
-=======
-
-Laravel supports Monolog out of the box, which also provides a native Sentry handler.
-
-Laravel 5.x
------------
-
-To configure logging, pop open your ``bootstrap/app.php`` file, and insert the following:
-
-.. sourcecode:: php
-
- $app->configureMonologUsing(function($monolog) {
- $client = new Raven_Client('___DSN___')
-
- $handler = new Monolog\Handler\RavenHandler($client);
- $handler->setFormatter(new Monolog\Formatter\LineFormatter("%message% %context% %extra%\n"));
-
- $monolog->pushHandler($handler);
- });
-
-Laravel 4.x
------------
-
-To configure logging, pop open your ``app/start/global.php`` file, and insert the following:
-
-.. sourcecode:: php
-
- $client = new Raven_Client('___DSN___')
-
- $handler = new Monolog\Handler\RavenHandler($client);
- $handler->setFormatter(new Monolog\Formatter\LineFormatter("%message% %context% %extra%\n"));
-
- $monolog = Log::getMonolog();
- $monolog->pushHandler($handler);
-
-Adding Context
---------------
-
-Context can be added via a Monolog processor:
-
-.. sourcecode:: php
-
- $monolog->pushProcessor(function ($record) {
- $user = Auth::user();
-
- // Add the authenticated user
- if ($user) {
- $record['context']['user'] = array(
- 'username' => Auth::user()->username,
- 'ip_address' => Request::getClientIp(),
- );
- } else {
- $record['context']['user'] = array(
- 'ip_address' => Request::getClientIp(),
- );
- }
-
- // Add various tags
- $record['context']['tags'] = array('key' => 'value');
-
- // Add various generic context
- $record['extra']['key'] = 'value';
-
- return $record;
- });
diff --git a/lib/sentry/raven/docs/integrations/symfony2.rst b/lib/sentry/raven/docs/integrations/symfony2.rst
deleted file mode 100644
index 843fab7..0000000
--- a/lib/sentry/raven/docs/integrations/symfony2.rst
+++ /dev/null
@@ -1,89 +0,0 @@
-Symfony2
-========
-
-Symfony2 supports Monolog out of the box, which also provides a native Sentry handler.
-
-Simply add a new handler for Sentry to your config (i.e. in ``config_prod.yaml``), and you're good to go:
-
-.. sourcecode:: yaml
-
- monolog:
- handlers:
- main:
- type: fingers_crossed
- action_level: error
- handler: grouped_main
-
- sentry:
- type: raven
- dsn: '___DSN___'
- level: error
-
- # Groups
- grouped_main:
- type: group
- members: [sentry, streamed_main]
-
- # Streams
- streamed_main:
- type: stream
- path: %kernel.logs_dir%/%kernel.environment%.log
- level: error
-
-Adding Context
---------------
-
-Capturing context can be done via a monolog processor:
-
-.. sourcecode:: php
-
- namespace Acme\Bundle\AcmeBundle\Monolog;
-
- use Symfony\Component\DependencyInjection\ContainerInterface;
- use Acme\Bundle\AcmeBundle\Entity\User;
-
- class SentryContextProcessor {
-
- protected $container;
-
- public function __construct(ContainerInterface $container)
- {
- $this->container = $container;
- }
-
- public function processRecord($record)
- {
- $securityContext = $this->container->get('security.context');
- $user = $securityContext->getToken()->getUser();
-
- if($user instanceof User)
- {
-
- $record['context']['user'] = array(
- 'name' => $user->getName(),
- 'username' => $user->getUsername(),
- 'email' => $user->getEmail(),
- );
- }
-
- // Add various tags
- $record['context']['tags'] = array('key' => 'value');
-
- // Add various generic context
- $record['extra']['key'] = 'value';
-
- return $record;
- }
-
- }
-
-You'll then register the processor in your config:
-
-.. sourcecode:: php
-
- services:
- monolog.processor.sentry_context:
- class: Applestump\Bundle\ShowsBundle\Monolog\SentryContextProcessor
- arguments: ["@service_container"]
- tags:
- - { name: monolog.processor, method: processRecord, handler: sentry }
diff --git a/lib/sentry/raven/docs/usage.rst b/lib/sentry/raven/docs/usage.rst
deleted file mode 100644
index 1c85450..0000000
--- a/lib/sentry/raven/docs/usage.rst
+++ /dev/null
@@ -1,180 +0,0 @@
-Usage
-=====
-
-Using Raven for PHP is straightforward. After installation of the library
-you can directly interface with the client and start submitting data.
-
-Basics
-------
-
-The most important part is the creation of the raven client. Create it
-once and reference it from anywhere you want to interface with Sentry:
-
-.. code-block:: php
-
- $client = new Raven_Client('___DSN___');
-
-Capturing Errors
-----------------
-
-The most basic functionality is to use Raven for reporting any uncaught
-exceptions or PHP errors. As this functionality is common enough, Raven
-provides support for this out of the box:
-
-.. code-block:: php
-
- $error_handler = new Raven_ErrorHandler($client);
- $error_handler->registerExceptionHandler();
- $error_handler->registerErrorHandler();
- $error_handler->registerShutdownFunction();
-
-Reporting Exceptions
---------------------
-
-If you want to report exceptions manually you can use the
-`captureException` function.
-
-.. code-block:: php
-
- // Basic Reporting
- $event_id = $client->getIdent($client->captureException($ex));
-
- // Provide some additional data with an exception
- $event_id = $client->getIdent($client->captureException($ex, array(
- 'extra' => array(
- 'php_version' => phpversion()
- ),
- )));
-
-Reporting Messages
-------------------
-
-Sometimes you don't have a PHP error but something bad happened and you
-want to report it anyways. This is where `captureMessage` comes in. It
-takes a message and reports it to sentry.
-
-.. code-block:: php
-
- // Capture a message
- $event_id = $client->getIdent($client->captureMessage('my log message'));
-
-Give User Feedback
-------------------
-
-The `event_id` returned can be shown to the user to help track down the
-particular exception in Sentry later. In case reporting to Sentry failed
-you can also detect that:
-
-.. code-block:: php
-
- if ($client->getLastError() !== null) {
- echo "Something went very, very wrong";
- // $client->getLastError() contains the error that occurred
- } else {
- // Give the user feedback
- echo "Sorry, there was an error!";
- echo "Your reference ID is " . $event_id;
- }
-
-Optional Attributes
--------------------
-
-With calls to ``captureException`` or ``captureMessage`` additional data
-can be supplied::
-
- .. code-block:: php
-
- $client->captureException($ex, array('attr' => 'value'))
-
-.. describe:: extra
-
- Additional context for this event. Must be a mapping. Children can be any native JSON type.
-
- .. code-block:: php
-
- array(
- 'extra' => array('key' => 'value')
- )
-
-.. describe:: fingerprint
-
- The fingerprint for grouping this event.
-
- .. code-block:: php
-
- array(
- // dont group events from the same NODE_ENV together
- 'fingerprint' => ['{{ default }}', process.env.NODE_ENV]
- )
-
-.. describe:: level
-
- The level of the event. Defaults to ``error``.
-
- .. code-block:: php
-
- array(
- 'level' => 'warning'
- )
-
- Sentry is aware of the following levels:
-
- * debug (the least serious)
- * info
- * warning
- * error
- * fatal (the most serious)
-
-.. describe:: logger
-
- The logger name for the event.
-
- .. code-block:: php
-
- array(
- 'logger' => 'default'
- )
-
-.. describe:: tags
-
- Tags to index with this event. Must be a mapping of strings.
-
- .. code-block:: php
-
- array(
- 'tags' => array('key' => 'value')
- )
-
-.. describe:: user
-
- The acting user.
-
- .. code-block:: php
-
- array(
- 'user' => array(
- 'id' => 42,
- 'email' => 'clever-girl'
- )
- )
-
-Testing Your Connection
------------------------
-
-The PHP client includes a simple helper script to test your connection and
-credentials with the Sentry master server::
-
- $ bin/raven test ___DSN___
- Client configuration:
- -> server: [___API_URL___]
- -> project: ___PROJECT_ID___
- -> public_key: ___PUBLIC_KEY___
- -> secret_key: ___SECRET_KEY___
-
- Sending a test event:
- -> event ID: f1765c9aed4f4ceebe5a93df9eb2d34f
-
- Done!
-
-.. note:: The CLI enforces the synchronous option on HTTP requests whereas
- the default configuration is asynchronous.
diff --git a/lib/sentry/raven/lib/Raven/Client.php b/lib/sentry/raven/lib/Raven/Client.php
deleted file mode 100644
index 6015bef..0000000
--- a/lib/sentry/raven/lib/Raven/Client.php
+++ /dev/null
@@ -1,915 +0,0 @@
-logger = Raven_Util::get($options, 'logger', 'php');
- $this->server = Raven_Util::get($options, 'server');
- $this->secret_key = Raven_Util::get($options, 'secret_key');
- $this->public_key = Raven_Util::get($options, 'public_key');
- $this->project = Raven_Util::get($options, 'project', 1);
- $this->auto_log_stacks = (bool) Raven_Util::get($options, 'auto_log_stacks', false);
- $this->name = Raven_Util::get($options, 'name', Raven_Compat::gethostname());
- $this->site = Raven_Util::get($options, 'site', $this->_server_variable('SERVER_NAME'));
- $this->tags = Raven_Util::get($options, 'tags', array());
- $this->release = Raven_util::get($options, 'release', null);
- $this->trace = (bool) Raven_Util::get($options, 'trace', true);
- $this->timeout = Raven_Util::get($options, 'timeout', 2);
- $this->message_limit = Raven_Util::get($options, 'message_limit', self::MESSAGE_LIMIT);
- $this->exclude = Raven_Util::get($options, 'exclude', array());
- $this->severity_map = null;
- $this->shift_vars = (bool) Raven_Util::get($options, 'shift_vars', true);
- $this->http_proxy = Raven_Util::get($options, 'http_proxy');
- $this->extra_data = Raven_Util::get($options, 'extra', array());
- $this->send_callback = Raven_Util::get($options, 'send_callback', null);
- $this->curl_method = Raven_Util::get($options, 'curl_method', 'sync');
- $this->curl_path = Raven_Util::get($options, 'curl_path', 'curl');
- $this->curl_ipv4 = Raven_util::get($options, 'curl_ipv4', true);
- $this->ca_cert = Raven_util::get($options, 'ca_cert', $this->get_default_ca_cert());
- $this->verify_ssl = Raven_util::get($options, 'verify_ssl', true);
- $this->curl_ssl_version = Raven_Util::get($options, 'curl_ssl_version');
-
- $this->processors = $this->setProcessorsFromOptions($options);
-
- $this->_lasterror = null;
- $this->_user = null;
- $this->context = new Raven_Context();
-
- if ($this->curl_method == 'async') {
- $this->_curl_handler = new Raven_CurlHandler($this->get_curl_options());
- }
- }
-
- public static function getDefaultProcessors()
- {
- return array(
- 'Raven_SanitizeDataProcessor',
- );
- }
-
- /**
- * Sets the Raven_Processor sub-classes to be used when data is processed before being
- * sent to Sentry.
- *
- * @param $options
- * @return array
- */
- public function setProcessorsFromOptions($options)
- {
- $processors = array();
- foreach (Raven_util::get($options, 'processors', self::getDefaultProcessors()) as $processor) {
- $new_processor = new $processor($this);
-
- if (isset($options['processorOptions']) && is_array($options['processorOptions'])) {
- if (isset($options['processorOptions'][$processor]) && method_exists($processor, 'setProcessorOptions')) {
- $new_processor->setProcessorOptions($options['processorOptions'][$processor]);
- }
- }
- $processors[] = $new_processor;
- }
- return $processors;
- }
-
- /**
- * Parses a Raven-compatible DSN and returns an array of its values.
- *
- * @param string $dsn Raven compatible DSN: http://raven.readthedocs.org/en/latest/config/#the-sentry-dsn
- * @return array parsed DSN
- */
- public static function parseDSN($dsn)
- {
- $url = parse_url($dsn);
- $scheme = (isset($url['scheme']) ? $url['scheme'] : '');
- if (!in_array($scheme, array('http', 'https'))) {
- throw new InvalidArgumentException('Unsupported Sentry DSN scheme: ' . (!empty($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(
- 'server' => sprintf('%s://%s%s/api/%s/store/', $scheme, $netloc, $path, $project),
- 'project' => $project,
- 'public_key' => $username,
- 'secret_key' => $password,
- );
- }
-
- public function getLastError()
- {
- return $this->_lasterror;
- }
-
- /**
- * Given an identifier, returns a Sentry searchable string.
- */
- public function getIdent($ident)
- {
- // XXX: We don't calculate checksums yet, so we only have the ident.
- return $ident;
- }
-
- /**
- * Deprecated
- */
- public function message($message, $params=array(), $level=self::INFO,
- $stack=false, $vars = null)
- {
- return $this->captureMessage($message, $params, $level, $stack, $vars);
- }
-
- /**
- * Deprecated
- */
- public function exception($exception)
- {
- return $this->captureException($exception);
- }
-
- /**
- * Log a message to sentry
- */
- public function captureMessage($message, $params=array(), $level_or_options=array(),
- $stack=false, $vars = null)
- {
- // Gracefully handle messages which contain formatting characters, but were not
- // intended to be used with formatting.
- if (!empty($params)) {
- $formatted_message = vsprintf($message, $params);
- } else {
- $formatted_message = $message;
- }
-
- if ($level_or_options === null) {
- $data = array();
- } elseif (!is_array($level_or_options)) {
- $data = array(
- 'level' => $level_or_options,
- );
- } else {
- $data = $level_or_options;
- }
-
- $data['message'] = $formatted_message;
- $data['sentry.interfaces.Message'] = array(
- 'message' => $message,
- 'params' => $params,
- );
-
- return $this->capture($data, $stack, $vars);
- }
-
- /**
- * Log an exception to sentry
- */
- public function captureException($exception, $culprit_or_options=null, $logger=null, $vars=null)
- {
- $has_chained_exceptions = version_compare(PHP_VERSION, '5.3.0', '>=');
-
- if (in_array(get_class($exception), $this->exclude)) {
- return null;
- }
-
- if (!is_array($culprit_or_options)) {
- $data = array();
- if ($culprit_or_options !== null) {
- $data['culprit'] = $culprit_or_options;
- }
- } else {
- $data = $culprit_or_options;
- }
-
- // TODO(dcramer): DRY this up
- $message = $exception->getMessage();
- if (empty($message)) {
- $message = get_class($exception);
- }
-
- $exc = $exception;
- do {
- $exc_data = array(
- 'value' => $exc->getMessage(),
- 'type' => get_class($exc),
- 'module' => $exc->getFile() .':'. $exc->getLine(),
- );
-
- /**'exception'
- * Exception::getTrace doesn't store the point at where the exception
- * was thrown, so we have to stuff it in ourselves. Ugh.
- */
- $trace = $exc->getTrace();
- $frame_where_exception_thrown = array(
- 'file' => $exc->getFile(),
- 'line' => $exc->getLine(),
- );
-
- array_unshift($trace, $frame_where_exception_thrown);
-
- // manually trigger autoloading, as it's not done in some edge cases due to PHP bugs (see #60149)
- if (!class_exists('Raven_Stacktrace')) {
- spl_autoload_call('Raven_Stacktrace');
- }
-
- $exc_data['stacktrace'] = array(
- 'frames' => Raven_Stacktrace::get_stack_info(
- $trace, $this->trace, $this->shift_vars, $vars, $this->message_limit
- ),
- );
-
- $exceptions[] = $exc_data;
- } while ($has_chained_exceptions && $exc = $exc->getPrevious());
-
- $data['message'] = $message;
- $data['exception'] = array(
- 'values' => array_reverse($exceptions),
- );
- if ($logger !== null) {
- $data['logger'] = $logger;
- }
-
- if (empty($data['level'])) {
- if (method_exists($exception, 'getSeverity')) {
- $data['level'] = $this->translateSeverity($exception->getSeverity());
- } else {
- $data['level'] = self::ERROR;
- }
- }
-
- return $this->capture($data, $trace, $vars);
- }
-
- /**
- * Log an query to sentry
- */
- public function captureQuery($query, $level=self::INFO, $engine = '')
- {
- $data = array(
- 'message' => $query,
- 'level' => $level,
- 'sentry.interfaces.Query' => array(
- 'query' => $query
- )
- );
-
- if ($engine !== '') {
- $data['sentry.interfaces.Query']['engine'] = $engine;
- }
- return $this->capture($data, false);
- }
-
- protected function is_http_request()
- {
- return isset($_SERVER['REQUEST_METHOD']) && PHP_SAPI !== 'cli';
- }
-
- protected function get_http_data()
- {
- $env = $headers = array();
-
- foreach ($_SERVER as $key => $value) {
- if (0 === strpos($key, 'HTTP_')) {
- if (in_array($key, array('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'))) {
- continue;
- }
- $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))))] = $value;
- } elseif (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) {
- $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))))] = $value;
- } else {
- $env[$key] = $value;
- }
- }
-
- $result = array(
- 'method' => $this->_server_variable('REQUEST_METHOD'),
- 'url' => $this->get_current_url(),
- 'query_string' => $this->_server_variable('QUERY_STRING'),
- );
-
- // dont set this as an empty array as PHP will treat it as a numeric array
- // instead of a mapping which goes against the defined Sentry spec
- if (!empty($_POST)) {
- $result['data'] = $_POST;
- }
- if (!empty($_COOKIE)) {
- $result['cookies'] = $_COOKIE;
- }
- if (!empty($headers)) {
- $result['headers'] = $headers;
- }
- if (!empty($env)) {
- $result['env'] = $env;
- }
-
- return array(
- 'request' => $result,
- );
- }
-
- protected function get_user_data()
- {
- $user = $this->context->user;
- if ($user === null) {
- if (!session_id()) {
- return array();
- }
- $user = array(
- 'id' => session_id(),
- );
- if (!empty($_SESSION)) {
- $user['data'] = $_SESSION;
- }
- }
- return array(
- 'user' => $user,
- );
- }
-
- protected function get_extra_data()
- {
- return $this->extra_data;
- }
-
- public function get_default_data()
- {
- return array(
- 'server_name' => $this->name,
- 'project' => $this->project,
- 'site' => $this->site,
- 'logger' => $this->logger,
- 'tags' => $this->tags,
- 'platform' => 'php',
- );
- }
-
- public function capture($data, $stack, $vars = null)
- {
- if (!isset($data['timestamp'])) {
- $data['timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
- }
- if (!isset($data['level'])) {
- $data['level'] = self::ERROR;
- }
- if (!isset($data['tags'])) {
- $data['tags'] = array();
- }
- if (!isset($data['extra'])) {
- $data['extra'] = array();
- }
- if (!isset($data['event_id'])) {
- $data['event_id'] = $this->uuid4();
- }
-
- if (isset($data['message'])) {
- $data['message'] = substr($data['message'], 0, $this->message_limit);
- }
-
- $data = array_merge($this->get_default_data(), $data);
-
- if ($this->is_http_request()) {
- $data = array_merge($this->get_http_data(), $data);
- }
-
- $data = array_merge($this->get_user_data(), $data);
-
- if ($this->release) {
- $data['release'] = $this->release;
- }
-
- $data['tags'] = array_merge(
- $this->tags,
- $this->context->tags,
- $data['tags']);
-
- $data['extra'] = array_merge(
- $this->get_extra_data(),
- $this->context->extra,
- $data['extra']);
-
- // avoid empty arrays (which dont convert to dicts)
- if (empty($data['extra'])) {
- unset($data['extra']);
- }
- if (empty($data['tags'])) {
- unset($data['tags']);
- }
-
- if ((!$stack && $this->auto_log_stacks) || $stack === true) {
- $stack = debug_backtrace();
-
- // Drop last stack
- array_shift($stack);
- }
-
- if (!empty($stack)) {
- // manually trigger autoloading, as it's not done in some edge cases due to PHP bugs (see #60149)
- if (!class_exists('Raven_Stacktrace')) {
- spl_autoload_call('Raven_Stacktrace');
- }
-
- if (!isset($data['stacktrace'])) {
- $data['stacktrace'] = array(
- 'frames' => Raven_Stacktrace::get_stack_info(
- $stack, $this->trace, $this->shift_vars, $vars, $this->message_limit
- ),
- );
- }
- }
-
- $this->sanitize($data);
- $this->process($data);
-
- if (!$this->store_errors_for_bulk_send) {
- $this->send($data);
- } else {
- if (empty($this->error_data)) {
- $this->error_data = array();
- }
- $this->error_data[] = $data;
- }
-
- return $data['event_id'];
- }
-
- public function sanitize(&$data)
- {
- // manually trigger autoloading, as it's not done in some edge cases due to PHP bugs (see #60149)
- if (!class_exists('Raven_Serializer')) {
- spl_autoload_call('Raven_Serializer');
- }
-
- $data = Raven_Serializer::serialize($data);
- }
-
- /**
- * Process data through all defined Raven_Processor sub-classes
- *
- * @param array $data Associative array of data to log
- */
- public function process(&$data)
- {
- foreach ($this->processors as $processor) {
- $processor->process($data);
- }
- }
-
- public function sendUnsentErrors()
- {
- if (!empty($this->error_data)) {
- foreach ($this->error_data as $data) {
- $this->send($data);
- }
- unset($this->error_data);
- }
- if ($this->store_errors_for_bulk_send) {
- //in case an error occurs after this is called, on shutdown, send any new errors.
- $this->store_errors_for_bulk_send = !defined('RAVEN_CLIENT_END_REACHED');
- }
- }
-
- /**
- * Wrapper to handle encoding and sending data to the Sentry API server.
- *
- * @param array $data Associative array of data to log
- */
- public function send($data)
- {
- if (is_callable($this->send_callback) && !call_user_func($this->send_callback, $data)) {
- // if send_callback returns falsely, end native send
- return;
- }
-
- if (!$this->server) {
- return;
- }
-
- $message = Raven_Compat::json_encode($data);
-
- if (function_exists("gzcompress")) {
- $message = gzcompress($message);
- }
- $message = base64_encode($message); // PHP's builtin curl_* function are happy without this, but the exec method requires it
-
- $client_string = 'raven-php/' . self::VERSION;
- $timestamp = microtime(true);
- $headers = array(
- 'User-Agent' => $client_string,
- 'X-Sentry-Auth' => $this->get_auth_header(
- $timestamp, $client_string, $this->public_key,
- $this->secret_key),
- 'Content-Type' => 'application/octet-stream'
- );
-
- $this->send_remote($this->server, $message, $headers);
- }
-
- /**
- * Send data to Sentry
- *
- * @param string $url Full URL to Sentry
- * @param array $data Associative array of data to log
- * @param array $headers Associative array of headers
- */
- private function send_remote($url, $data, $headers=array())
- {
- $parts = parse_url($url);
- $parts['netloc'] = $parts['host'].(isset($parts['port']) ? ':'.$parts['port'] : null);
- $this->send_http($url, $data, $headers);
- }
-
- protected function get_default_ca_cert()
- {
- return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'cacert.pem';
- }
-
- protected function get_curl_options()
- {
- $options = array(
- CURLOPT_VERBOSE => false,
- CURLOPT_SSL_VERIFYHOST => 2,
- CURLOPT_SSL_VERIFYPEER => $this->verify_ssl,
- CURLOPT_CAINFO => $this->ca_cert,
- CURLOPT_USERAGENT => 'raven-php/' . self::VERSION,
- );
- if ($this->http_proxy) {
- $options[CURLOPT_PROXY] = $this->http_proxy;
- }
- if ($this->curl_ssl_version) {
- $options[CURLOPT_SSLVERSION] = $this->curl_ssl_version;
- }
- if ($this->curl_ipv4) {
- $options[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
- }
- if (defined('CURLOPT_TIMEOUT_MS')) {
- // MS is available in curl >= 7.16.2
- $timeout = max(1, ceil(1000 * $this->timeout));
-
- // some versions of PHP 5.3 don't have this defined correctly
- if (!defined('CURLOPT_CONNECTTIMEOUT_MS')) {
- //see http://stackoverflow.com/questions/9062798/php-curl-timeout-is-not-working/9063006#9063006
- define('CURLOPT_CONNECTTIMEOUT_MS', 156);
- }
-
- $options[CURLOPT_CONNECTTIMEOUT_MS] = $timeout;
- $options[CURLOPT_TIMEOUT_MS] = $timeout;
- } else {
- // fall back to the lower-precision timeout.
- $timeout = max(1, ceil($this->timeout));
- $options[CURLOPT_CONNECTTIMEOUT] = $timeout;
- $options[CURLOPT_TIMEOUT] = $timeout;
- }
- return $options;
- }
-
- /**
- * Send the message over http to the sentry url given
- *
- * @param string $url URL of the Sentry instance to log to
- * @param array $data Associative array of data to log
- * @param array $headers Associative array of headers
- */
- private function send_http($url, $data, $headers=array())
- {
- if ($this->curl_method == 'async') {
- $this->_curl_handler->enqueue($url, $data, $headers);
- } elseif ($this->curl_method == 'exec') {
- $this->send_http_asynchronous_curl_exec($url, $data, $headers);
- } else {
- $this->send_http_synchronous($url, $data, $headers);
- }
- }
-
- /**
- * Send the cURL to Sentry asynchronously. No errors will be returned from cURL
- *
- * @param string $url URL of the Sentry instance to log to
- * @param array $data Associative array of data to log
- * @param array $headers Associative array of headers
- * @return bool
- */
- private function send_http_asynchronous_curl_exec($url, $data, $headers)
- {
- // TODO(dcramer): support ca_cert
- $cmd = $this->curl_path.' -X POST ';
- foreach ($headers as $key => $value) {
- $cmd .= '-H \''. $key. ': '. $value. '\' ';
- }
- $cmd .= '-d \''. $data .'\' ';
- $cmd .= '\''. $url .'\' ';
- $cmd .= '-m 5 '; // 5 second timeout for the whole process (connect + send)
- $cmd .= '> /dev/null 2>&1 &'; // ensure exec returns immediately while curl runs in the background
-
- exec($cmd);
-
- return true; // The exec method is just fire and forget, so just assume it always works
- }
-
- /**
- * Send a blocking cURL to Sentry and check for errors from cURL
- *
- * @param string $url URL of the Sentry instance to log to
- * @param array $data Associative array of data to log
- * @param array $headers Associative array of headers
- * @return bool
- */
- private function send_http_synchronous($url, $data, $headers)
- {
- $new_headers = array();
- foreach ($headers as $key => $value) {
- array_push($new_headers, $key .': '. $value);
- }
- // XXX(dcramer): Prevent 100-continue response form server (Fixes GH-216)
- $new_headers[] = 'Expect:';
-
- $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_RETURNTRANSFER, true);
-
- $options = $this->get_curl_options();
- $ca_cert = $options[CURLOPT_CAINFO];
- unset($options[CURLOPT_CAINFO]);
- curl_setopt_array($curl, $options);
-
- curl_exec($curl);
-
- $errno = curl_errno($curl);
- // CURLE_SSL_CACERT || CURLE_SSL_CACERT_BADFILE
- if ($errno == 60 || $errno == 77) {
- curl_setopt($curl, CURLOPT_CAINFO, $ca_cert);
- curl_exec($curl);
- }
-
- $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- $success = ($code == 200);
- if (!$success) {
- // It'd be nice just to raise an exception here, but it's not very PHP-like
- $this->_lasterror = curl_error($curl);
- } else {
- $this->_lasterror = null;
- }
- curl_close($curl);
-
- return $success;
- }
-
- /**
- * Generate a Sentry authorization header string
- *
- * @param string $timestamp Timestamp when the event occurred
- * @param string $client HTTP client name (not Raven_Client object)
- * @param string $api_key Sentry API key
- * @param string $secret_key Sentry API key
- * @return string
- */
- protected function get_auth_header($timestamp, $client, $api_key, $secret_key)
- {
- $header = array(
- sprintf('sentry_timestamp=%F', $timestamp),
- "sentry_client={$client}",
- sprintf('sentry_version=%s', self::PROTOCOL),
- );
-
- if ($api_key) {
- $header[] = "sentry_key={$api_key}";
- }
-
- if ($secret_key) {
- $header[] = "sentry_secret={$secret_key}";
- }
-
-
- return sprintf('Sentry %s', implode(', ', $header));
- }
-
- /**
- * Generate an uuid4 value
- *
- * @return string
- */
- 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
- *
- * @return string|null
- */
- private function get_current_url()
- {
- // When running from commandline the REQUEST_URI is missing.
- if (!isset($_SERVER['REQUEST_URI'])) {
- return null;
- }
-
- $schema = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'
- || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
-
- // HTTP_HOST is a client-supplied header that is optional in HTTP 1.0
- $host = (!empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
- : (!empty($_SERVER['LOCAL_ADDR']) ? $_SERVER['LOCAL_ADDR']
- : (!empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '')));
-
- return $schema . $host . $_SERVER['REQUEST_URI'];
- }
-
- /**
- * Get the value of a key from $_SERVER
- *
- * @param string $key Key whose value you wish to obtain
- * @return string Key's value
- */
- private function _server_variable($key)
- {
- if (isset($_SERVER[$key])) {
- return $_SERVER[$key];
- }
-
- return '';
- }
-
- /**
- * Translate a PHP Error constant into a Sentry log level group
- *
- * @param string $severity PHP E_$x error constant
- * @return string Sentry log level group
- */
- public function translateSeverity($severity)
- {
- if (is_array($this->severity_map) && isset($this->severity_map[$severity])) {
- return $this->severity_map[$severity];
- }
- switch ($severity) {
- case E_ERROR: return Raven_Client::ERROR;
- case E_WARNING: return Raven_Client::WARN;
- case E_PARSE: return Raven_Client::ERROR;
- case E_NOTICE: return Raven_Client::INFO;
- case E_CORE_ERROR: return Raven_Client::ERROR;
- case E_CORE_WARNING: return Raven_Client::WARN;
- case E_COMPILE_ERROR: return Raven_Client::ERROR;
- case E_COMPILE_WARNING: return Raven_Client::WARN;
- case E_USER_ERROR: return Raven_Client::ERROR;
- case E_USER_WARNING: return Raven_Client::WARN;
- case E_USER_NOTICE: return Raven_Client::INFO;
- case E_STRICT: return Raven_Client::INFO;
- case E_RECOVERABLE_ERROR: return Raven_Client::ERROR;
- }
- if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
- switch ($severity) {
- case E_DEPRECATED: return Raven_Client::WARN;
- case E_USER_DEPRECATED: return Raven_Client::WARN;
- }
- }
- return Raven_Client::ERROR;
- }
-
- /**
- * Provide a map of PHP Error constants to Sentry logging groups to use instead
- * of the defaults in translateSeverity()
- *
- * @param array $map
- */
- public function registerSeverityMap($map)
- {
- $this->severity_map = $map;
- }
-
- /**
- * Convenience function for setting a user's ID and Email
- *
- * @param string $id User's ID
- * @param string|null $email User's email
- * @param array $data Additional user data
- */
- public function set_user_data($id, $email=null, $data=array())
- {
- $this->user_context(array_merge(array(
- 'id' => $id,
- 'email' => $email,
- ), $data));
- }
-
- /**
- * Sets user context.
- *
- * @param array $data Associative array of user data
- */
- public function user_context($data)
- {
- $this->context->user = $data;
- }
-
- /**
- * Appends tags context.
- *
- * @param array $data Associative array of tags
- */
- public function tags_context($data)
- {
- $this->context->tags = array_merge($this->context->tags, $data);
- }
-
- /**
- * Appends additional context.
- *
- * @param array $data Associative array of extra data
- */
- public function extra_context($data)
- {
- $this->context->extra = array_merge($this->context->extra, $data);
- }
-
- /**
- * @param array $processors
- */
- public function setProcessors(array $processors)
- {
- $this->processors = $processors;
- }
-}
diff --git a/lib/sentry/raven/lib/Raven/ErrorHandler.php b/lib/sentry/raven/lib/Raven/ErrorHandler.php
deleted file mode 100644
index 15dff8f..0000000
--- a/lib/sentry/raven/lib/Raven/ErrorHandler.php
+++ /dev/null
@@ -1,178 +0,0 @@
-registerExceptionHandler();
- * $error_handler->registerErrorHandler();
- * $error_handler->registerShutdownFunction();
- *
- * @package raven
- */
-
-class Raven_ErrorHandler
-{
- private $old_exception_handler;
- private $call_existing_exception_handler = false;
- private $old_error_handler;
- private $call_existing_error_handler = false;
- private $reservedMemory;
- private $send_errors_last = false;
- private $error_types = -1;
-
- /**
- * @var array
- * Error types that can be processed by the handler
- */
- private $validErrorTypes = array(
- E_ERROR,
- E_WARNING,
- E_PARSE,
- E_NOTICE,
- E_CORE_ERROR,
- E_CORE_WARNING,
- E_COMPILE_ERROR,
- E_COMPILE_WARNING,
- E_USER_ERROR,
- E_USER_WARNING,
- E_USER_NOTICE,
- E_STRICT,
- E_RECOVERABLE_ERROR,
- E_DEPRECATED,
- E_USER_DEPRECATED,
- );
-
- /**
- * @var array
- * The default Error types that are always processed by the handler. Can be set during construction.
- */
- private $defaultErrorTypes = array(
- E_ERROR,
- E_PARSE,
- E_CORE_ERROR,
- E_CORE_WARNING,
- E_COMPILE_ERROR,
- E_COMPILE_WARNING,
- E_STRICT,
- );
-
- public function __construct($client, $send_errors_last = false, $default_error_types = null)
- {
- $this->client = $client;
- if ($default_error_types !== null) {
- $this->defaultErrorTypes = $default_error_types;
- }
- register_shutdown_function(array($this, 'detectShutdown'));
- if ($send_errors_last) {
- $this->send_errors_last = true;
- $this->client->store_errors_for_bulk_send = true;
- register_shutdown_function(array($this->client, 'sendUnsentErrors'));
- }
- }
-
- public function handleException($e, $isError = false, $vars = null)
- {
- $e->event_id = $this->client->getIdent($this->client->captureException($e, null, null, $vars));
-
- if (!$isError && $this->call_existing_exception_handler && $this->old_exception_handler) {
- call_user_func($this->old_exception_handler, $e);
- }
- }
-
- public function handleError($code, $message, $file = '', $line = 0, $context=array())
- {
- if ($this->error_types & $code & error_reporting()) {
- $e = new ErrorException($message, 0, $code, $file, $line);
- $this->handleException($e, true, $context);
- }
-
- if ($this->call_existing_error_handler) {
- if ($this->old_error_handler) {
- return call_user_func($this->old_error_handler, $code, $message, $file, $line, $context);
- } else {
- return false;
- }
- }
- }
-
- /**
- * Nothing by default, use it in child classes for catching other types of errors
- * Only constants from $this->validErrorTypes can be used
- *
- * @return array
- */
- protected function getAdditionalErrorTypesToProcess()
- {
- return array();
- }
-
- /**
- * @return array
- */
- private function getErrorTypesToProcess()
- {
- $additionalErrorTypes = array_intersect($this->getAdditionalErrorTypesToProcess(), $this->validErrorTypes);
- // array_unique so bitwise "or" operation wouldn't fail if some error type gets repeated
- return array_unique($this->defaultErrorTypes + $additionalErrorTypes);
- }
-
- public function handleFatalError()
- {
- if (null === $lastError = error_get_last()) {
- return;
- }
-
- unset($this->reservedMemory);
-
- $errors = 0;
- foreach ($this->getErrorTypesToProcess() as $errorType) {
- $errors |= $errorType;
- }
-
- if ($lastError['type'] & $errors) {
- $e = new ErrorException(
- @$lastError['message'], @$lastError['type'], @$lastError['type'],
- @$lastError['file'], @$lastError['line']
- );
- $this->handleException($e, true);
- }
- }
-
- public 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;
- }
-
- public function registerErrorHandler($call_existing_error_handler = true, $error_types = -1)
- {
- $this->error_types = $error_types;
- $this->old_error_handler = set_error_handler(array($this, 'handleError'), error_reporting());
- $this->call_existing_error_handler = $call_existing_error_handler;
- }
-
- public function registerShutdownFunction($reservedMemorySize = 10)
- {
- register_shutdown_function(array($this, 'handleFatalError'));
-
- $this->reservedMemory = str_repeat('x', 1024 * $reservedMemorySize);
- }
-
- public function detectShutdown()
- {
- if (!defined('RAVEN_CLIENT_END_REACHED')) {
- define('RAVEN_CLIENT_END_REACHED', true);
- }
- }
-}
diff --git a/lib/sentry/raven/lib/Raven/Processor.php b/lib/sentry/raven/lib/Raven/Processor.php
deleted file mode 100644
index 7e37400..0000000
--- a/lib/sentry/raven/lib/Raven/Processor.php
+++ /dev/null
@@ -1,20 +0,0 @@
-client = $client;
- }
-
- /**
- * Process and sanitize data, modifying the existing value if necessary.
- *
- * @param array $data Array of log data
- */
- abstract public function process(&$data);
-}
diff --git a/lib/sentry/raven/lib/Raven/SanitizeDataProcessor.php b/lib/sentry/raven/lib/Raven/SanitizeDataProcessor.php
deleted file mode 100644
index cfac44f..0000000
--- a/lib/sentry/raven/lib/Raven/SanitizeDataProcessor.php
+++ /dev/null
@@ -1,119 +0,0 @@
-client = $client;
- $this->fields_re = self::FIELDS_RE;
- $this->values_re = self::VALUES_RE;
- $this->session_cookie_name = ini_get('session.name');
- }
-
- /**
- * Override the default processor options
- *
- * @param array $options Associative array of processor options
- */
- public function setProcessorOptions(array $options)
- {
- if (isset($options['fields_re'])) {
- $this->fields_re = $options['fields_re'];
- }
-
- if (isset($options['values_re'])) {
- $this->values_re = $options['values_re'];
- }
- }
-
- /**
- * Replace any array values with our mask if the field name or the value matches a respective regex
- *
- * @param mixed $item Associative array value
- * @param string $key Associative array key
- */
- public function sanitize(&$item, $key)
- {
- if (empty($item)) {
- return;
- }
-
- if (preg_match($this->values_re, $item)) {
- $item = self::MASK;
- }
-
- if (empty($key)) {
- return;
- }
-
- if (preg_match($this->fields_re, $key)) {
- $item = self::MASK;
- }
- }
-
- public function sanitizeHttp(&$data) {
- if (empty($data['request'])) {
- return;
- }
- $http = &$data['request'];
- if (empty($http['cookies'])) {
- return;
- }
-
- $cookies = &$http['cookies'];
- if (!empty($cookies[$this->session_cookie_name])) {
- $cookies[$this->session_cookie_name] = self::MASK;
- }
- }
-
- public function process(&$data)
- {
- array_walk_recursive($data, array($this, 'sanitize'));
- $this->sanitizeHttp($data);
- }
-
- /**
- * @return string
- */
- public function getFieldsRe()
- {
- return $this->fields_re;
- }
-
- /**
- * @param string $fields_re
- */
- public function setFieldsRe($fields_re)
- {
- $this->fields_re = $fields_re;
- }
-
- /**
- * @return string
- */
- public function getValuesRe()
- {
- return $this->values_re;
- }
-
- /**
- * @param string $values_re
- */
- public function setValuesRe($values_re)
- {
- $this->values_re = $values_re;
- }
-}
diff --git a/lib/sentry/raven/lib/Raven/Serializer.php b/lib/sentry/raven/lib/Raven/Serializer.php
deleted file mode 100644
index 3423dbf..0000000
--- a/lib/sentry/raven/lib/Raven/Serializer.php
+++ /dev/null
@@ -1,77 +0,0 @@
- $v) {
- $new[self::serializeValue($k)] = self::serialize($v, $max_depth, $_depth + 1);
- }
-
- return $new;
- } else {
- return self::serializeValue($value);
- }
- }
-
- public static function serializeValue($value)
- {
- if ($value === null) {
- return 'null';
- } elseif ($value === false) {
- return 'false';
- } elseif ($value === true) {
- return 'true';
- } elseif (is_float($value) && (int) $value == $value) {
- return $value.'.0';
- } elseif (is_object($value) || gettype($value) == 'object') {
- return 'Object '.get_class($value);
- } elseif (is_resource($value)) {
- return 'Resource '.get_resource_type($value);
- } elseif (is_array($value)) {
- return 'Array of length ' . count($value);
- } elseif (is_integer($value)) {
- return (integer) $value;
- } else {
- $value = (string) $value;
-
- if (function_exists('mb_convert_encoding')) {
- $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
- }
-
- return $value;
- }
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/ClientTest.php b/lib/sentry/raven/test/Raven/Tests/ClientTest.php
deleted file mode 100644
index bade086..0000000
--- a/lib/sentry/raven/test/Raven/Tests/ClientTest.php
+++ /dev/null
@@ -1,635 +0,0 @@
-__sent_events;
- }
- public function send($data)
- {
- if (is_callable($this->send_callback) && !call_user_func($this->send_callback, $data)) {
- // if send_callback returns falsely, end native send
- return;
- }
- $this->__sent_events[] = $data;
- }
- public function is_http_request()
- {
- return true;
- }
- public function get_auth_header($timestamp, $client, $api_key, $secret_key)
- {
- return parent::get_auth_header($timestamp, $client, $api_key, $secret_key);
- }
- public function get_http_data()
- {
- return parent::get_http_data();
- }
- public function get_user_data()
- {
- return parent::get_user_data();
- }
-}
-
-class Raven_Tests_ClientTest extends PHPUnit_Framework_TestCase
-{
- private function create_exception()
- {
- try {
- throw new Exception('Foo bar');
- } catch (Exception $ex) {
- return $ex;
- }
- }
-
- private function create_chained_exception()
- {
- try {
- throw new Exception('Foo bar');
- } catch (Exception $ex) {
- try {
- throw new Exception('Child exc', 0, $ex);
- } catch (Exception $ex2) {
- return $ex2;
- }
- }
- }
-
- public function testParseDsnHttp()
- {
- $result = Raven_Client::parseDsn('http://public:secret@example.com/1');
-
- $this->assertEquals($result['project'], 1);
- $this->assertEquals($result['server'], 'http://example.com/api/1/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['server'], 'https://example.com/api/1/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['server'], 'http://example.com/app/api/1/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['server'], 'http://example.com:9000/app/api/1/store/');
- $this->assertEquals($result['public_key'], 'public');
- $this->assertEquals($result['secret_key'], 'secret');
- }
-
- public function testParseDsnInvalidScheme()
- {
- try {
- Raven_Client::parseDsn('gopher://public:secret@/1');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- public function testParseDsnMissingNetloc()
- {
- try {
- Raven_Client::parseDsn('http://public:secret@/1');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- public function testParseDsnMissingProject()
- {
- try {
- Raven_Client::parseDsn('http://public:secret@example.com');
- $this->fail();
- } catch (Exception $e) {
- return;
- }
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testParseDsnMissingPublicKey()
- {
- Raven_Client::parseDsn('http://:secret@example.com/1');
- }
- /**
- * @expectedException InvalidArgumentException
- */
- public function testParseDsnMissingSecretKey()
- {
- 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->server, 'http://example.com/api/1/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->server, 'http://example.com/api/1/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(
- 'server' => 'http://example.com/api/1/store/',
- 'project' => 1,
- ));
-
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- }
-
- public function testOptionsFirstArgumentWithOptions()
- {
- $client = new Raven_Client(array(
- 'server' => 'http://example.com/api/1/store/',
- 'project' => 1,
- ), array(
- 'site' => 'foo',
- ));
-
- $this->assertEquals($client->server, 'http://example.com/api/1/store/');
- $this->assertEquals($client->site, 'foo');
- }
-
- public function testOptionsExtraData()
- {
- $client = new Dummy_Raven_Client(array('extra' => array('foo' => 'bar')));
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['extra']['foo'], 'bar');
- }
-
- public function testEmptyExtraData()
- {
- $client = new Dummy_Raven_Client(array('extra' => array()));
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals(array_key_exists('extra', $event), false);
- }
-
- public function testCaptureMessageDoesHandleUninterpolatedMessage()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['message'], 'Test Message %s');
- }
-
- public function testCaptureMessageDoesHandleInterpolatedMessage()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['message'], 'Test Message foo');
- }
-
- public function testCaptureMessageSetsInterface()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['sentry.interfaces.Message'], array(
- 'message' => 'Test Message %s',
- 'params' => array('foo'),
- ));
- }
-
- public function testCaptureMessageHandlesOptionsAsThirdArg()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'), array(
- 'level' => Dummy_Raven_Client::WARNING,
- 'extra' => array('foo' => 'bar')
- ));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- $this->assertEquals($event['extra']['foo'], 'bar');
- }
-
- public function testCaptureMessageHandlesLevelAsThirdArg()
- {
- $client = new Dummy_Raven_Client();
-
- $client->captureMessage('Test Message %s', array('foo'), Dummy_Raven_Client::WARNING);
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- }
-
- public function testCaptureExceptionSetsInterfaces()
- {
- # TODO: it'd be nice if we could mock the stacktrace extraction function here
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex);
-
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
-
- $exc = $event['exception'];
- $this->assertEquals(count($exc['values']), 1);
- $this->assertEquals($exc['values'][0]['value'], 'Foo bar');
- $this->assertEquals($exc['values'][0]['type'], 'Exception');
- $this->assertFalse(empty($exc['values'][0]['module']));
-
- $this->assertFalse(empty($exc['values'][0]['stacktrace']['frames']));
- $frames = $exc['values'][0]['stacktrace']['frames'];
- $frame = $frames[count($frames) - 1];
- $this->assertTrue($frame['lineno'] > 0);
- $this->assertEquals($frame['module'], 'ClientTest.php:Raven_Tests_ClientTest');
- $this->assertEquals($frame['function'], 'create_exception');
- $this->assertFalse(isset($frame['vars']));
- $this->assertEquals($frame['context_line'], ' throw new Exception(\'Foo bar\');');
- $this->assertFalse(empty($frame['pre_context']));
- $this->assertFalse(empty($frame['post_context']));
- }
-
- public function testCaptureExceptionChainedException()
- {
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
- }
-
- # TODO: it'd be nice if we could mock the stacktrace extraction function here
- $client = new Dummy_Raven_Client();
- $ex = $this->create_chained_exception();
- $client->captureException($ex);
-
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
-
- $exc = $event['exception'];
- $this->assertEquals(count($exc['values']), 2);
- $this->assertEquals($exc['values'][0]['value'], 'Foo bar');
- $this->assertEquals($exc['values'][1]['value'], 'Child exc');
- }
-
- public function testCaptureExceptionDifferentLevelsInChainedExceptionsBug()
- {
- if (version_compare(PHP_VERSION, '5.3.0', '<')) {
- $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
- }
-
- $client = new Dummy_Raven_Client();
- $e1 = new ErrorException('First', 0, E_DEPRECATED);
- $e2 = new ErrorException('Second', 0, E_NOTICE, __FILE__, __LINE__, $e1);
- $e3 = new ErrorException('Third', 0, E_ERROR, __FILE__, __LINE__, $e2);
-
- $client->captureException($e1);
- $client->captureException($e2);
- $client->captureException($e3);
- $events = $client->getSentEvents();
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::ERROR);
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::INFO);
-
- $event = array_pop($events);
- $this->assertEquals($event['level'], Dummy_Raven_Client::WARNING);
- }
-
- public function testCaptureExceptionHandlesOptionsAsSecondArg()
- {
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex, array('culprit' => 'test'));
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['culprit'], 'test');
- }
-
- public function testCaptureExceptionHandlesCulpritAsSecondArg()
- {
- $client = new Dummy_Raven_Client();
- $ex = $this->create_exception();
- $client->captureException($ex, 'test');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 1);
- $event = array_pop($events);
- $this->assertEquals($event['culprit'], 'test');
- }
-
- public function testCaptureExceptionHandlesExcludeOption()
- {
- $client = new Dummy_Raven_Client(array(
- 'exclude' => array('Exception'),
- ));
- $ex = $this->create_exception();
- $client->captureException($ex, 'test');
- $events = $client->getSentEvents();
- $this->assertEquals(count($events), 0);
- }
-
- public function testDoesRegisterProcessors()
- {
- $client = new Dummy_Raven_Client(array(
- 'processors' => array('Raven_SanitizeDataProcessor'),
- ));
- $this->assertEquals(count($client->processors), 1);
- $this->assertTrue($client->processors[0] instanceof Raven_SanitizeDataProcessor);
- }
-
- public function testProcessDoesCallProcessors()
- {
- $data = array("key"=>"value");
-
- $processor = $this->getMock('Processor', array('process'));
- $processor->expects($this->once())
- ->method('process')
- ->with($data);
-
- $client = new Dummy_Raven_Client();
- $client->processors[] = $processor;
- $client->process($data);
- }
-
- public function testDefaultProcessorsAreUsed()
- {
- $client = new Dummy_Raven_Client();
- $defaults = Dummy_Raven_Client::getDefaultProcessors();
-
- $this->assertEquals(count($client->processors), count($defaults));
- }
-
- public function testDefaultProcessorsContainSanitizeDataProcessor()
- {
- $defaults = Dummy_Raven_Client::getDefaultProcessors();
-
- $this->assertTrue(in_array('Raven_SanitizeDataProcessor', $defaults));
- }
-
- public function testGetDefaultData()
- {
- $client = new Dummy_Raven_Client();
- $expected = array(
- 'platform' => 'php',
- 'project' => $client->project,
- 'server_name' => $client->name,
- 'site' => $client->site,
- 'logger' => $client->logger,
- 'tags' => $client->tags,
- );
- $this->assertEquals($expected, $client->get_default_data());
- }
-
- /**
- * @backupGlobals
- */
- public function testGetHttpData()
- {
- $_SERVER = array(
- 'REDIRECT_STATUS' => '200',
- 'CONTENT_TYPE' => 'text/xml',
- 'CONTENT_LENGTH' => '99',
- 'HTTP_HOST' => 'getsentry.com',
- 'HTTP_ACCEPT' => 'text/html',
- 'HTTP_ACCEPT_CHARSET' => 'utf-8',
- 'HTTP_COOKIE' => 'cupcake: strawberry',
- 'HTTP_CONTENT_TYPE' => 'text/html',
- 'HTTP_CONTENT_LENGTH' => '1000',
- 'SERVER_PORT' => '443',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'PATCH',
- 'QUERY_STRING' => 'q=bitch&l=en',
- 'REQUEST_URI' => '/welcome/',
- 'SCRIPT_NAME' => '/index.php',
- );
- $_POST = array(
- 'stamp' => '1c',
- );
- $_COOKIE = array(
- 'donut' => 'chocolat',
- );
-
- $expected = array(
- 'request' => array(
- 'method' => 'PATCH',
- 'url' => 'https://getsentry.com/welcome/',
- 'query_string' => 'q=bitch&l=en',
- 'data' => array(
- 'stamp' => '1c',
- ),
- 'cookies' => array(
- 'donut' => 'chocolat',
- ),
- 'headers' => array(
- 'Host' => 'getsentry.com',
- 'Accept' => 'text/html',
- 'Accept-Charset' => 'utf-8',
- 'Cookie' => 'cupcake: strawberry',
- 'Content-Type' => 'text/xml',
- 'Content-Length' => '99',
- ),
- 'env' => array(
- 'REDIRECT_STATUS' => '200',
- 'SERVER_PORT' => '443',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'PATCH',
- 'QUERY_STRING' => 'q=bitch&l=en',
- 'REQUEST_URI' => '/welcome/',
- 'SCRIPT_NAME' => '/index.php',
- ),
- )
- );
-
- $client = new Dummy_Raven_Client();
- $this->assertEquals($expected, $client->get_http_data());
- }
-
- public function testGetUserDataWithSetUser()
- {
- $client = new Dummy_Raven_Client();
-
- $id = 'unique_id';
- $email = 'foo@example.com';
-
- $user = array(
- 'username' => 'my_user',
- );
-
- $client->set_user_data($id, $email, $user);
-
- $expected = array(
- 'user' => array(
- 'id' => 'unique_id',
- 'username' => 'my_user',
- 'email' => 'foo@example.com',
- )
- );
-
- $this->assertEquals($expected, $client->get_user_data());
- }
-
- public function testGetUserDataWithNoUser()
- {
- $client = new Dummy_Raven_Client();
-
- $expected = array(
- 'user' => array(
- 'id' => session_id(),
- )
- );
- $this->assertEquals($expected, $client->get_user_data());
- }
-
- public function testGetAuthHeader()
- {
- $client = new Dummy_Raven_Client();
-
- $clientstring = 'raven-php/test';
- $timestamp = '1234341324.340000';
-
- $expected = "Sentry sentry_timestamp={$timestamp}, sentry_client={$clientstring}, " .
- "sentry_version=" . Dummy_Raven_Client::PROTOCOL . ", " .
- "sentry_key=publickey, sentry_secret=secretkey";
-
- $this->assertEquals($expected, $client->get_auth_header($timestamp, 'raven-php/test', 'publickey', 'secretkey'));
- }
-
- public function testCaptureMessageWithUserContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->user_context(array('email' => 'foo@example.com'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'email' => 'foo@example.com',
- ), $event['user']);
- }
-
- public function testCaptureMessageWithTagsContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->tags_context(array('foo' => 'bar'));
- $client->tags_context(array('biz' => 'boz'));
- $client->tags_context(array('biz' => 'baz'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'foo' => 'bar',
- 'biz' => 'baz',
- ), $event['tags']);
- }
-
- public function testCaptureMessageWithExtraContext()
- {
- $client = new Dummy_Raven_Client();
-
- $client->extra_context(array('foo' => 'bar'));
- $client->extra_context(array('biz' => 'boz'));
- $client->extra_context(array('biz' => 'baz'));
-
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- $event = array_pop($events);
- $this->assertEquals(array(
- 'foo' => 'bar',
- 'biz' => 'baz',
- ), $event['extra']);
- }
-
- public function cb1($data)
- {
- $this->assertEquals('test', $data['message']);
- return false;
- }
-
- public function cb2($data)
- {
- $this->assertEquals('test', $data['message']);
- return true;
- }
-
- public function testSendCallback()
- {
- $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb1')));
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(0, count($events));
-
- $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb2')));
- $client->captureMessage('test');
- $events = $client->getSentEvents();
- $this->assertEquals(1, count($events));
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/CompatTest.php b/lib/sentry/raven/test/Raven/Tests/CompatTest.php
deleted file mode 100644
index 93f7c41..0000000
--- a/lib/sentry/raven/test/Raven/Tests/CompatTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-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('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
-
- $result = Raven_Compat::_hash_hmac('sha1', 'foo', 'bar');
- $this->assertEquals('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
- }
-
- public function test_json_encode()
- {
- $result = Raven_Compat::json_encode(array('foo' => array('bar' => 1)));
- $this->assertEquals('{"foo":{"bar":1}}', $result);
-
- $result = Raven_Compat::_json_encode(array('foo' => array('bar' => 1)));
- $this->assertEquals('{"foo":{"bar":1}}', $result);
-
- $result = Raven_Compat::_json_encode(array(1, 2, 3, 4, 'foo', 'bar'));
- $this->assertEquals('[1,2,3,4,"foo","bar"]', $result);
-
- $result = Raven_Compat::_json_encode(array(1, 'foo', 'foobar' => 'bar'));
- $this->assertEquals('{0:1,1:"foo","foobar":"bar"}', $result);
-
- $result = Raven_Compat::_json_encode(array(array()));
- $this->assertEquals('[[]]', $result);
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/ErrorHandlerTest.php b/lib/sentry/raven/test/Raven/Tests/ErrorHandlerTest.php
deleted file mode 100644
index 656b759..0000000
--- a/lib/sentry/raven/test/Raven/Tests/ErrorHandlerTest.php
+++ /dev/null
@@ -1,87 +0,0 @@
-errorLevel = error_reporting();
- }
-
- public function tearDown()
- {
- error_reporting($this->errorLevel);
- }
-
- 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);
- }
-
- public function testErrorHandlerCheckSilentReporting()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->never())
- ->method('captureException');
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false);
-
- @trigger_error('Silent', E_USER_WARNING);
- }
-
- public function testErrorHandlerBlockErrorReporting()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->never())
- ->method('captureException');
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false);
-
- error_reporting(E_USER_ERROR);
- trigger_error('Warning', E_USER_WARNING);
- }
-
- public function testErrorHandlerPassErrorReportingPass()
- {
- $client = $this->getMock('Client', array('captureException', 'getIdent'));
- $client->expects($this->once())
- ->method('captureException');
-
- $handler = new Raven_ErrorHandler($client);
- $handler->registerErrorHandler(false);
-
- error_reporting(E_USER_WARNING);
- trigger_error('Warning', E_USER_WARNING);
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/SerializerTest.php b/lib/sentry/raven/test/Raven/Tests/SerializerTest.php
deleted file mode 100644
index af15713..0000000
--- a/lib/sentry/raven/test/Raven/Tests/SerializerTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-assertEquals(array('1', '2', '3'), $result);
- }
-
- public function testObjectsAreStrings()
- {
- $input = new Raven_StacktraceTestObject();
- $result = Raven_Serializer::serialize($input);
- $this->assertEquals('Object Raven_StacktraceTestObject', $result);
- }
-
- public function testIntsAreInts()
- {
- $input = 1;
- $result = Raven_Serializer::serialize($input);
- $this->assertTrue(is_integer($result));
- $this->assertEquals(1, $result);
- }
-
- public function testRecursionMaxDepth()
- {
- $input = array();
- $input[] = &$input;
- $result = Raven_Serializer::serialize($input, 3);
- $this->assertEquals(array(array(array('Array of length 1'))), $result);
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/StacktraceTest.php b/lib/sentry/raven/test/Raven/Tests/StacktraceTest.php
deleted file mode 100644
index 939a959..0000000
--- a/lib/sentry/raven/test/Raven/Tests/StacktraceTest.php
+++ /dev/null
@@ -1,262 +0,0 @@
- 0) {
- return call_user_func('raven_test_recurse', $times, $callback);
- }
-
- return call_user_func($callback);
-}
-
-function raven_test_create_stacktrace($args=null, $times=3)
-{
- return raven_test_recurse($times, 'debug_backtrace');
-}
-
-class Raven_Tests_StacktraceTest extends PHPUnit_Framework_TestCase
-{
- public function testCanTraceParamContext()
- {
- $stack = raven_test_create_stacktrace(array('biz', 'baz'), 0);
-
- $frame = $stack[2];
- $params = Raven_Stacktrace::get_frame_context($frame);
- $this->assertEquals($params['args'], array('biz', 'baz'));
- $this->assertEquals($params['times'], 0);
- }
-
- public function testSimpleTrace()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testSimpleUnshiftedTrace()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, false);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals('/tmp/a.php', $frame['vars']['param1']);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('friend', $frame['vars']['param1']);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testShiftedCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $vars = array(
- "foo" => "bar",
- "baz" => "zoom"
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, true, $vars);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $this->assertFalse(isset($frame['vars']));
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- $this->assertEquals($vars, $frame['vars']);
- }
-
- public function testDoesNotModifyCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- // PHP's errcontext as passed to the error handler contains REFERENCES to any vars that were in the global scope.
- // Modification of these would be really bad, since if control is returned (non-fatal error) we'll have altered the state of things!
- $originalFoo = "bloopblarp";
- $iAmFoo = $originalFoo;
- $vars = array(
- "foo" => &$iAmFoo
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, true, $vars, 5);
-
- // Check we haven't modified our vars.
- $this->assertEquals($originalFoo, $vars["foo"]);
-
- $frame = $frames[1];
- // Check that we did truncate the variable in our output
- $this->assertEquals(5, strlen($frame['vars']['foo']));
- }
-
- public function testUnshiftedCaptureVars()
- {
- $stack = array(
- array(
- "file" => dirname(__FILE__) . "/resources/a.php",
- "line" => 11,
- "function" => "a_test",
- "args"=> array(
- "friend",
- ),
- ),
- array(
- "file" => dirname(__FILE__) . "/resources/b.php",
- "line" => 3,
- "args"=> array(
- "/tmp/a.php",
- ),
- "function" => "include_once",
- ),
- );
-
- $vars = array(
- "foo" => "bar",
- "baz" => "zoom"
- );
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true, false, $vars);
-
- $frame = $frames[0];
- $this->assertEquals('b.php', $frame["module"]);
- $this->assertEquals(3, $frame["lineno"]);
- $this->assertNull($frame["function"]);
- $this->assertEquals(array('param1' => '/tmp/a.php'), $frame['vars']);
- $this->assertEquals("include_once '/tmp/a.php';", $frame["context_line"]);
- $frame = $frames[1];
- $this->assertEquals('a.php', $frame["module"]);
- $this->assertEquals(11, $frame["lineno"]);
- $this->assertEquals('include_once', $frame["function"]);
- $this->assertEquals($vars, $frame['vars']);
- $this->assertEquals('a_test($foo);', $frame["context_line"]);
- }
-
- public function testDoesFixFrameInfo()
- {
- /**
- * 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.
- */
- $stack = raven_test_create_stacktrace();
-
- $frames = Raven_Stacktrace::get_stack_info($stack, true);
- // just grab the last few frames
- $frames = array_slice($frames, -5);
- $frame = $frames[0];
- $this->assertEquals('StacktraceTest.php:Raven_Tests_StacktraceTest', $frame['module']);
- $this->assertEquals('testDoesFixFrameInfo', $frame['function']);
- $frame = $frames[1];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_create_stacktrace', $frame['function']);
- $frame = $frames[2];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- $frame = $frames[3];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- $frame = $frames[4];
- $this->assertEquals('StacktraceTest.php', $frame['module']);
- $this->assertEquals('raven_test_recurse', $frame['function']);
- }
-}
diff --git a/lib/sentry/raven/test/Raven/Tests/resources/b.php b/lib/sentry/raven/test/Raven/Tests/resources/b.php
deleted file mode 100644
index 50f00e1..0000000
--- a/lib/sentry/raven/test/Raven/Tests/resources/b.php
+++ /dev/null
@@ -1,3 +0,0 @@
-
+
+
+
+
+
+# Sentry for PHP
+
+[![Build Status](https://secure.travis-ci.org/getsentry/sentry-php.png?branch=master)](http://travis-ci.org/getsentry/sentry-php)
+[![Total Downloads](https://img.shields.io/packagist/dt/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry)
+[![Downloads per month](https://img.shields.io/packagist/dm/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry)
+[![Latest stable version](https://img.shields.io/packagist/v/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry)
+[![License](http://img.shields.io/packagist/l/sentry/sentry.svg?style=flat-square)](https://packagist.org/packages/sentry/sentry)
+[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/getsentry/sentry-php/master.svg)](https://scrutinizer-ci.com/g/getsentry/sentry-php/)
+[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/getsentry/sentry-php/master.svg)](https://scrutinizer-ci.com/g/getsentry/sentry-php/)
+
+The Sentry PHP error reporter tracks errors and exceptions that happen during the
+execution of your application and provides instant notification with detailed
+informations needed to prioritize, identify, reproduce and fix each issue. Learn
+more about [automatic PHP error reporting with Sentry](https://sentry.io/for/php/).
+
+## Features
+
+- Automatically report (un)handled exceptions and errors
+- Send customized diagnostic data
+- Process and sanitize data before sending it over the network
+
+## Usage
+
+```php
+// Instantiate a new client with a compatible DSN and install built-in
+// handlers
+$client = (new Raven_Client('http://public:secret@example.com/1'))->install();
+
+// Capture an exception
+$event_id = $client->captureException($ex);
+
+// Give the user feedback
+echo "Sorry, there was an error!";
+echo "Your reference ID is " . $event_id;
+```
+
+For more information, see our [documentation](https://docs.getsentry.com/hosted/clients/php/).
+
+
+## Integration with frameworks
+
+Other packages exists to integrate this SDK into the most common frameworks.
+
+### Official integrations
+
+The following integrations are fully supported and maintained by the Sentry team.
+
+- [Symfony](https://github.com/getsentry/sentry-symfony)
+- [Laravel](https://github.com/getsentry/sentry-laravel)
+
+### 3rd party integrations
+
+The following integrations are available and maintained by members of the Sentry community.
+
+- [Nette](https://github.com/Salamek/raven-nette)
+- [ZendFramework](https://github.com/facile-it/sentry-module)
+- [WordPress](https://wordpress.org/plugins/wp-sentry-integration/)
+- [Drupal](https://www.drupal.org/project/raven)
+- [OpenCart](https://github.com/BurdaPraha/oc_sentry)
+- ... feel free to be famous, create a port to your favourite platform!
+
+## Community
+
+- [Documentation](https://docs.getsentry.com/hosted/clients/php/)
+- [Bug Tracker](http://github.com/getsentry/sentry-php/issues)
+- [Code](http://github.com/getsentry/sentry-php)
+- [Mailing List](https://groups.google.com/group/getsentry)
+- [IRC](irc://irc.freenode.net/sentry) (irc.freenode.net, #sentry)
+
+
+Contributing
+------------
+
+Dependencies are managed through composer:
+
+```
+$ composer install
+```
+
+Tests can then be run via phpunit:
+
+```
+$ vendor/bin/phpunit
+```
+
+
+Tagging a Release
+-----------------
+
+1. Make sure ``CHANGES`` is up to date (add the release date) and ``master`` is green.
+
+2. Create a new branch for the minor version (if not present):
+
+```
+$ git checkout -b releases/1.7.x
+```
+
+3. Update the hardcoded version tag in ``Client.php``:
+
+```
+class Raven_Client
+{
+ const VERSION = '1.7.0';
+}
+```
+
+4. Commit the change:
+
+```
+$ git commit -a -m "1.7.0"
+```
+
+5. Tag the branch:
+
+```
+git tag 1.7.0
+```
+
+6. Push the tag:
+
+```
+git push --tags
+```
+
+7. Switch back to ``master``:
+
+```
+git checkout master
+```
+
+8. Add the next minor release to the ``CHANGES`` file:
+
+```
+## 1.8.0 (unreleased)
+```
+
+9. Update the version in ``Client.php``:
+
+```
+class Raven_Client
+{
+ const VERSION = '1.8.x-dev';
+}
+```
+
+10. Lastly, update the composer version in ``composer.json``:
+
+```
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.8.x-dev"
+ }
+ }
+```
+
+All done! Composer will pick up the tag and configuration automatically.
diff --git a/lib/sentry/raven/bin/raven b/lib/sentry/sentry/bin/sentry
similarity index 89%
rename from lib/sentry/raven/bin/raven
rename to lib/sentry/sentry/bin/sentry
index 9bea261..4694cfc 100755
--- a/lib/sentry/raven/bin/raven
+++ b/lib/sentry/sentry/bin/sentry
@@ -1,4 +1,4 @@
-#!/usr/bin/php
+#!/usr/bin/env php
true,
'curl_method' => 'sync',
+ 'app_path' => realpath(__DIR__ . '/..'),
+ 'base_path' => realpath(__DIR__ . '/..'),
));
$config = get_object_vars($client);
@@ -74,6 +76,10 @@ function cmd_test($dsn)
function main() {
global $argv;
+ if (!isset($argv[1])) {
+ exit('Usage: sentry test ');
+ }
+
$cmd = $argv[1];
switch ($cmd) {
@@ -81,7 +87,7 @@ function main() {
cmd_test(@$argv[2]);
break;
default:
- exit('Usage: raven test ');
+ exit('Usage: sentry test ');
}
}
diff --git a/lib/sentry/sentry/composer.json b/lib/sentry/sentry/composer.json
new file mode 100644
index 0000000..04e6125
--- /dev/null
+++ b/lib/sentry/sentry/composer.json
@@ -0,0 +1,60 @@
+{
+ "name": "sentry/sentry",
+ "type": "library",
+ "description": "A PHP client for Sentry (http://getsentry.com)",
+ "keywords": ["log", "logging"],
+ "homepage": "http://getsentry.com",
+ "license": "BSD-3-Clause",
+ "authors": [
+ {
+ "name": "David Cramer",
+ "email": "dcramer@gmail.com"
+ }
+ ],
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^1.8.0",
+ "phpunit/phpunit": "^4.8 || ^5.0",
+ "monolog/monolog": "*"
+ },
+ "require": {
+ "php": "^5.3|^7.0",
+ "ext-curl": "*"
+ },
+ "suggest": {
+ "ext-hash": "*",
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "immobiliare/sentry-php": "Fork that fixes support for PHP 5.2",
+ "monolog/monolog": "Automatically capture Monolog events as breadcrumbs"
+ },
+ "conflict": {
+ "raven/raven": "*"
+ },
+ "bin": [
+ "bin/sentry"
+ ],
+ "autoload": {
+ "psr-0" : {
+ "Raven_" : "lib/"
+ }
+ },
+ "scripts": {
+ "tests": [
+ "vendor/bin/phpunit --verbose"
+ ],
+ "tests-travis": [
+ "vendor/bin/phpunit --verbose --configuration phpunit.xml --coverage-clover test/clover.xml"
+ ],
+ "tests-report": [
+ "vendor/bin/phpunit --verbose --configuration phpunit.xml --coverage-html test/html-report"
+ ],
+ "phpcs": [
+ "vendor/bin/php-cs-fixer fix --config-file=.php_cs --verbose --diff --dry-run"
+ ]
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.8.x-dev"
+ }
+ }
+}
diff --git a/lib/sentry/raven/docs/Makefile b/lib/sentry/sentry/docs/Makefile
similarity index 100%
rename from lib/sentry/raven/docs/Makefile
rename to lib/sentry/sentry/docs/Makefile
diff --git a/lib/sentry/raven/docs/conf.py b/lib/sentry/sentry/docs/conf.py
similarity index 95%
rename from lib/sentry/raven/docs/conf.py
rename to lib/sentry/sentry/docs/conf.py
index 5f93364..04ee267 100644
--- a/lib/sentry/raven/docs/conf.py
+++ b/lib/sentry/sentry/docs/conf.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# raven-php documentation build configuration file, created by
+# sentry-php documentation build configuration file, created by
# sphinx-quickstart on Mon Jan 21 21:04:27 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
@@ -40,7 +40,7 @@
master_doc = 'index'
# General information about the project.
-project = u'raven-php'
+project = u'sentry-php'
copyright = u'%s, Functional Software Inc.' % datetime.date.today().year
# The version info for the project you're documenting, acts as replacement for
@@ -164,7 +164,7 @@
#html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'raven-phpdoc'
+htmlhelp_basename = 'sentry-phpdoc'
# -- Options for LaTeX output --------------------------------------------------
@@ -183,7 +183,7 @@
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'raven-php.tex', u'raven-php Documentation',
+ ('index', 'sentry-php.tex', u'sentry-php Documentation',
u'Functional Software Inc.', 'manual'),
]
@@ -213,7 +213,7 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- ('index', 'raven-php', u'raven-php Documentation',
+ ('index', 'sentry-php', u'sentry-php Documentation',
[u'Functional Software Inc.'], 1)
]
@@ -227,8 +227,8 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'raven-php', u'raven-php Documentation',
- u'Functional Software Inc.', 'raven-php', 'One line description of project.',
+ ('index', 'sentry-php', u'sentry-php Documentation',
+ u'Functional Software Inc.', 'sentry-php', 'One line description of project.',
'Miscellaneous'),
]
diff --git a/lib/sentry/raven/docs/config.rst b/lib/sentry/sentry/docs/config.rst
similarity index 56%
rename from lib/sentry/raven/docs/config.rst
rename to lib/sentry/sentry/docs/config.rst
index 7460325..ddfbaba 100644
--- a/lib/sentry/raven/docs/config.rst
+++ b/lib/sentry/sentry/docs/config.rst
@@ -32,6 +32,109 @@ The following settings are available for the client:
'php_version' => phpversion(),
)
+ .. code-block:: php
+
+ $client->tags_context(array(
+ 'php_version' => phpversion(),
+ ));
+
+.. describe:: release
+
+ The version of your application (e.g. git SHA)
+
+ .. code-block:: php
+
+ 'release' => MyApp::getReleaseVersion(),
+
+ .. code-block:: php
+
+ $client->setRelease(MyApp::getReleaseVersion());
+
+.. describe:: environment
+
+ The environment your application is running in.
+
+ .. code-block:: php
+
+ 'environment' => 'production',
+
+ .. code-block:: php
+
+ $client->setEnvironment('production');
+
+.. describe:: app_path
+
+ The root path to your application code.
+
+ .. code-block:: php
+
+ 'app_path' => app_root(),
+
+ .. code-block:: php
+
+ $client->setAppPath(app_root());
+
+.. describe:: excluded_app_paths
+
+ Paths to exclude from app_path detection.
+
+ .. code-block:: php
+
+ 'excluded_app_paths' => array(app_root() . '/cache'),
+
+ .. code-block:: php
+
+ $client->setExcludedAppPaths(array(app_root() . '/cache'));
+
+.. describe:: prefixes
+
+ Prefixes which should be stripped from filenames to create relative
+ paths.
+
+ .. code-block:: php
+
+ 'prefixes' => array(
+ '/www/php/lib',
+ ),
+
+ .. code-block:: php
+
+ $client->setPrefixes(array(
+ '/www/php/lib',
+ ));
+
+.. describe:: sample_rate
+
+ The sampling factor to apply to events. A value of 0.00 will deny sending
+ any events, and a value of 1.00 will send 100% of events.
+
+ .. code-block:: php
+
+ // send 50% of events
+ 'sample_rate' => 0.5,
+
+.. describe:: send_callback
+
+ A function which will be called whenever data is ready to be sent. Within
+ the function you can mutate the data, or alternatively return ``false`` to
+ instruct the SDK to not send the event.
+
+ .. code-block:: php
+
+ 'send_callback' => function($data) {
+ // strip HTTP data
+ @unset($data['request']);
+ },
+
+ .. code-block:: php
+
+ $client->setSendCallback(function($data) {
+ // dont send events if POST
+ if ($_SERVER['REQUEST_METHOD'] === 'POST')
+ {
+ return false;
+ }
+ });
.. describe:: curl_method
@@ -52,6 +155,30 @@ The following settings are available for the client:
Specify the path to the curl binary to be used with the 'exec' curl
method.
+.. describe:: transport
+
+ Set a custom transport to override how Sentry events are sent upstream.
+
+ .. code-block:: php
+
+ 'transport' => function($client, $data) {
+ $myHttpClient->send(array(
+ 'url' => $client->getServerEndpoint(),
+ 'method' => 'POST',
+ 'headers' => array(
+ 'Content-Encoding' => 'gzip',
+ 'Content-Type' => 'application/octet-stream',
+ 'User-Agent' => $client->getUserAgent(),
+ 'X-Sentry-Auth' => $client->getAuthHeader(),
+ ),
+ 'body' => gzipCompress(jsonEncode($data)),
+ ))
+ },
+
+ .. code-block:: php
+
+ $client->setTransport(...);
+
.. describe:: trace
Set this to ``false`` to disable reflection tracing (function calling
@@ -114,7 +241,7 @@ The following settings are available for the client:
)
)
-.. _raven-php-request-context:
+.. _sentry-php-request-context:
Providing Request Context
-------------------------
diff --git a/lib/sentry/raven/docs/index.rst b/lib/sentry/sentry/docs/index.rst
similarity index 77%
rename from lib/sentry/raven/docs/index.rst
rename to lib/sentry/sentry/docs/index.rst
index b1ce2d5..9f04540 100644
--- a/lib/sentry/raven/docs/index.rst
+++ b/lib/sentry/sentry/docs/index.rst
@@ -1,7 +1,7 @@
.. sentry:edition:: self
- Raven-PHP
- =========
+ Sentry-PHP
+ ==========
.. sentry:edition:: on-premise, hosted
@@ -10,7 +10,7 @@
PHP
===
-Raven-PHP is a PHP client for Sentry supporting PHP 5.3 or higher. It'a
+The PHP SDK for Sentry supports PHP 5.3 and higher. It's
available as a BSD licensed Open Source library.
Installation
@@ -19,12 +19,12 @@ Installation
There are various ways to install the PHP integration for Sentry. The
recommended way is to use `Composer `__::
- $ composer require "raven/raven"
+ $ composer require "sentry/sentry"
Alternatively you can manually install it:
-1. Download and extract the latest `raven-php
- `__ archive
+1. Download and extract the latest `sentry-php
+ `__ archive
to your PHP project.
2. Require the autoloader in your application:
@@ -33,8 +33,6 @@ Alternatively you can manually install it:
require_once '/path/to/Raven/library/Raven/Autoloader.php';
Raven_Autoloader::register();
-For more methods have a look at :ref:`raven-php-advanced-installation`.
-
Configuration
-------------
@@ -70,7 +68,7 @@ automatically with all events. For instance you can use the
'email' => $USER->getEmail()
));
-For more information see :ref:`raven-php-request-context`.
+For more information see :ref:`sentry-php-request-context`.
Deep Dive
---------
@@ -81,12 +79,11 @@ Want more? Have a look at the full documentation for more information.
:maxdepth: 2
:titlesonly:
- advanced
usage
config
integrations/index
Resources:
-* `Bug Tracker `_
-* `Github Project `_
+* `Bug Tracker `_
+* `Github Project `_
diff --git a/lib/sentry/raven/docs/integrations/index.rst b/lib/sentry/sentry/docs/integrations/index.rst
similarity index 100%
rename from lib/sentry/raven/docs/integrations/index.rst
rename to lib/sentry/sentry/docs/integrations/index.rst
diff --git a/lib/sentry/sentry/docs/integrations/laravel.rst b/lib/sentry/sentry/docs/integrations/laravel.rst
new file mode 100644
index 0000000..acd72a3
--- /dev/null
+++ b/lib/sentry/sentry/docs/integrations/laravel.rst
@@ -0,0 +1,315 @@
+Laravel
+=======
+
+Laravel is supported via a native package, `sentry-laravel `_.
+
+Laravel 5.x
+-----------
+
+Install the ``sentry/sentry-laravel`` package:
+
+.. code-block:: bash
+
+ $ composer require sentry/sentry-laravel
+
+If you're on Laravel 5.4 or earlier, you'll need to add the following to your ``config/app.php`` (for Laravel 5.5+ these will be auto-discovered by Laravel):
+
+.. code-block:: php
+
+ 'providers' => array(
+ // ...
+ Sentry\SentryLaravel\SentryLaravelServiceProvider::class,
+ )
+
+ 'aliases' => array(
+ // ...
+ 'Sentry' => Sentry\SentryLaravel\SentryFacade::class,
+ )
+
+
+Add Sentry reporting to ``App/Exceptions/Handler.php``:
+
+.. code-block:: php
+
+ public function report(Exception $exception)
+ {
+ if (app()->bound('sentry') && $this->shouldReport($exception)) {
+ app('sentry')->captureException($exception);
+ }
+
+ parent::report($exception);
+ }
+
+Create the Sentry configuration file (``config/sentry.php``):
+
+.. code-block:: bash
+
+ $ php artisan vendor:publish --provider="Sentry\SentryLaravel\SentryLaravelServiceProvider"
+
+
+Add your DSN to ``.env``:
+
+.. code-block:: bash
+
+ SENTRY_DSN=___DSN___
+
+Finally, if you wish to wire up User Feedback, you can do so by creating a custom
+error view in `resources/views/errors/500.blade.php`.
+
+For Laravel 5 up to 5.4 you need to open up ``App/Exceptions/Handler.php`` and extend the
+``render`` method to make sure the 500 error is rendered as a view correctly, in 5.5+ this
+step is not required anymore an you can skip ahead to the next one:
+
+.. code-block:: php
+
+ bound('sentry') && $this->shouldReport($exception)) {
+ app('sentry')->captureException($exception);
+ }
+
+ parent::report($exception);
+ }
+
+ public function render($request, Exception $exception)
+ {
+ // Convert all non-http exceptions to a proper 500 http exception
+ // if we don't do this exceptions are shown as a default template
+ // instead of our own view in resources/views/errors/500.blade.php
+ if ($this->shouldReport($exception) && !$this->isHttpException($exception) && !config('app.debug')) {
+ $exception = new HttpException(500, 'Whoops!');
+ }
+
+ return parent::render($request, $exception);
+ }
+ }
+
+Next, create ``resources/views/errors/500.blade.php``, and embed the feedback code:
+
+.. code-block:: html
+
+
+
Something went wrong.
+
+ @if(app()->bound('sentry') && !empty(Sentry::getLastEventID()))
+
Error ID: {{ Sentry::getLastEventID() }}
+
+
+
+
+
+ @endif
+
+
+That's it!
+
+Laravel 4.x
+-----------
+
+Install the ``sentry/sentry-laravel`` package:
+
+.. code-block:: bash
+
+ $ composer require sentry/sentry-laravel
+
+Add the Sentry service provider and facade in ``config/app.php``:
+
+.. code-block:: php
+
+ 'providers' => array(
+ // ...
+ 'Sentry\SentryLaravel\SentryLaravelServiceProvider',
+ )
+
+ 'aliases' => array(
+ // ...
+ 'Sentry' => 'Sentry\SentryLaravel\SentryFacade',
+ )
+
+Create the Sentry configuration file (``config/sentry.php``):
+
+.. code-block:: php
+
+ $ php artisan config:publish sentry/sentry-laravel
+
+Add your DSN to ``config/sentry.php``:
+
+.. code-block:: php
+
+ '___DSN___',
+
+ // ...
+ );
+
+If you wish to wire up Sentry anywhere outside of the standard error handlers, or
+if you need to configure additional settings, you can access the Sentry instance
+through ``$app``:
+
+.. code-block:: php
+
+ $app['sentry']->setRelease(Git::sha());
+
+Lumen 5.x
+---------
+
+Install the ``sentry/sentry-laravel`` package:
+
+.. code-block:: bash
+
+ $ composer require sentry/sentry-laravel
+
+Register Sentry in ``bootstrap/app.php``:
+
+.. code-block:: php
+
+ $app->register('Sentry\SentryLaravel\SentryLumenServiceProvider');
+
+ # Sentry must be registered before routes are included
+ require __DIR__ . '/../app/Http/routes.php';
+
+Add Sentry reporting to ``app/Exceptions/Handler.php``:
+
+.. code-block:: php
+
+ public function report(Exception $e)
+ {
+ if (app()->bound('sentry') && $this->shouldReport($e)) {
+ app('sentry')->captureException($e);
+ }
+
+ parent::report($e);
+ }
+
+Create the Sentry configuration file (``config/sentry.php``):
+
+.. code-block:: php
+
+ '___DSN___',
+
+ // capture release as git sha
+ // 'release' => trim(exec('git log --pretty="%h" -n1 HEAD')),
+ );
+
+Testing with Artisan
+--------------------
+
+You can test your configuration using the provided ``artisan`` command:
+
+.. code-block:: bash
+
+ $ php artisan sentry:test
+ [sentry] Client configuration:
+ -> server: https://app.getsentry.com/api/3235/store/
+ -> project: 3235
+ -> public_key: e9ebbd88548a441288393c457ec90441
+ -> secret_key: 399aaee02d454e2ca91351f29bdc3a07
+ [sentry] Generating test event
+ [sentry] Sending test event with ID: 5256614438cf4e0798dc9688e9545d94
+
+Adding Context
+--------------
+
+The mechanism to add context will vary depending on which version of Laravel you're using, but the general approach is the same. Find a good entry point to your application in which the context you want to add is available, ideally early in the process.
+
+In the following example, we'll use a middleware:
+
+.. code-block:: php
+
+ namespace App\Http\Middleware;
+
+ use Closure;
+
+ class SentryContext
+ {
+ /**
+ * Handle an incoming request.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @param \Closure $next
+ *
+ * @return mixed
+ */
+ public function handle($request, Closure $next)
+ {
+ if (app()->bound('sentry')) {
+ /** @var \Raven_Client $sentry */
+ $sentry = app('sentry');
+
+ // Add user context
+ if (auth()->check()) {
+ $sentry->user_context([...]);
+ } else {
+ $sentry->user_context(['id' => null]);
+ }
+
+ // Add tags context
+ $sentry->tags_context([...]);
+ }
+
+ return $next($request);
+ }
+ }
+
+Configuration
+-------------
+
+The following settings are available for the client:
+
+.. describe:: dsn
+
+ The DSN to authenticate with Sentry.
+
+ .. code-block:: php
+
+ 'dsn' => '___DSN___',
+
+.. describe:: release
+
+ The version of your application (e.g. git SHA)
+
+ .. code-block:: php
+
+ 'release' => MyApp::getReleaseVersion(),
+
+
+.. describe:: breadcrumbs.sql_bindings
+
+ Capture bindings on SQL queries.
+
+ Defaults to ``true``.
+
+ .. code-block:: php
+
+ 'breadcrumbs.sql_bindings' => false,
+
+
+.. describe:: user_context
+
+ Capture user_context automatically.
+
+ Defaults to ``true``.
+
+ .. code-block:: php
+
+ 'user_context' => false,
+
diff --git a/lib/sentry/raven/docs/integrations/monolog.rst b/lib/sentry/sentry/docs/integrations/monolog.rst
similarity index 69%
rename from lib/sentry/raven/docs/integrations/monolog.rst
rename to lib/sentry/sentry/docs/integrations/monolog.rst
index 732a619..b2d99f8 100644
--- a/lib/sentry/raven/docs/integrations/monolog.rst
+++ b/lib/sentry/sentry/docs/integrations/monolog.rst
@@ -1,11 +1,14 @@
Monolog
=======
+Capturing Errors
+----------------
+
Monolog supports Sentry out of the box, so you'll just need to configure a handler:
.. sourcecode:: php
- $client = new Raven_Client('___DSN___')
+ $client = new Raven_Client('___DSN___');
$handler = new Monolog\Handler\RavenHandler($client);
$handler->setFormatter(new Monolog\Formatter\LineFormatter("%message% %context% %extra%\n"));
@@ -22,7 +25,7 @@ Capturing context can be done via a monolog processor:
$monolog->pushProcessor(function ($record) {
// record the current user
$user = Acme::getCurrentUser();
- $record['user'] = array(
+ $record['context']['user'] = array(
'name' => $user->getName(),
'username' => $user->getUsername(),
'email' => $user->getEmail(),
@@ -36,3 +39,16 @@ Capturing context can be done via a monolog processor:
return $record;
});
+
+
+Breadcrumbs
+-----------
+
+Sentry provides a breadcrumb handler to automatically send logs along as crumbs:
+
+.. sourcecode:: php
+
+ $client = new Raven_Client('___DSN___');
+
+ $handler = new \Raven_Breadcrumbs_MonologHandler($client);
+ $monolog->pushHandler($handler);
diff --git a/lib/sentry/sentry/docs/integrations/symfony2.rst b/lib/sentry/sentry/docs/integrations/symfony2.rst
new file mode 100644
index 0000000..b119164
--- /dev/null
+++ b/lib/sentry/sentry/docs/integrations/symfony2.rst
@@ -0,0 +1,42 @@
+Symfony
+=======
+
+Symfony is supported via the `sentry-symfony `_ package as a native bundle.
+
+Symfony 2+
+----------
+
+Install the ``sentry/sentry-symfony`` package:
+
+.. code-block:: bash
+
+ $ composer require sentry/sentry-symfony
+
+
+Enable the bundle in ``app/AppKernel.php``:
+
+.. code-block:: php
+
+ registerExceptionHandler();
+ $error_handler->registerErrorHandler();
+ $error_handler->registerShutdownFunction();
+
+.. note:: Calling ``install()`` on a Raven_Client instance will automatically
+ register these handlers.
+
+
+Reporting Exceptions
+--------------------
+
+If you want to report exceptions manually you can use the
+`captureException` function.
+
+.. code-block:: php
+
+ // Basic Reporting
+ $sentryClient->captureException($ex);
+
+ // Provide some additional data with an exception
+ $sentryClient->captureException($ex, array(
+ 'extra' => array(
+ 'php_version' => phpversion()
+ ),
+ ));
+
+
+Reporting Other Errors
+----------------------
+
+Sometimes you don't have an actual exception object, but something bad happened and you
+want to report it anyways. This is where `captureMessage` comes in. It
+takes a message and reports it to sentry.
+
+.. code-block:: php
+
+ // Capture a message
+ $sentryClient->captureMessage('my log message');
+
+Note, ``captureMessage`` has a slightly different API than ``captureException`` to support
+parameterized formatting:
+
+.. code-block:: php
+
+ $sentryClient->captureMessage('my %s message', array('log'), array(
+ 'extra' => array(
+ 'foo' => 'bar',
+ ),
+ ));
+
+
+Optional Attributes
+-------------------
+
+With calls to ``captureException`` or ``captureMessage`` additional data
+can be supplied:
+
+.. code-block:: php
+
+ $sentryClient->captureException($ex, array(
+ 'attr' => 'value',
+ ));
+
+
+.. describe:: extra
+
+Additional context for this event. Must be a mapping. Children can be any native JSON type.
+
+.. code-block:: php
+
+ array(
+ 'extra' => array('key' => 'value')
+ )
+
+.. describe:: fingerprint
+
+The fingerprint for grouping this event.
+
+.. code-block:: php
+
+ array(
+ 'fingerprint' => ['{{ default }}', 'other value']
+ )
+
+.. describe:: level
+
+The level of the event. Defaults to ``error``.
+
+.. code-block:: php
+
+ array(
+ 'level' => 'warning'
+ )
+
+Sentry is aware of the following levels:
+
+* debug (the least serious)
+* info
+* warning
+* error
+* fatal (the most serious)
+
+.. describe:: logger
+
+The logger name for the event.
+
+.. code-block:: php
+
+ array(
+ 'logger' => 'default'
+ )
+
+.. describe:: tags
+
+Tags to index with this event. Must be a mapping of strings.
+
+.. code-block:: php
+
+ array(
+ 'tags' => array('key' => 'value')
+ )
+
+.. describe:: user
+
+The acting user.
+
+.. code-block:: php
+
+ array(
+ 'user' => array(
+ 'id' => 42,
+ 'email' => 'clever-girl'
+ )
+ )
+
+Getting Back an Event ID
+------------------------
+
+An event id is a globally unique id for the event that was just sent. This
+event id can be used to find the exact event from within Sentry.
+
+This is often used to display for the user and report an error to customer
+service.
+
+.. code-block:: php
+
+ $sentryClient->getLastEventID();
+
+.. _php-user-feedback:
+
+User Feedback
+-------------
+
+To enable user feedback for crash reports you will need to create an error handler
+which is aware of the last event ID.
+
+.. sourcecode:: php
+
+ captureException($exc);
+
+ return $this->render('500.html', array(
+ 'sentry_event_id' => $event_id,
+ ), 500);
+ }
+ }
+
+Then in your template you can load up the feedback widget:
+
+.. sourcecode:: html+django
+
+
+
+
+ {% if sentry_event_id %}
+
+ {% endif %}
+
+That's it!
+
+For more details on this feature, see the :doc:`User Feedback guide <../../../learn/user-feedback>`.
+
+
+Handling Failures
+-----------------
+
+The SDK attempts to minimize failures, and when they happen will always try to avoid bubbling them up
+to your application. If you do want to know when an event fails to record, you can use the ``getLastError``
+helper:
+
+.. code-block:: php
+
+ if ($sentryClient->getLastError() !== null) {
+ echo "Something went very, very wrong";
+ // $sentryClient->getLastError() contains the error that occurred
+ } else {
+ // Give the user feedback
+ echo "Sorry, there was an error!";
+ echo "Your reference ID is " . $event_id;
+ }
+
+
+Breadcrumbs
+-----------
+
+Sentry supports capturing breadcrumbs -- events that happened prior to an issue.
+
+.. code-block:: php
+
+ $sentryClient->breadcrumbs->record(array(
+ 'message' => 'Authenticating user as ' . $username,
+ 'category' => 'auth',
+ 'level' => 'info',
+ ));
+
+
+Filtering Out Errors
+--------------------
+
+Its common that you might want to prevent automatic capture of certain areas. Ideally you simply would avoid calling out to Sentry in that case, but that's often easier said than done. Instead, you can provide a function which the SDK will call before it sends any data, allowing you both to mutate that data, as well as prevent it from being sent to the server.
+
+.. code-block:: php
+
+ $sentryClient->setSendCallback(function($data) {
+ $ignore_types = array('Symfony\Component\HttpKernel\Exception\NotFoundHttpException');
+
+ if (isset($data['exception']) && in_array($data['exception']['values'][0]['type'], $ignore_types))
+ {
+ return false;
+ }
+ });
+
+
+Error Control Operators
+-----------------------
+
+In PHP its fairly common to use the `suppression operator `_
+to avoid bubbling up handled errors:
+
+.. code-block:: php
+
+ $my_file = @file('non_existent_file');
+
+In these situations, Sentry will never capture the error. If you wish to capture it at that stage
+you'd need to manually call out to the PHP client:
+
+.. code-block:: php
+
+ $my_file = @file('non_existent_file');
+ if (!$my_file) {
+ // ...
+ $sentryClient->captureLastError();
+ }
+
+
+Testing Your Connection
+-----------------------
+
+The PHP client includes a simple helper script to test your connection and
+credentials with the Sentry master server::
+
+ $ bin/sentry test ___DSN___
+ Client configuration:
+ -> server: [___API_URL___]
+ -> project: ___PROJECT_ID___
+ -> public_key: ___PUBLIC_KEY___
+ -> secret_key: ___SECRET_KEY___
+
+ Sending a test event:
+ -> event ID: f1765c9aed4f4ceebe5a93df9eb2d34f
+
+ Done!
diff --git a/lib/sentry/sentry/examples/vanilla/README.md b/lib/sentry/sentry/examples/vanilla/README.md
new file mode 100644
index 0000000..5a32cd6
--- /dev/null
+++ b/lib/sentry/sentry/examples/vanilla/README.md
@@ -0,0 +1,6 @@
+Running this example:
+
+```
+# Run webserver
+php -S localhost:8000
+```
diff --git a/lib/sentry/sentry/examples/vanilla/index.php b/lib/sentry/sentry/examples/vanilla/index.php
new file mode 100644
index 0000000..c96c0af
--- /dev/null
+++ b/lib/sentry/sentry/examples/vanilla/index.php
@@ -0,0 +1,39 @@
+setAppPath(__DIR__)
+ ->setRelease(Raven_Client::VERSION)
+ ->setPrefixes(array(__DIR__))
+ ->install();
+}
+
+function createCrumbs()
+{
+ echo($undefined['foobar']);
+ echo($undefined['bizbaz']);
+}
+
+function createError()
+{
+ 1 / 0;
+}
+
+
+function createException()
+{
+ throw new Exception('example exception');
+}
+
+setupSentry();
+createCrumbs();
+createError();
+createException();
diff --git a/lib/sentry/raven/lib/Raven/Autoloader.php b/lib/sentry/sentry/lib/Raven/Autoloader.php
similarity index 76%
rename from lib/sentry/raven/lib/Raven/Autoloader.php
rename to lib/sentry/sentry/lib/Raven/Autoloader.php
index d5adf1a..f4caa6f 100644
--- a/lib/sentry/raven/lib/Raven/Autoloader.php
+++ b/lib/sentry/sentry/lib/Raven/Autoloader.php
@@ -32,11 +32,13 @@ public static function register()
*/
public static function autoload($class)
{
- if (0 !== strpos($class, 'Raven')) {
+ if (substr($class, 0, 6) !== 'Raven_') {
return;
}
- if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
+ $file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php';
+ if (is_file($file)) {
+ /** @noinspection PhpIncludeInspection */
require $file;
}
}
diff --git a/lib/sentry/sentry/lib/Raven/Breadcrumbs.php b/lib/sentry/sentry/lib/Raven/Breadcrumbs.php
new file mode 100644
index 0000000..9f1eebb
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Breadcrumbs.php
@@ -0,0 +1,76 @@
+size = $size;
+ $this->reset();
+ }
+
+ public function reset()
+ {
+ $this->count = 0;
+ $this->pos = 0;
+ $this->buffer = array();
+ }
+
+ public function record($crumb)
+ {
+ if (empty($crumb['timestamp'])) {
+ $crumb['timestamp'] = microtime(true);
+ }
+ $this->buffer[$this->pos] = $crumb;
+ $this->pos = ($this->pos + 1) % $this->size;
+ $this->count++;
+ }
+
+ /**
+ * @return array[]
+ */
+ public function fetch()
+ {
+ $results = array();
+ for ($i = 0; $i <= ($this->size - 1); $i++) {
+ $idx = ($this->pos + $i) % $this->size;
+ if (isset($this->buffer[$idx])) {
+ $results[] = $this->buffer[$idx];
+ }
+ }
+ return $results;
+ }
+
+ public function is_empty()
+ {
+ return $this->count === 0;
+ }
+
+ public function to_json()
+ {
+ return array(
+ 'values' => $this->fetch(),
+ );
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Breadcrumbs/ErrorHandler.php b/lib/sentry/sentry/lib/Raven/Breadcrumbs/ErrorHandler.php
new file mode 100644
index 0000000..ffb07fd
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Breadcrumbs/ErrorHandler.php
@@ -0,0 +1,45 @@
+ravenClient = $ravenClient;
+ }
+
+ public function handleError($code, $message, $file = '', $line = 0, $context = array())
+ {
+ $this->ravenClient->breadcrumbs->record(array(
+ 'category' => 'error_reporting',
+ 'message' => $message,
+ 'level' => $this->ravenClient->translateSeverity($code),
+ 'data' => array(
+ 'code' => $code,
+ 'line' => $line,
+ 'file' => $file,
+ ),
+ ));
+
+ if ($this->existingHandler !== null) {
+ return call_user_func($this->existingHandler, $code, $message, $file, $line, $context);
+ } else {
+ return false;
+ }
+ }
+
+ public function install()
+ {
+ $this->existingHandler = set_error_handler(array($this, 'handleError'), E_ALL);
+ return $this;
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Breadcrumbs/MonologHandler.php b/lib/sentry/sentry/lib/Raven/Breadcrumbs/MonologHandler.php
new file mode 100644
index 0000000..52a658d
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Breadcrumbs/MonologHandler.php
@@ -0,0 +1,101 @@
+ Raven_Client::DEBUG,
+ Logger::INFO => Raven_Client::INFO,
+ Logger::NOTICE => Raven_Client::INFO,
+ Logger::WARNING => Raven_Client::WARNING,
+ Logger::ERROR => Raven_Client::ERROR,
+ Logger::CRITICAL => Raven_Client::FATAL,
+ Logger::ALERT => Raven_Client::FATAL,
+ Logger::EMERGENCY => Raven_Client::FATAL,
+ );
+
+ protected $excMatch = '/^exception \'([^\']+)\' with message \'(.+)\' in .+$/s';
+
+ /**
+ * @var Raven_Client the client object that sends the message to the server
+ */
+ protected $ravenClient;
+
+ /**
+ * @param Raven_Client $ravenClient
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->ravenClient = $ravenClient;
+ }
+
+ /**
+ * @param string $message
+ * @return array|null
+ */
+ protected function parseException($message)
+ {
+ if (preg_match($this->excMatch, $message, $matches)) {
+ return array($matches[1], $matches[2]);
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ // sentry uses the 'nobreadcrumb' attribute to skip reporting
+ if (!empty($record['context']['nobreadcrumb'])) {
+ return;
+ }
+
+ if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
+ /**
+ * @var Exception $exc
+ */
+ $exc = $record['context']['exception'];
+ $crumb = array(
+ 'type' => 'error',
+ 'level' => $this->logLevels[$record['level']],
+ 'category' => $record['channel'],
+ 'data' => array(
+ 'type' => get_class($exc),
+ 'value' => $exc->getMessage(),
+ ),
+ );
+ } else {
+ // TODO(dcramer): parse exceptions out of messages and format as above
+ if ($error = $this->parseException($record['message'])) {
+ $crumb = array(
+ 'type' => 'error',
+ 'level' => $this->logLevels[$record['level']],
+ 'category' => $record['channel'],
+ 'data' => array(
+ 'type' => $error[0],
+ 'value' => $error[1],
+ ),
+ );
+ } else {
+ $crumb = array(
+ 'level' => $this->logLevels[$record['level']],
+ 'category' => $record['channel'],
+ 'message' => $record['message'],
+ );
+ }
+ }
+
+ $this->ravenClient->breadcrumbs->record($crumb);
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Client.php b/lib/sentry/sentry/lib/Raven/Client.php
new file mode 100644
index 0000000..5b37844
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Client.php
@@ -0,0 +1,1438 @@
+logger = Raven_Util::get($options, 'logger', 'php');
+ $this->server = Raven_Util::get($options, 'server');
+ $this->secret_key = Raven_Util::get($options, 'secret_key');
+ $this->public_key = Raven_Util::get($options, 'public_key');
+ $this->project = Raven_Util::get($options, 'project', 1);
+ $this->auto_log_stacks = (bool) Raven_Util::get($options, 'auto_log_stacks', false);
+ $this->name = Raven_Util::get($options, 'name', Raven_Compat::gethostname());
+ $this->site = Raven_Util::get($options, 'site', self::_server_variable('SERVER_NAME'));
+ $this->tags = Raven_Util::get($options, 'tags', array());
+ $this->release = Raven_Util::get($options, 'release', null);
+ $this->environment = Raven_Util::get($options, 'environment', null);
+ $this->sample_rate = Raven_Util::get($options, 'sample_rate', 1);
+ $this->trace = (bool) Raven_Util::get($options, 'trace', true);
+ $this->timeout = Raven_Util::get($options, 'timeout', 2);
+ $this->message_limit = Raven_Util::get($options, 'message_limit', self::MESSAGE_LIMIT);
+ $this->exclude = Raven_Util::get($options, 'exclude', array());
+ $this->severity_map = null;
+ $this->http_proxy = Raven_Util::get($options, 'http_proxy');
+ $this->extra_data = Raven_Util::get($options, 'extra', array());
+ $this->send_callback = Raven_Util::get($options, 'send_callback', null);
+ $this->curl_method = Raven_Util::get($options, 'curl_method', 'sync');
+ $this->curl_path = Raven_Util::get($options, 'curl_path', 'curl');
+ $this->curl_ipv4 = Raven_Util::get($options, 'curl_ipv4', true);
+ $this->ca_cert = Raven_Util::get($options, 'ca_cert', static::get_default_ca_cert());
+ $this->verify_ssl = Raven_Util::get($options, 'verify_ssl', true);
+ $this->curl_ssl_version = Raven_Util::get($options, 'curl_ssl_version');
+ $this->trust_x_forwarded_proto = Raven_Util::get($options, 'trust_x_forwarded_proto');
+ $this->transport = Raven_Util::get($options, 'transport', null);
+ $this->mb_detect_order = Raven_Util::get($options, 'mb_detect_order', null);
+ $this->error_types = Raven_Util::get($options, 'error_types', null);
+
+ // app path is used to determine if code is part of your application
+ $this->setAppPath(Raven_Util::get($options, 'app_path', null));
+ $this->setExcludedAppPaths(Raven_Util::get($options, 'excluded_app_paths', null));
+ // a list of prefixes used to coerce absolute paths into relative
+ $this->setPrefixes(Raven_Util::get($options, 'prefixes', static::getDefaultPrefixes()));
+ $this->processors = $this->setProcessorsFromOptions($options);
+
+ $this->_lasterror = null;
+ $this->_last_sentry_error = null;
+ $this->_curl_instance = null;
+ $this->_last_event_id = null;
+ $this->_user = null;
+ $this->_pending_events = array();
+ $this->context = new Raven_Context();
+ $this->breadcrumbs = new Raven_Breadcrumbs();
+ $this->_shutdown_function_has_been_set = false;
+
+ $this->sdk = Raven_Util::get($options, 'sdk', array(
+ 'name' => 'sentry-php',
+ 'version' => self::VERSION,
+ ));
+ $this->serializer = new Raven_Serializer($this->mb_detect_order);
+ $this->reprSerializer = new Raven_ReprSerializer($this->mb_detect_order);
+
+ if ($this->curl_method == 'async') {
+ $this->_curl_handler = new Raven_CurlHandler($this->get_curl_options());
+ }
+
+ $this->transaction = new Raven_TransactionStack();
+ if (static::is_http_request() && isset($_SERVER['PATH_INFO'])) {
+ // @codeCoverageIgnoreStart
+ $this->transaction->push($_SERVER['PATH_INFO']);
+ // @codeCoverageIgnoreEnd
+ }
+
+ if (Raven_Util::get($options, 'install_default_breadcrumb_handlers', true)) {
+ $this->registerDefaultBreadcrumbHandlers();
+ }
+
+ if (Raven_Util::get($options, 'install_shutdown_handler', true)) {
+ $this->registerShutdownFunction();
+ }
+ }
+
+ public function __destruct()
+ {
+ // Force close curl resource
+ $this->close_curl_resource();
+ }
+
+ /**
+ * Destruct all objects contain link to this object
+ *
+ * This method can not delete shutdown handler
+ */
+ public function close_all_children_link()
+ {
+ $this->processors = array();
+ }
+
+ /**
+ * Installs any available automated hooks (such as error_reporting).
+ */
+ public function install()
+ {
+ if ($this->error_handler) {
+ throw new Raven_Exception(sprintf('%s->install() must only be called once', get_class($this)));
+ }
+ $this->error_handler = new Raven_ErrorHandler($this, false, $this->error_types);
+ $this->error_handler->registerExceptionHandler();
+ $this->error_handler->registerErrorHandler();
+ $this->error_handler->registerShutdownFunction();
+ return $this;
+ }
+
+ public function getRelease()
+ {
+ return $this->release;
+ }
+
+ public function setRelease($value)
+ {
+ $this->release = $value;
+ return $this;
+ }
+
+ public function getEnvironment()
+ {
+ return $this->environment;
+ }
+
+ public function setEnvironment($value)
+ {
+ $this->environment = $value;
+ return $this;
+ }
+
+ private static function getDefaultPrefixes()
+ {
+ $value = get_include_path();
+ return explode(PATH_SEPARATOR, $value);
+ }
+
+ private static function _convertPath($value)
+ {
+ $path = @realpath($value);
+ if ($path === false) {
+ $path = $value;
+ }
+ // we need app_path to have a trailing slash otherwise
+ // base path detection becomes complex if the same
+ // prefix is matched
+ if (substr($path, 0, 1) === DIRECTORY_SEPARATOR && substr($path, -1) !== DIRECTORY_SEPARATOR) {
+ $path = $path.DIRECTORY_SEPARATOR;
+ }
+ return $path;
+ }
+
+ public function getAppPath()
+ {
+ return $this->app_path;
+ }
+
+ public function setAppPath($value)
+ {
+ if ($value) {
+ $this->app_path = static::_convertPath($value);
+ } else {
+ $this->app_path = null;
+ }
+ return $this;
+ }
+
+ public function getExcludedAppPaths()
+ {
+ return $this->excluded_app_paths;
+ }
+
+ public function setExcludedAppPaths($value)
+ {
+ $this->excluded_app_paths = $value ? array_map(array($this, '_convertPath'), $value) : null;
+ return $this;
+ }
+
+ public function getPrefixes()
+ {
+ return $this->prefixes;
+ }
+
+ /**
+ * @param array $value
+ * @return Raven_Client
+ */
+ public function setPrefixes($value)
+ {
+ $this->prefixes = $value ? array_map(array($this, '_convertPath'), $value) : $value;
+ return $this;
+ }
+
+ public function getSendCallback()
+ {
+ return $this->send_callback;
+ }
+
+ public function setSendCallback($value)
+ {
+ $this->send_callback = $value;
+ return $this;
+ }
+
+ public function getTransport()
+ {
+ return $this->transport;
+ }
+
+ public function getServerEndpoint($value = '')
+ {
+ return $this->server;
+ }
+
+ public static function getUserAgent()
+ {
+ return 'sentry-php/' . self::VERSION;
+ }
+
+ /**
+ * Set a custom transport to override how Sentry events are sent upstream.
+ *
+ * The bound function will be called with ``$client`` and ``$data`` arguments
+ * and is responsible for encoding the data, authenticating, and sending
+ * the data to the upstream Sentry server.
+ *
+ * @param Callable $value Function to be called
+ * @return Raven_Client
+ */
+ public function setTransport($value)
+ {
+ $this->transport = $value;
+ return $this;
+ }
+
+ /**
+ * @return string[]|Raven_Processor[]
+ */
+ public static function getDefaultProcessors()
+ {
+ return array(
+ 'Raven_Processor_SanitizeDataProcessor',
+ );
+ }
+
+ /**
+ * Sets the Raven_Processor sub-classes to be used when data is processed before being
+ * sent to Sentry.
+ *
+ * @param $options
+ * @return Raven_Processor[]
+ */
+ public function setProcessorsFromOptions($options)
+ {
+ $processors = array();
+ foreach (Raven_util::get($options, 'processors', static::getDefaultProcessors()) as $processor) {
+ /**
+ * @var Raven_Processor $new_processor
+ * @var Raven_Processor|string $processor
+ */
+ $new_processor = new $processor($this);
+
+ if (isset($options['processorOptions']) && is_array($options['processorOptions'])) {
+ if (isset($options['processorOptions'][$processor])
+ && method_exists($processor, 'setProcessorOptions')
+ ) {
+ $new_processor->setProcessorOptions($options['processorOptions'][$processor]);
+ }
+ }
+ $processors[] = $new_processor;
+ }
+ return $processors;
+ }
+
+ /**
+ * Parses a Raven-compatible DSN and returns an array of its values.
+ *
+ * @param string $dsn Raven compatible DSN
+ * @return array parsed DSN
+ *
+ * @doc http://raven.readthedocs.org/en/latest/config/#the-sentry-dsn
+ */
+ public static function parseDSN($dsn)
+ {
+ $url = parse_url($dsn);
+ $scheme = (isset($url['scheme']) ? $url['scheme'] : '');
+ if (!in_array($scheme, array('http', 'https'))) {
+ throw new InvalidArgumentException(
+ 'Unsupported Sentry DSN scheme: '.
+ (!empty($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(
+ 'server' => sprintf('%s://%s%s/api/%s/store/', $scheme, $netloc, $path, $project),
+ 'project' => $project,
+ 'public_key' => $username,
+ 'secret_key' => $password,
+ );
+ }
+
+ public function getLastError()
+ {
+ return $this->_lasterror;
+ }
+
+ /**
+ * Given an identifier, returns a Sentry searchable string.
+ *
+ * @param mixed $ident
+ * @return mixed
+ * @codeCoverageIgnore
+ */
+ public function getIdent($ident)
+ {
+ // XXX: We don't calculate checksums yet, so we only have the ident.
+ return $ident;
+ }
+
+ /**
+ * @param string $message The message (primary description) for the event.
+ * @param array $params params to use when formatting the message.
+ * @param string $level Log level group
+ * @param bool|array $stack
+ * @param mixed $vars
+ * @return string|null
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function message($message, $params = array(), $level = self::INFO,
+ $stack = false, $vars = null)
+ {
+ return $this->captureMessage($message, $params, $level, $stack, $vars);
+ }
+
+ /**
+ * @param Exception $exception
+ * @return string|null
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function exception($exception)
+ {
+ return $this->captureException($exception);
+ }
+
+ /**
+ * Log a message to sentry
+ *
+ * @param string $message The message (primary description) for the event.
+ * @param array $params params to use when formatting the message.
+ * @param array $data Additional attributes to pass with this event (see Sentry docs).
+ * @param bool|array $stack
+ * @param mixed $vars
+ * @return string|null
+ */
+ public function captureMessage($message, $params = array(), $data = array(),
+ $stack = false, $vars = null)
+ {
+ // Gracefully handle messages which contain formatting characters, but were not
+ // intended to be used with formatting.
+ if (!empty($params)) {
+ $formatted_message = vsprintf($message, $params);
+ } else {
+ $formatted_message = $message;
+ }
+
+ if ($data === null) {
+ $data = array();
+ // support legacy method of passing in a level name as the third arg
+ } elseif (!is_array($data)) {
+ $data = array(
+ 'level' => $data,
+ );
+ }
+
+ $data['message'] = $formatted_message;
+ $data['sentry.interfaces.Message'] = array(
+ 'message' => $message,
+ 'params' => $params,
+ 'formatted' => $formatted_message,
+ );
+
+ return $this->capture($data, $stack, $vars);
+ }
+
+ /**
+ * Log an exception to sentry
+ *
+ * @param Exception $exception The Exception object.
+ * @param array $data Additional attributes to pass with this event (see Sentry docs).
+ * @param mixed $logger
+ * @param mixed $vars
+ * @return string|null
+ */
+ public function captureException($exception, $data = null, $logger = null, $vars = null)
+ {
+ $has_chained_exceptions = version_compare(PHP_VERSION, '5.3.0', '>=');
+
+ if (in_array(get_class($exception), $this->exclude)) {
+ return null;
+ }
+
+ if ($data === null) {
+ $data = array();
+ }
+
+ $exc = $exception;
+ do {
+ $exc_data = array(
+ 'value' => $this->serializer->serialize($exc->getMessage()),
+ 'type' => get_class($exc),
+ );
+
+ /**'exception'
+ * Exception::getTrace doesn't store the point at where the exception
+ * was thrown, so we have to stuff it in ourselves. Ugh.
+ */
+ $trace = $exc->getTrace();
+ $frame_where_exception_thrown = array(
+ 'file' => $exc->getFile(),
+ 'line' => $exc->getLine(),
+ );
+
+ array_unshift($trace, $frame_where_exception_thrown);
+
+ // manually trigger autoloading, as it's not done in some edge cases due to PHP bugs (see #60149)
+ if (!class_exists('Raven_Stacktrace')) {
+ // @codeCoverageIgnoreStart
+ spl_autoload_call('Raven_Stacktrace');
+ // @codeCoverageIgnoreEnd
+ }
+
+ $exc_data['stacktrace'] = array(
+ 'frames' => Raven_Stacktrace::get_stack_info(
+ $trace, $this->trace, $vars, $this->message_limit, $this->prefixes,
+ $this->app_path, $this->excluded_app_paths, $this->serializer, $this->reprSerializer
+ ),
+ );
+
+ $exceptions[] = $exc_data;
+ } while ($has_chained_exceptions && $exc = $exc->getPrevious());
+
+ $data['exception'] = array(
+ 'values' => array_reverse($exceptions),
+ );
+ if ($logger !== null) {
+ $data['logger'] = $logger;
+ }
+
+ if (empty($data['level'])) {
+ if (method_exists($exception, 'getSeverity')) {
+ $data['level'] = $this->translateSeverity($exception->getSeverity());
+ } else {
+ $data['level'] = self::ERROR;
+ }
+ }
+
+ return $this->capture($data, $trace, $vars);
+ }
+
+
+ /**
+ * Capture the most recent error (obtained with ``error_get_last``).
+ * @return string|null
+ */
+ public function captureLastError()
+ {
+ if (null === $error = error_get_last()) {
+ return null;
+ }
+
+ $e = new ErrorException(
+ @$error['message'], 0, @$error['type'],
+ @$error['file'], @$error['line']
+ );
+
+ return $this->captureException($e);
+ }
+
+ /**
+ * Log an query to sentry
+ *
+ * @param string|null $query
+ * @param string $level
+ * @param string $engine
+ */
+ public function captureQuery($query, $level = self::INFO, $engine = '')
+ {
+ $data = array(
+ 'message' => $query,
+ 'level' => $level,
+ 'sentry.interfaces.Query' => array(
+ 'query' => $query
+ )
+ );
+
+ if ($engine !== '') {
+ $data['sentry.interfaces.Query']['engine'] = $engine;
+ }
+ return $this->capture($data, false);
+ }
+
+ /**
+ * Return the last captured event's ID or null if none available.
+ */
+ public function getLastEventID()
+ {
+ return $this->_last_event_id;
+ }
+
+ protected function registerDefaultBreadcrumbHandlers()
+ {
+ $handler = new Raven_Breadcrumbs_ErrorHandler($this);
+ $handler->install();
+ }
+
+ protected function registerShutdownFunction()
+ {
+ if (!$this->_shutdown_function_has_been_set) {
+ $this->_shutdown_function_has_been_set = true;
+ register_shutdown_function(array($this, 'onShutdown'));
+ }
+ }
+
+ /**
+ * @return bool
+ * @codeCoverageIgnore
+ */
+ protected static function is_http_request()
+ {
+ return isset($_SERVER['REQUEST_METHOD']) && PHP_SAPI !== 'cli';
+ }
+
+ protected function get_http_data()
+ {
+ $headers = array();
+
+ foreach ($_SERVER as $key => $value) {
+ if (0 === strpos($key, 'HTTP_')) {
+ $header_key =
+ str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
+ $headers[$header_key] = $value;
+ } elseif (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH')) && $value !== '') {
+ $header_key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
+ $headers[$header_key] = $value;
+ }
+ }
+
+ $result = array(
+ 'method' => self::_server_variable('REQUEST_METHOD'),
+ 'url' => $this->get_current_url(),
+ 'query_string' => self::_server_variable('QUERY_STRING'),
+ );
+
+ // dont set this as an empty array as PHP will treat it as a numeric array
+ // instead of a mapping which goes against the defined Sentry spec
+ if (!empty($_POST)) {
+ $result['data'] = $_POST;
+ }
+ if (!empty($_COOKIE)) {
+ $result['cookies'] = $_COOKIE;
+ }
+ if (!empty($headers)) {
+ $result['headers'] = $headers;
+ }
+
+ return array(
+ 'request' => $result,
+ );
+ }
+
+ protected function get_user_data()
+ {
+ $user = $this->context->user;
+ if ($user === null) {
+ if (!function_exists('session_id') || !session_id()) {
+ return array();
+ }
+ $user = array(
+ 'id' => session_id(),
+ );
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
+ $user['ip_address'] = $_SERVER['REMOTE_ADDR'];
+ }
+ if (!empty($_SESSION)) {
+ $user['data'] = $_SESSION;
+ }
+ }
+ return array(
+ 'user' => $user,
+ );
+ }
+
+ protected function get_extra_data()
+ {
+ return $this->extra_data;
+ }
+
+ public function get_default_data()
+ {
+ return array(
+ 'server_name' => $this->name,
+ 'project' => $this->project,
+ 'site' => $this->site,
+ 'logger' => $this->logger,
+ 'tags' => $this->tags,
+ 'platform' => 'php',
+ 'sdk' => $this->sdk,
+ 'culprit' => $this->transaction->peek(),
+ );
+ }
+
+ public function capture($data, $stack = null, $vars = null)
+ {
+ if (!isset($data['timestamp'])) {
+ $data['timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
+ }
+ if (!isset($data['level'])) {
+ $data['level'] = self::ERROR;
+ }
+ if (!isset($data['tags'])) {
+ $data['tags'] = array();
+ }
+ if (!isset($data['extra'])) {
+ $data['extra'] = array();
+ }
+ if (!isset($data['event_id'])) {
+ $data['event_id'] = static::uuid4();
+ }
+
+ if (isset($data['message'])) {
+ $data['message'] = substr($data['message'], 0, $this->message_limit);
+ }
+
+ $data = array_merge($this->get_default_data(), $data);
+
+ if (static::is_http_request()) {
+ $data = array_merge($this->get_http_data(), $data);
+ }
+
+ $data = array_merge($this->get_user_data(), $data);
+
+ if ($this->release) {
+ $data['release'] = $this->release;
+ }
+ if ($this->environment) {
+ $data['environment'] = $this->environment;
+ }
+
+ $data['tags'] = array_merge(
+ $this->tags,
+ $this->context->tags,
+ $data['tags']);
+
+ $data['extra'] = array_merge(
+ $this->get_extra_data(),
+ $this->context->extra,
+ $data['extra']);
+
+ if (empty($data['extra'])) {
+ unset($data['extra']);
+ }
+ if (empty($data['tags'])) {
+ unset($data['tags']);
+ }
+ if (empty($data['user'])) {
+ unset($data['user']);
+ }
+ if (empty($data['request'])) {
+ unset($data['request']);
+ }
+
+ if (!$this->breadcrumbs->is_empty()) {
+ $data['breadcrumbs'] = $this->breadcrumbs->fetch();
+ }
+
+ if ((!$stack && $this->auto_log_stacks) || $stack === true) {
+ $stack = debug_backtrace();
+
+ // Drop last stack
+ array_shift($stack);
+ }
+
+ if (!empty($stack)) {
+ // manually trigger autoloading, as it's not done in some edge cases due to PHP bugs (see #60149)
+ if (!class_exists('Raven_Stacktrace')) {
+ // @codeCoverageIgnoreStart
+ spl_autoload_call('Raven_Stacktrace');
+ // @codeCoverageIgnoreEnd
+ }
+
+ if (!isset($data['stacktrace']) && !isset($data['exception'])) {
+ $data['stacktrace'] = array(
+ 'frames' => Raven_Stacktrace::get_stack_info(
+ $stack, $this->trace, $vars, $this->message_limit, $this->prefixes,
+ $this->app_path, $this->excluded_app_paths, $this->serializer, $this->reprSerializer
+ ),
+ );
+ }
+ }
+
+ $this->sanitize($data);
+ $this->process($data);
+
+ if (!$this->store_errors_for_bulk_send) {
+ $this->send($data);
+ } else {
+ $this->_pending_events[] = $data;
+ }
+
+ $this->_last_event_id = $data['event_id'];
+
+ return $data['event_id'];
+ }
+
+ public function sanitize(&$data)
+ {
+ // attempt to sanitize any user provided data
+ if (!empty($data['request'])) {
+ $data['request'] = $this->serializer->serialize($data['request']);
+ }
+ if (!empty($data['user'])) {
+ $data['user'] = $this->serializer->serialize($data['user'], 3);
+ }
+ if (!empty($data['extra'])) {
+ $data['extra'] = $this->serializer->serialize($data['extra']);
+ }
+ if (!empty($data['tags'])) {
+ foreach ($data['tags'] as $key => $value) {
+ $data['tags'][$key] = @(string)$value;
+ }
+ }
+ if (!empty($data['contexts'])) {
+ $data['contexts'] = $this->serializer->serialize($data['contexts'], 5);
+ }
+ }
+
+ /**
+ * Process data through all defined Raven_Processor sub-classes
+ *
+ * @param array $data Associative array of data to log
+ */
+ public function process(&$data)
+ {
+ foreach ($this->processors as $processor) {
+ $processor->process($data);
+ }
+ }
+
+ public function sendUnsentErrors()
+ {
+ foreach ($this->_pending_events as $data) {
+ $this->send($data);
+ }
+ $this->_pending_events = array();
+ if ($this->store_errors_for_bulk_send) {
+ //in case an error occurs after this is called, on shutdown, send any new errors.
+ $this->store_errors_for_bulk_send = !defined('RAVEN_CLIENT_END_REACHED');
+ }
+ }
+
+ /**
+ * @param array $data
+ * @return string|bool
+ */
+ public function encode(&$data)
+ {
+ $message = Raven_Compat::json_encode($data);
+ if ($message === false) {
+ if (function_exists('json_last_error_msg')) {
+ $this->_lasterror = json_last_error_msg();
+ } else {
+ // @codeCoverageIgnoreStart
+ $this->_lasterror = json_last_error();
+ // @codeCoverageIgnoreEnd
+ }
+ return false;
+ }
+
+ if (function_exists("gzcompress")) {
+ $message = gzcompress($message);
+ }
+
+ // PHP's builtin curl_* function are happy without this, but the exec method requires it
+ $message = base64_encode($message);
+
+ return $message;
+ }
+
+ /**
+ * Wrapper to handle encoding and sending data to the Sentry API server.
+ *
+ * @param array $data Associative array of data to log
+ */
+ public function send(&$data)
+ {
+ if (is_callable($this->send_callback)
+ && call_user_func_array($this->send_callback, array(&$data)) === false
+ ) {
+ // if send_callback returns false, end native send
+ return;
+ }
+
+ if (!$this->server) {
+ return;
+ }
+
+ if ($this->transport) {
+ call_user_func($this->transport, $this, $data);
+ return;
+ }
+
+ // should this event be sampled?
+ if (rand(1, 100) / 100.0 > $this->sample_rate) {
+ return;
+ }
+
+ $message = $this->encode($data);
+
+ $headers = array(
+ 'User-Agent' => static::getUserAgent(),
+ 'X-Sentry-Auth' => $this->getAuthHeader(),
+ 'Content-Type' => 'application/octet-stream'
+ );
+
+ $this->send_remote($this->server, $message, $headers);
+ }
+
+ /**
+ * Send data to Sentry
+ *
+ * @param string $url Full URL to Sentry
+ * @param array|string $data Associative array of data to log
+ * @param array $headers Associative array of headers
+ */
+ protected function send_remote($url, $data, $headers = array())
+ {
+ $parts = parse_url($url);
+ $parts['netloc'] = $parts['host'].(isset($parts['port']) ? ':'.$parts['port'] : null);
+ $this->send_http($url, $data, $headers);
+ }
+
+ protected static function get_default_ca_cert()
+ {
+ return dirname(__FILE__) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'cacert.pem';
+ }
+
+ /**
+ * @return array
+ * @doc http://stackoverflow.com/questions/9062798/php-curl-timeout-is-not-working/9063006#9063006
+ */
+ protected function get_curl_options()
+ {
+ $options = array(
+ CURLOPT_VERBOSE => false,
+ CURLOPT_SSL_VERIFYHOST => 2,
+ CURLOPT_SSL_VERIFYPEER => $this->verify_ssl,
+ CURLOPT_CAINFO => $this->ca_cert,
+ CURLOPT_USERAGENT => 'sentry-php/' . self::VERSION,
+ );
+ if ($this->http_proxy) {
+ $options[CURLOPT_PROXY] = $this->http_proxy;
+ }
+ if ($this->curl_ssl_version) {
+ $options[CURLOPT_SSLVERSION] = $this->curl_ssl_version;
+ }
+ if ($this->curl_ipv4) {
+ $options[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
+ }
+ if (defined('CURLOPT_TIMEOUT_MS')) {
+ // MS is available in curl >= 7.16.2
+ $timeout = max(1, ceil(1000 * $this->timeout));
+
+ // some versions of PHP 5.3 don't have this defined correctly
+ if (!defined('CURLOPT_CONNECTTIMEOUT_MS')) {
+ //see stackoverflow link in the phpdoc
+ define('CURLOPT_CONNECTTIMEOUT_MS', 156);
+ }
+
+ $options[CURLOPT_CONNECTTIMEOUT_MS] = $timeout;
+ $options[CURLOPT_TIMEOUT_MS] = $timeout;
+ } else {
+ // fall back to the lower-precision timeout.
+ $timeout = max(1, ceil($this->timeout));
+ $options[CURLOPT_CONNECTTIMEOUT] = $timeout;
+ $options[CURLOPT_TIMEOUT] = $timeout;
+ }
+ return $options;
+ }
+
+ /**
+ * Send the message over http to the sentry url given
+ *
+ * @param string $url URL of the Sentry instance to log to
+ * @param array|string $data Associative array of data to log
+ * @param array $headers Associative array of headers
+ */
+ protected function send_http($url, $data, $headers = array())
+ {
+ if ($this->curl_method == 'async') {
+ $this->_curl_handler->enqueue($url, $data, $headers);
+ } elseif ($this->curl_method == 'exec') {
+ $this->send_http_asynchronous_curl_exec($url, $data, $headers);
+ } else {
+ $this->send_http_synchronous($url, $data, $headers);
+ }
+ }
+
+ protected function buildCurlCommand($url, $data, $headers)
+ {
+ // TODO(dcramer): support ca_cert
+ $cmd = $this->curl_path.' -X POST ';
+ foreach ($headers as $key => $value) {
+ $cmd .= '-H ' . escapeshellarg($key.': '.$value). ' ';
+ }
+ $cmd .= '-d ' . escapeshellarg($data) . ' ';
+ $cmd .= escapeshellarg($url) . ' ';
+ $cmd .= '-m 5 '; // 5 second timeout for the whole process (connect + send)
+ if (!$this->verify_ssl) {
+ $cmd .= '-k ';
+ }
+ $cmd .= '> /dev/null 2>&1 &'; // ensure exec returns immediately while curl runs in the background
+
+ return $cmd;
+ }
+
+ /**
+ * Send the cURL to Sentry asynchronously. No errors will be returned from cURL
+ *
+ * @param string $url URL of the Sentry instance to log to
+ * @param array|string $data Associative array of data to log
+ * @param array $headers Associative array of headers
+ * @return bool
+ */
+ protected function send_http_asynchronous_curl_exec($url, $data, $headers)
+ {
+ exec($this->buildCurlCommand($url, $data, $headers));
+ return true; // The exec method is just fire and forget, so just assume it always works
+ }
+
+ /**
+ * Send a blocking cURL to Sentry and check for errors from cURL
+ *
+ * @param string $url URL of the Sentry instance to log to
+ * @param array|string $data Associative array of data to log
+ * @param array $headers Associative array of headers
+ * @return bool
+ */
+ protected function send_http_synchronous($url, $data, $headers)
+ {
+ $new_headers = array();
+ foreach ($headers as $key => $value) {
+ array_push($new_headers, $key .': '. $value);
+ }
+ // XXX(dcramer): Prevent 100-continue response form server (Fixes GH-216)
+ $new_headers[] = 'Expect:';
+
+ if (is_null($this->_curl_instance)) {
+ $this->_curl_instance = curl_init($url);
+ }
+ curl_setopt($this->_curl_instance, CURLOPT_POST, 1);
+ curl_setopt($this->_curl_instance, CURLOPT_HTTPHEADER, $new_headers);
+ curl_setopt($this->_curl_instance, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($this->_curl_instance, CURLOPT_RETURNTRANSFER, true);
+
+ $options = $this->get_curl_options();
+ if (isset($options[CURLOPT_CAINFO])) {
+ $ca_cert = $options[CURLOPT_CAINFO];
+ unset($options[CURLOPT_CAINFO]);
+ } else {
+ $ca_cert = null;
+ }
+ curl_setopt_array($this->_curl_instance, $options);
+
+ $buffer = curl_exec($this->_curl_instance);
+
+ $errno = curl_errno($this->_curl_instance);
+ // CURLE_SSL_CACERT || CURLE_SSL_CACERT_BADFILE
+ if ((($errno == 60) || ($errno == 77)) && !is_null($ca_cert)) {
+ curl_setopt($this->_curl_instance, CURLOPT_CAINFO, $ca_cert);
+ $buffer = curl_exec($this->_curl_instance);
+ }
+ if ($errno != 0) {
+ $this->_lasterror = curl_error($this->_curl_instance);
+ $this->_last_sentry_error = null;
+ return false;
+ }
+
+ $code = curl_getinfo($this->_curl_instance, CURLINFO_HTTP_CODE);
+ $success = ($code == 200);
+ if ($success) {
+ $this->_lasterror = null;
+ $this->_last_sentry_error = null;
+ } else {
+ // It'd be nice just to raise an exception here, but it's not very PHP-like
+ $this->_lasterror = curl_error($this->_curl_instance);
+ $this->_last_sentry_error = @json_decode($buffer);
+ }
+
+ return $success;
+ }
+
+ /**
+ * Generate a Sentry authorization header string
+ *
+ * @param string $timestamp Timestamp when the event occurred
+ * @param string $client HTTP client name (not Raven_Client object)
+ * @param string $api_key Sentry API key
+ * @param string $secret_key Sentry API key
+ * @return string
+ */
+ protected static function get_auth_header($timestamp, $client, $api_key, $secret_key)
+ {
+ $header = array(
+ sprintf('sentry_timestamp=%F', $timestamp),
+ "sentry_client={$client}",
+ sprintf('sentry_version=%s', self::PROTOCOL),
+ );
+
+ if ($api_key) {
+ $header[] = "sentry_key={$api_key}";
+ }
+
+ if ($secret_key) {
+ $header[] = "sentry_secret={$secret_key}";
+ }
+
+
+ return sprintf('Sentry %s', implode(', ', $header));
+ }
+
+ public function getAuthHeader()
+ {
+ $timestamp = microtime(true);
+ return $this->get_auth_header(
+ $timestamp, static::getUserAgent(), $this->public_key, $this->secret_key
+ );
+ }
+
+ /**
+ * Generate an uuid4 value
+ *
+ * @return string
+ */
+ protected static 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
+ *
+ * @return string|null
+ */
+ protected function get_current_url()
+ {
+ // When running from commandline the REQUEST_URI is missing.
+ if (!isset($_SERVER['REQUEST_URI'])) {
+ return null;
+ }
+
+ // HTTP_HOST is a client-supplied header that is optional in HTTP 1.0
+ $host = (!empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
+ : (!empty($_SERVER['LOCAL_ADDR']) ? $_SERVER['LOCAL_ADDR']
+ : (!empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '')));
+
+ $httpS = $this->isHttps() ? 's' : '';
+ return "http{$httpS}://{$host}{$_SERVER['REQUEST_URI']}";
+ }
+
+ /**
+ * Was the current request made over https?
+ *
+ * @return bool
+ */
+ protected function isHttps()
+ {
+ if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
+ return true;
+ }
+
+ if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
+ return true;
+ }
+
+ if (!empty($this->trust_x_forwarded_proto) &&
+ !empty($_SERVER['X-FORWARDED-PROTO']) &&
+ $_SERVER['X-FORWARDED-PROTO'] === 'https') {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the value of a key from $_SERVER
+ *
+ * @param string $key Key whose value you wish to obtain
+ * @return string Key's value
+ */
+ private static function _server_variable($key)
+ {
+ if (isset($_SERVER[$key])) {
+ return $_SERVER[$key];
+ }
+
+ return '';
+ }
+
+ /**
+ * Translate a PHP Error constant into a Sentry log level group
+ *
+ * @param string $severity PHP E_$x error constant
+ * @return string Sentry log level group
+ */
+ public function translateSeverity($severity)
+ {
+ if (is_array($this->severity_map) && isset($this->severity_map[$severity])) {
+ return $this->severity_map[$severity];
+ }
+ switch ($severity) {
+ case E_ERROR: return Raven_Client::ERROR;
+ case E_WARNING: return Raven_Client::WARN;
+ case E_PARSE: return Raven_Client::ERROR;
+ case E_NOTICE: return Raven_Client::INFO;
+ case E_CORE_ERROR: return Raven_Client::ERROR;
+ case E_CORE_WARNING: return Raven_Client::WARN;
+ case E_COMPILE_ERROR: return Raven_Client::ERROR;
+ case E_COMPILE_WARNING: return Raven_Client::WARN;
+ case E_USER_ERROR: return Raven_Client::ERROR;
+ case E_USER_WARNING: return Raven_Client::WARN;
+ case E_USER_NOTICE: return Raven_Client::INFO;
+ case E_STRICT: return Raven_Client::INFO;
+ case E_RECOVERABLE_ERROR: return Raven_Client::ERROR;
+ }
+ if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
+ switch ($severity) {
+ case E_DEPRECATED: return Raven_Client::WARN;
+ case E_USER_DEPRECATED: return Raven_Client::WARN;
+ }
+ }
+ return Raven_Client::ERROR;
+ }
+
+ /**
+ * Provide a map of PHP Error constants to Sentry logging groups to use instead
+ * of the defaults in translateSeverity()
+ *
+ * @param array $map
+ */
+ public function registerSeverityMap($map)
+ {
+ $this->severity_map = $map;
+ }
+
+ /**
+ * Convenience function for setting a user's ID and Email
+ *
+ * @deprecated
+ * @param string $id User's ID
+ * @param string|null $email User's email
+ * @param array $data Additional user data
+ * @codeCoverageIgnore
+ */
+ public function set_user_data($id, $email = null, $data = array())
+ {
+ $user = array('id' => $id);
+ if (isset($email)) {
+ $user['email'] = $email;
+ }
+ $this->user_context(array_merge($user, $data));
+ }
+
+ public function onShutdown()
+ {
+ if (!defined('RAVEN_CLIENT_END_REACHED')) {
+ define('RAVEN_CLIENT_END_REACHED', true);
+ }
+ $this->sendUnsentErrors();
+ if ($this->curl_method == 'async') {
+ $this->_curl_handler->join();
+ }
+ }
+
+ /**
+ * Sets user context.
+ *
+ * @param array $data Associative array of user data
+ * @param bool $merge Merge existing context with new context
+ */
+ public function user_context($data, $merge = true)
+ {
+ if ($merge && $this->context->user !== null) {
+ // bail if data is null
+ if (!$data) {
+ return;
+ }
+ $this->context->user = array_merge($this->context->user, $data);
+ } else {
+ $this->context->user = $data;
+ }
+ }
+
+ /**
+ * Appends tags context.
+ *
+ * @param array $data Associative array of tags
+ */
+ public function tags_context($data)
+ {
+ $this->context->tags = array_merge($this->context->tags, $data);
+ }
+
+ /**
+ * Appends additional context.
+ *
+ * @param array $data Associative array of extra data
+ */
+ public function extra_context($data)
+ {
+ $this->context->extra = array_merge($this->context->extra, $data);
+ }
+
+ /**
+ * @param array $processors
+ */
+ public function setProcessors(array $processors)
+ {
+ $this->processors = $processors;
+ }
+
+ /**
+ * @return object|null
+ */
+ public function getLastSentryError()
+ {
+ return $this->_last_sentry_error;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getShutdownFunctionHasBeenSet()
+ {
+ return $this->_shutdown_function_has_been_set;
+ }
+
+ public function close_curl_resource()
+ {
+ if (!is_null($this->_curl_instance)) {
+ curl_close($this->_curl_instance);
+ $this->_curl_instance = null;
+ }
+ }
+}
diff --git a/lib/sentry/raven/lib/Raven/Compat.php b/lib/sentry/sentry/lib/Raven/Compat.php
similarity index 57%
rename from lib/sentry/raven/lib/Raven/Compat.php
rename to lib/sentry/sentry/lib/Raven/Compat.php
index 1970090..4d5f719 100644
--- a/lib/sentry/raven/lib/Raven/Compat.php
+++ b/lib/sentry/sentry/lib/Raven/Compat.php
@@ -25,7 +25,7 @@ public static function _gethostname()
return php_uname('n');
}
- public static function hash_hmac($algo, $data, $key, $raw_output=false)
+ public static function hash_hmac($algo, $data, $key, $raw_output = false)
{
if (function_exists('hash_hmac')) {
return hash_hmac($algo, $data, $key, $raw_output);
@@ -36,9 +36,15 @@ public static function hash_hmac($algo, $data, $key, $raw_output=false)
/**
* Implementation from 'KC Cloyd'.
- * See http://nl2.php.net/manual/en/function.hash-hmac.php
+ *
+ * @param string $algo Name of selected hashing algorithm
+ * @param string $data Message to be hashed
+ * @param string $key Shared secret key used for generating the HMAC variant of the message digest
+ * @param bool $raw_output Must be binary
+ * @return string
+ * @doc http://php.net/manual/en/function.hash-hmac.php
*/
- public static function _hash_hmac($algo, $data, $key, $raw_output=false)
+ public static function _hash_hmac($algo, $data, $key, $raw_output = false)
{
$algo = strtolower($algo);
$pack = 'H'.strlen($algo('test'));
@@ -66,25 +72,55 @@ public static function _hash_hmac($algo, $data, $key, $raw_output=false)
/**
* Note that we discard the options given to be compatible
* with PHP < 5.3
+ *
+ * @param mixed $value
+ * @param int $options
+ * @param int $depth Set the maximum depth
+ * @return string
*/
- public static function json_encode($value, $options=0)
+ public static function json_encode($value, $options = 0, $depth = 512)
{
if (function_exists('json_encode')) {
- return json_encode($value);
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ return json_encode($value);
+ } elseif (version_compare(PHP_VERSION, '5.5.0', '<')) {
+ return json_encode($value, $options);
+ } else {
+ return json_encode($value, $options, $depth);
+ }
}
- return self::_json_encode($value);
+ // @codeCoverageIgnoreStart
+ return self::_json_encode($value, $depth);
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @param mixed $value
+ * @param int $depth Set the maximum depth
+ * @return string|false
+ */
+ public static function _json_encode($value, $depth = 513)
+ {
+ if (ini_get('xdebug.extended_info') !== false) {
+ ini_set('xdebug.max_nesting_level', 2048);
+ }
+ return self::_json_encode_lowlevel($value, $depth);
}
/**
* Implementation taken from
* http://www.mike-griffiths.co.uk/php-json_encode-alternative/
+ *
+ * @param mixed $value
+ * @param int $depth Set the maximum depth
+ * @return string|false
*/
- public static function _json_encode($value)
+ private static function _json_encode_lowlevel($value, $depth)
{
static $jsonReplaces = array(
- array('\\', '/', "\n", "\t", "\r", "\b", "\f", '"'),
- array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
+ array('\\', '/', "\n", "\t", "\r", "\f", '"'),
+ array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\f', '\"'));
if (is_null($value)) {
return 'null';
@@ -97,7 +133,6 @@ public static function _json_encode($value)
}
if (is_scalar($value)) {
-
// Always use '.' for floats.
if (is_float($value)) {
return floatval(str_replace(',', '.', strval($value)));
@@ -108,6 +143,8 @@ public static function _json_encode($value)
} else {
return $value;
}
+ } elseif ($depth <= 1) {
+ return false;
}
$isList = true;
@@ -120,13 +157,21 @@ public static function _json_encode($value)
$result = array();
if ($isList) {
foreach ($value as $v) {
- $result[] = self::_json_encode($v);
+ $this_value = self::_json_encode($v, $depth - 1);
+ if ($this_value === false) {
+ return false;
+ }
+ $result[] = $this_value;
}
return '[' . join(',', $result) . ']';
} else {
foreach ($value as $k => $v) {
- $result[] = self::_json_encode($k) . ':' . self::_json_encode($v);
+ $this_value = self::_json_encode($v, $depth - 1);
+ if ($this_value === false) {
+ return false;
+ }
+ $result[] = self::_json_encode($k, $depth - 1).':'.$this_value;
}
return '{' . join(',', $result) . '}';
diff --git a/lib/sentry/raven/lib/Raven/Context.php b/lib/sentry/sentry/lib/Raven/Context.php
similarity index 68%
rename from lib/sentry/raven/lib/Raven/Context.php
rename to lib/sentry/sentry/lib/Raven/Context.php
index ef56adb..7487da4 100644
--- a/lib/sentry/raven/lib/Raven/Context.php
+++ b/lib/sentry/sentry/lib/Raven/Context.php
@@ -6,6 +6,19 @@
*/
class Raven_Context
{
+ /**
+ * @var array
+ */
+ public $tags;
+ /**
+ * @var array
+ */
+ public $extra;
+ /**
+ * @var array|null
+ */
+ public $user;
+
public function __construct()
{
$this->clear();
diff --git a/lib/sentry/raven/lib/Raven/CurlHandler.php b/lib/sentry/sentry/lib/Raven/CurlHandler.php
similarity index 84%
rename from lib/sentry/raven/lib/Raven/CurlHandler.php
rename to lib/sentry/sentry/lib/Raven/CurlHandler.php
index cce4f8a..0412a86 100644
--- a/lib/sentry/raven/lib/Raven/CurlHandler.php
+++ b/lib/sentry/sentry/lib/Raven/CurlHandler.php
@@ -17,12 +17,12 @@
// TODO(dcramer): handle ca_cert
class Raven_CurlHandler
{
- private $join_timeout;
- private $multi_handle;
- private $options;
- private $requests;
+ protected $join_timeout;
+ protected $multi_handle;
+ protected $options;
+ protected $requests;
- public function __construct($options, $join_timeout=5)
+ public function __construct($options, $join_timeout = 5)
{
$this->options = $options;
$this->multi_handle = curl_multi_init();
@@ -37,7 +37,7 @@ public function __destruct()
$this->join();
}
- public function enqueue($url, $data=null, $headers=array())
+ public function enqueue($url, $data = null, $headers = array())
{
$ch = curl_init();
@@ -69,7 +69,7 @@ public function enqueue($url, $data=null, $headers=array())
return $fd;
}
- public function join($timeout=null)
+ public function join($timeout = null)
{
if (!isset($timeout)) {
$timeout = $this->join_timeout;
@@ -81,11 +81,13 @@ public function join($timeout=null)
break;
}
usleep(10000);
- } while ($timeout !== 0 && time() - $start > $timeout);
+ } while ($timeout !== 0 && time() - $start < $timeout);
}
- // http://se2.php.net/manual/en/function.curl-multi-exec.php
- private function select()
+ /**
+ * @doc http://php.net/manual/en/function.curl-multi-exec.php
+ */
+ protected function select()
{
do {
$mrc = curl_multi_exec($this->multi_handle, $active);
diff --git a/lib/sentry/sentry/lib/Raven/ErrorHandler.php b/lib/sentry/sentry/lib/Raven/ErrorHandler.php
new file mode 100644
index 0000000..21358c1
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/ErrorHandler.php
@@ -0,0 +1,195 @@
+registerExceptionHandler();
+ * $error_handler->registerErrorHandler();
+ * $error_handler->registerShutdownFunction();
+ *
+ * @package raven
+ */
+
+// TODO(dcramer): deprecate default error types in favor of runtime configuration
+// unless a reason can be determined that making them dynamic is better. They
+// currently are not used outside of the fatal handler.
+class Raven_ErrorHandler
+{
+ protected $old_exception_handler;
+ protected $call_existing_exception_handler = false;
+ protected $old_error_handler;
+ protected $call_existing_error_handler = false;
+ protected $reservedMemory;
+ /** @var Raven_Client */
+ protected $client;
+ protected $send_errors_last = false;
+ protected $fatal_error_types = array(
+ E_ERROR,
+ E_PARSE,
+ E_CORE_ERROR,
+ E_CORE_WARNING,
+ E_COMPILE_ERROR,
+ E_COMPILE_WARNING,
+ E_STRICT,
+ );
+
+ /**
+ * @var array
+ * Error types which should be processed by the handler.
+ * A 'null' value implies "whatever error_reporting is at time of error".
+ */
+ protected $error_types = null;
+
+ public function __construct($client, $send_errors_last = false, $error_types = null,
+ $__error_types = null)
+ {
+ // support legacy fourth argument for error types
+ if ($error_types === null) {
+ $error_types = $__error_types;
+ }
+
+ $this->client = $client;
+ $this->error_types = $error_types;
+ $this->fatal_error_types = array_reduce($this->fatal_error_types, array($this, 'bitwiseOr'));
+ if ($send_errors_last) {
+ $this->send_errors_last = true;
+ $this->client->store_errors_for_bulk_send = true;
+ }
+ }
+
+ public function bitwiseOr($a, $b)
+ {
+ return $a | $b;
+ }
+
+ public function handleException($e, $isError = false, $vars = null)
+ {
+ $e->event_id = $this->client->captureException($e, null, null, $vars);
+
+ if (!$isError && $this->call_existing_exception_handler) {
+ if ($this->old_exception_handler !== null) {
+ call_user_func($this->old_exception_handler, $e);
+ } else {
+ throw $e;
+ }
+ }
+ }
+
+ public function handleError($type, $message, $file = '', $line = 0, $context = array())
+ {
+ // http://php.net/set_error_handler
+ // The following error types cannot be handled with a user defined function: E_ERROR,
+ // E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and
+ // most of E_STRICT raised in the file where set_error_handler() is called.
+
+ if (error_reporting() !== 0) {
+ $error_types = $this->error_types;
+ if ($error_types === null) {
+ $error_types = error_reporting();
+ }
+ if ($error_types & $type) {
+ $e = new ErrorException($message, 0, $type, $file, $line);
+ $this->handleException($e, true, $context);
+ }
+ }
+
+ if ($this->call_existing_error_handler) {
+ if ($this->old_error_handler !== null) {
+ return call_user_func(
+ $this->old_error_handler,
+ $type,
+ $message,
+ $file,
+ $line,
+ $context
+ );
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function handleFatalError()
+ {
+ unset($this->reservedMemory);
+
+ if (null === $error = error_get_last()) {
+ return;
+ }
+
+ if ($this->shouldCaptureFatalError($error['type'])) {
+ $e = new ErrorException(
+ @$error['message'], 0, @$error['type'],
+ @$error['file'], @$error['line']
+ );
+ $this->handleException($e, true);
+ }
+ }
+
+ public function shouldCaptureFatalError($type)
+ {
+ return $type & $this->fatal_error_types;
+ }
+
+ /**
+ * Register a handler which will intercept unhandled exceptions and report them to the
+ * associated Sentry client.
+ *
+ * @param bool $call_existing Call any existing exception handlers after processing
+ * this instance.
+ * @return Raven_ErrorHandler
+ */
+ public function registerExceptionHandler($call_existing = true)
+ {
+ $this->old_exception_handler = set_exception_handler(array($this, 'handleException'));
+ $this->call_existing_exception_handler = $call_existing;
+ return $this;
+ }
+
+ /**
+ * Register a handler which will intercept standard PHP errors and report them to the
+ * associated Sentry client.
+ *
+ * @param bool $call_existing Call any existing errors handlers after processing
+ * this instance.
+ * @param array $error_types All error types that should be sent.
+ * @return Raven_ErrorHandler
+ */
+ public function registerErrorHandler($call_existing = true, $error_types = null)
+ {
+ if ($error_types !== null) {
+ $this->error_types = $error_types;
+ }
+ $this->old_error_handler = set_error_handler(array($this, 'handleError'), E_ALL);
+ $this->call_existing_error_handler = $call_existing;
+ return $this;
+ }
+
+ /**
+ * Register a fatal error handler, which will attempt to capture errors which
+ * shutdown the PHP process. These are commonly things like OOM or timeouts.
+ *
+ * @param int $reservedMemorySize Number of kilobytes memory space to reserve,
+ * which is utilized when handling fatal errors.
+ * @return Raven_ErrorHandler
+ */
+ public function registerShutdownFunction($reservedMemorySize = 10)
+ {
+ register_shutdown_function(array($this, 'handleFatalError'));
+
+ $this->reservedMemory = str_repeat('x', 1024 * $reservedMemorySize);
+ return $this;
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Exception.php b/lib/sentry/sentry/lib/Raven/Exception.php
new file mode 100644
index 0000000..a6199f4
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Exception.php
@@ -0,0 +1,4 @@
+client = $client;
+ }
+
+ /**
+ * Override the default processor options
+ *
+ * @param array $options Associative array of processor options
+ */
+ public function setProcessorOptions(array $options)
+ {
+ }
+
+ /**
+ * Process and sanitize data, modifying the existing value if necessary.
+ *
+ * @param array $data Array of log data
+ */
+ abstract public function process(&$data);
+}
diff --git a/lib/sentry/sentry/lib/Raven/Processor/RemoveCookiesProcessor.php b/lib/sentry/sentry/lib/Raven/Processor/RemoveCookiesProcessor.php
new file mode 100644
index 0000000..482f872
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Processor/RemoveCookiesProcessor.php
@@ -0,0 +1,35 @@
+
+ */
+final class Raven_Processor_RemoveCookiesProcessor extends Raven_Processor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function process(&$data)
+ {
+ if (isset($data['request'])) {
+ if (isset($data['request']['cookies'])) {
+ $data['request']['cookies'] = self::STRING_MASK;
+ }
+
+ if (isset($data['request']['headers']) && isset($data['request']['headers']['Cookie'])) {
+ $data['request']['headers']['Cookie'] = self::STRING_MASK;
+ }
+ }
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Processor/RemoveHttpBodyProcessor.php b/lib/sentry/sentry/lib/Raven/Processor/RemoveHttpBodyProcessor.php
new file mode 100644
index 0000000..3952ced
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Processor/RemoveHttpBodyProcessor.php
@@ -0,0 +1,30 @@
+
+ */
+final class Raven_Processor_RemoveHttpBodyProcessor extends Raven_Processor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function process(&$data)
+ {
+ if (isset($data['request'], $data['request']['method']) && in_array(strtoupper($data['request']['method']), array('POST', 'PUT', 'PATCH', 'DELETE'))) {
+ $data['request']['data'] = self::STRING_MASK;
+ }
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Processor/SanitizeDataProcessor.php b/lib/sentry/sentry/lib/Raven/Processor/SanitizeDataProcessor.php
new file mode 100644
index 0000000..44cc77e
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Processor/SanitizeDataProcessor.php
@@ -0,0 +1,160 @@
+fields_re = self::FIELDS_RE;
+ $this->values_re = self::VALUES_RE;
+ $this->session_cookie_name = ini_get('session.name');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setProcessorOptions(array $options)
+ {
+ if (isset($options['fields_re'])) {
+ $this->fields_re = $options['fields_re'];
+ }
+
+ if (isset($options['values_re'])) {
+ $this->values_re = $options['values_re'];
+ }
+ }
+
+ /**
+ * Replace any array values with our mask if the field name or the value matches a respective regex
+ *
+ * @param mixed $item Associative array value
+ * @param string $key Associative array key
+ */
+ public function sanitize(&$item, $key)
+ {
+ if (empty($item)) {
+ return;
+ }
+
+ if (preg_match($this->values_re, $item)) {
+ $item = self::STRING_MASK;
+ }
+
+ if (empty($key)) {
+ return;
+ }
+
+ if (preg_match($this->fields_re, $key)) {
+ $item = self::STRING_MASK;
+ }
+ }
+
+ public function sanitizeException(&$data)
+ {
+ foreach ($data['exception']['values'] as &$value) {
+ $this->sanitizeStacktrace($value['stacktrace']);
+ }
+ }
+
+ public function sanitizeHttp(&$data)
+ {
+ $http = &$data['request'];
+ if (!empty($http['cookies']) && is_array($http['cookies'])) {
+ $cookies = &$http['cookies'];
+ if (!empty($cookies[$this->session_cookie_name])) {
+ $cookies[$this->session_cookie_name] = self::STRING_MASK;
+ }
+ }
+ if (!empty($http['data']) && is_array($http['data'])) {
+ array_walk_recursive($http['data'], array($this, 'sanitize'));
+ }
+ }
+
+ public function sanitizeStacktrace(&$data)
+ {
+ foreach ($data['frames'] as &$frame) {
+ if (empty($frame['vars'])) {
+ continue;
+ }
+ array_walk_recursive($frame['vars'], array($this, 'sanitize'));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(&$data)
+ {
+ if (!empty($data['exception'])) {
+ $this->sanitizeException($data);
+ }
+ if (!empty($data['stacktrace'])) {
+ $this->sanitizeStacktrace($data['stacktrace']);
+ }
+ if (!empty($data['request'])) {
+ $this->sanitizeHttp($data);
+ }
+ if (!empty($data['extra'])) {
+ array_walk_recursive($data['extra'], array($this, 'sanitize'));
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getFieldsRe()
+ {
+ return $this->fields_re;
+ }
+
+ /**
+ * @param string $fields_re
+ */
+ public function setFieldsRe($fields_re)
+ {
+ $this->fields_re = $fields_re;
+ }
+
+ /**
+ * @return string
+ */
+ public function getValuesRe()
+ {
+ return $this->values_re;
+ }
+
+ /**
+ * @param string $values_re
+ */
+ public function setValuesRe($values_re)
+ {
+ $this->values_re = $values_re;
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Processor/SanitizeHttpHeadersProcessor.php b/lib/sentry/sentry/lib/Raven/Processor/SanitizeHttpHeadersProcessor.php
new file mode 100644
index 0000000..c058c1f
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Processor/SanitizeHttpHeadersProcessor.php
@@ -0,0 +1,64 @@
+
+ */
+final class Raven_Processor_SanitizeHttpHeadersProcessor extends Raven_Processor
+{
+ /**
+ * @var string[] $httpHeadersToSanitize The list of HTTP headers to sanitize
+ */
+ private $httpHeadersToSanitize = array();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(Raven_Client $client)
+ {
+ parent::__construct($client);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setProcessorOptions(array $options)
+ {
+ $this->httpHeadersToSanitize = array_merge($this->getDefaultHeaders(), isset($options['sanitize_http_headers']) ? $options['sanitize_http_headers'] : array());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function process(&$data)
+ {
+ if (isset($data['request']) && isset($data['request']['headers'])) {
+ foreach ($data['request']['headers'] as $header => &$value) {
+ if (in_array($header, $this->httpHeadersToSanitize)) {
+ $value = self::STRING_MASK;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the list of default headers that must be sanitized.
+ *
+ * @return string[]
+ */
+ private function getDefaultHeaders()
+ {
+ return array('Authorization', 'Proxy-Authorization', 'X-Csrf-Token', 'X-CSRFToken', 'X-XSRF-TOKEN');
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/Processor/SanitizeStacktraceProcessor.php b/lib/sentry/sentry/lib/Raven/Processor/SanitizeStacktraceProcessor.php
new file mode 100644
index 0000000..96e1526
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/Processor/SanitizeStacktraceProcessor.php
@@ -0,0 +1,39 @@
+
+ */
+class Raven_Processor_SanitizeStacktraceProcessor extends Raven_Processor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function process(&$data)
+ {
+ if (!isset($data['exception'], $data['exception']['values'])) {
+ return;
+ }
+
+ foreach ($data['exception']['values'] as &$exception) {
+ if (!isset($exception['stacktrace'])) {
+ continue;
+ }
+
+ foreach ($exception['stacktrace']['frames'] as &$frame) {
+ unset($frame['pre_context'], $frame['context_line'], $frame['post_context']);
+ }
+ }
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/ReprSerializer.php b/lib/sentry/sentry/lib/Raven/ReprSerializer.php
new file mode 100644
index 0000000..dc70469
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/ReprSerializer.php
@@ -0,0 +1,41 @@
+serializeString($value);
+ }
+ }
+}
diff --git a/lib/sentry/sentry/lib/Raven/SanitizeDataProcessor.php b/lib/sentry/sentry/lib/Raven/SanitizeDataProcessor.php
new file mode 100644
index 0000000..06e7a93
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/SanitizeDataProcessor.php
@@ -0,0 +1,19 @@
+mb_detect_order = $mb_detect_order;
+ }
+ }
+
+ /**
+ * Serialize an object (recursively) into something safe for data
+ * sanitization and encoding.
+ *
+ * @param mixed $value
+ * @param int $max_depth
+ * @param int $_depth
+ * @return string|bool|double|int|null|object|array
+ */
+ public function serialize($value, $max_depth = 3, $_depth = 0)
+ {
+ $className = is_object($value) ? get_class($value) : null;
+ $toArray = is_array($value) || $className === 'stdClass';
+ if ($toArray && $_depth < $max_depth) {
+ $new = array();
+ foreach ($value as $k => $v) {
+ $new[$this->serializeValue($k)] = $this->serialize($v, $max_depth, $_depth + 1);
+ }
+
+ return $new;
+ }
+ return $this->serializeValue($value);
+ }
+
+ protected function serializeString($value)
+ {
+ $value = (string) $value;
+ if (function_exists('mb_detect_encoding')
+ && function_exists('mb_convert_encoding')
+ ) {
+ // we always guarantee this is coerced, even if we can't detect encoding
+ if ($currentEncoding = mb_detect_encoding($value, $this->mb_detect_order)) {
+ $value = mb_convert_encoding($value, 'UTF-8', $currentEncoding);
+ } else {
+ $value = mb_convert_encoding($value, 'UTF-8');
+ }
+ }
+
+ if (strlen($value) > 1024) {
+ $value = substr($value, 0, 1014) . ' {clipped}';
+ }
+
+ return $value;
+ }
+
+ /**
+ * @param mixed $value
+ * @return string|bool|double|int|null
+ */
+ protected function serializeValue($value)
+ {
+ if (is_null($value) || is_bool($value) || is_float($value) || is_integer($value)) {
+ return $value;
+ } elseif (is_object($value) || gettype($value) == 'object') {
+ return 'Object '.get_class($value);
+ } elseif (is_resource($value)) {
+ return 'Resource '.get_resource_type($value);
+ } elseif (is_array($value)) {
+ return 'Array of length ' . count($value);
+ } else {
+ return $this->serializeString($value);
+ }
+ }
+
+
+ /**
+ * @return string
+ * @codeCoverageIgnore
+ */
+ public function getMbDetectOrder()
+ {
+ return $this->mb_detect_order;
+ }
+
+ /**
+ * @param string $mb_detect_order
+ *
+ * @return Raven_Serializer
+ * @codeCoverageIgnore
+ */
+ public function setMbDetectOrder($mb_detect_order)
+ {
+ $this->mb_detect_order = $mb_detect_order;
+
+ return $this;
+ }
+}
diff --git a/lib/sentry/raven/lib/Raven/Stacktrace.php b/lib/sentry/sentry/lib/Raven/Stacktrace.php
similarity index 52%
rename from lib/sentry/raven/lib/Raven/Stacktrace.php
rename to lib/sentry/sentry/lib/Raven/Stacktrace.php
index 964fcf3..10a00ce 100644
--- a/lib/sentry/raven/lib/Raven/Stacktrace.php
+++ b/lib/sentry/sentry/lib/Raven/Stacktrace.php
@@ -13,100 +13,107 @@ class Raven_Stacktrace
'require_once',
);
- public static function get_stack_info($frames, $trace = false, $shiftvars = true, $errcontext = null,
- $frame_var_limit = Raven_Client::MESSAGE_LIMIT)
+ public static function get_stack_info($frames,
+ $trace = false,
+ $errcontext = null,
+ $frame_var_limit = Raven_Client::MESSAGE_LIMIT,
+ $strip_prefixes = null,
+ $app_path = null,
+ $excluded_app_paths = null,
+ Raven_Serializer $serializer = null,
+ Raven_ReprSerializer $reprSerializer = null)
{
+ $serializer = $serializer ?: new Raven_Serializer();
+ $reprSerializer = $reprSerializer ?: new Raven_ReprSerializer();
+
/**
- * 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.
+ * PHP stores calls in the stacktrace, rather than executing context. Sentry
+ * wants to know "when Im calling this code, where am I", and PHP says "I'm
+ * calling this function" not "I'm in this function". Due to that, we shift
+ * the context for a frame up one, meaning the variables (which are the calling
+ * args) come from the previous frame.
*/
$result = array();
for ($i = 0; $i < count($frames); $i++) {
- $frame = $frames[$i];
+ $frame = isset($frames[$i]) ? $frames[$i] : null;
$nextframe = isset($frames[$i + 1]) ? $frames[$i + 1] : null;
if (!array_key_exists('file', $frame)) {
- // XXX: Disable capturing of anonymous functions until we can implement a better grouping mechanism.
- // In our examples these generally didn't help with debugging as the information was found elsewhere
- // within the exception or the stacktrace
- continue;
- // if (isset($frame['args'])) {
- // $args = is_string($frame['args']) ? $frame['args'] : @json_encode($frame['args']);
- // }
- // else {
- // $args = array();
- // }
- // if (!empty($nextframe['class'])) {
- // $context['line'] = sprintf('%s%s%s(%s)',
- // $nextframe['class'], $nextframe['type'], $nextframe['function'],
- // $args);
- // }
- // else {
- // $context['line'] = sprintf('%s(%s)', $nextframe['function'], $args);
- // }
- // $abs_path = '';
- // $context['prefix'] = '';
- // $context['suffix'] = '';
- // $context['filename'] = $filename = '[Anonymous function]';
- // $context['lineno'] = 0;
+ if (!empty($frame['class'])) {
+ $context['line'] = sprintf('%s%s%s',
+ $frame['class'], $frame['type'], $frame['function']);
+ } else {
+ $context['line'] = sprintf('%s(anonymous)', $frame['function']);
+ }
+ $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($nextframe['class'])) {
- $module .= ':' . $nextframe['class'];
- }
-
- if (empty($result) && isset($errcontext)) {
+ // strip base path if present
+ $context['filename'] = self::strip_prefixes($context['filename'], $strip_prefixes);
+ if ($i === 0 && isset($errcontext)) {
// If we've been given an error context that can be used as the vars for the first frame.
$vars = $errcontext;
} else {
if ($trace) {
- if ($shiftvars) {
- $vars = self::get_frame_context($nextframe, $frame_var_limit);
- } else {
- $vars = self::get_caller_frame_context($frame);
- }
+ $vars = self::get_frame_context($nextframe, $frame_var_limit);
} else {
$vars = array();
}
}
- $frame = array(
- 'abs_path' => $abs_path,
+ $data = array(
'filename' => $context['filename'],
'lineno' => (int) $context['lineno'],
- 'module' => $module,
- 'function' => $nextframe['function'],
- 'pre_context' => $context['prefix'],
- 'context_line' => $context['line'],
- 'post_context' => $context['suffix'],
+ 'function' => isset($nextframe['function']) ? $nextframe['function'] : null,
+ 'pre_context' => $serializer->serialize($context['prefix']),
+ 'context_line' => $serializer->serialize($context['line']),
+ 'post_context' => $serializer->serialize($context['suffix']),
);
+
+ // detect in_app based on app path
+ if ($app_path) {
+ $norm_abs_path = @realpath($abs_path) ?: $abs_path;
+ $in_app = (bool)(substr($norm_abs_path, 0, strlen($app_path)) === $app_path);
+ if ($in_app && $excluded_app_paths) {
+ foreach ($excluded_app_paths as $path) {
+ if (substr($norm_abs_path, 0, strlen($path)) === $path) {
+ $in_app = false;
+ break;
+ }
+ }
+ }
+ $data['in_app'] = $in_app;
+ }
+
// dont set this as an empty array as PHP will treat it as a numeric array
// instead of a mapping which goes against the defined Sentry spec
if (!empty($vars)) {
$cleanVars = array();
foreach ($vars as $key => $value) {
+ $value = $reprSerializer->serialize($value);
if (is_string($value) || is_numeric($value)) {
- $cleanVars[$key] = substr($value, 0, $frame_var_limit);
+ $cleanVars[(string)$key] = substr($value, 0, $frame_var_limit);
} else {
- $cleanVars[$key] = $value;
+ $cleanVars[(string)$key] = $value;
}
}
- $frame['vars'] = $cleanVars;
+ $data['vars'] = $cleanVars;
}
- $result[] = $frame;
+ $result[] = $data;
}
return array_reverse($result);
}
- public static function get_caller_frame_context($frame)
+ public static function get_default_context($frame, $frame_arg_limit = Raven_Client::MESSAGE_LIMIT)
{
if (!isset($frame['args'])) {
return array();
@@ -115,7 +122,7 @@ public static function get_caller_frame_context($frame)
$i = 1;
$args = array();
foreach ($frame['args'] as $arg) {
- $args['param'.$i] = $arg;
+ $args['param'.$i] = self::serialize_argument($arg, $frame_arg_limit);
$i++;
}
return $args;
@@ -123,24 +130,23 @@ public static function get_caller_frame_context($frame)
public static function get_frame_context($frame, $frame_arg_limit = Raven_Client::MESSAGE_LIMIT)
{
- // The reflection API seems more appropriate if we associate it with the frame
- // where the function is actually called (since we're treating them as function context)
- if (!isset($frame['function'])) {
- return array();
- }
-
if (!isset($frame['args'])) {
return array();
}
+ // The reflection API seems more appropriate if we associate it with the frame
+ // where the function is actually called (since we're treating them as function context)
+ if (!isset($frame['function'])) {
+ return self::get_default_context($frame, $frame_arg_limit);
+ }
if (strpos($frame['function'], '__lambda_func') !== false) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (isset($frame['class']) && $frame['class'] == 'Closure') {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (strpos($frame['function'], '{closure}') !== false) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
if (in_array($frame['function'], self::$statements)) {
if (empty($frame['args'])) {
@@ -148,7 +154,9 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
return array();
} else {
// Sanitize the file path
- return array($frame['args'][0]);
+ return array(
+ 'param1' => self::serialize_argument($frame['args'][0], $frame_arg_limit),
+ );
}
}
try {
@@ -164,33 +172,57 @@ public static function get_frame_context($frame, $frame_arg_limit = Raven_Client
$reflection = new ReflectionFunction($frame['function']);
}
} catch (ReflectionException $e) {
- return array();
+ return self::get_default_context($frame, $frame_arg_limit);
}
$params = $reflection->getParameters();
$args = array();
foreach ($frame['args'] as $i => $arg) {
+ $arg = self::serialize_argument($arg, $frame_arg_limit);
if (isset($params[$i])) {
// Assign the argument by the parameter name
- if (is_array($arg)) {
- foreach ($arg as $key => $value) {
- if (is_string($value) || is_numeric($value)) {
- $arg[$key] = substr($value, 0, $frame_arg_limit);
- }
- }
- }
$args[$params[$i]->name] = $arg;
} else {
- // TODO: Sentry thinks of these as context locals, so they must be named
- // Assign the argument by number
- // $args[$i] = $arg;
+ $args['param'.$i] = $arg;
}
}
return $args;
}
+ private static function serialize_argument($arg, $frame_arg_limit)
+ {
+ if (is_array($arg)) {
+ $_arg = array();
+ foreach ($arg as $key => $value) {
+ if (is_string($value) || is_numeric($value)) {
+ $_arg[$key] = substr($value, 0, $frame_arg_limit);
+ } else {
+ $_arg[$key] = $value;
+ }
+ }
+ return $_arg;
+ } elseif (is_string($arg) || is_numeric($arg)) {
+ return substr($arg, 0, $frame_arg_limit);
+ } else {
+ return $arg;
+ }
+ }
+
+ private static function strip_prefixes($filename, $prefixes)
+ {
+ if ($prefixes === null) {
+ return $filename;
+ }
+ foreach ($prefixes as $prefix) {
+ if (substr($filename, 0, strlen($prefix)) === $prefix) {
+ return substr($filename, strlen($prefix));
+ }
+ }
+ return $filename;
+ }
+
private static function read_source_file($filename, $lineno, $context_lines = 5)
{
$frame = array(
@@ -208,7 +240,7 @@ private static function read_source_file($filename, $lineno, $context_lines = 5)
// 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$/",
+ $matched = preg_match("/^(.*?)\\((\\d+)\\) : eval\\(\\)'d code$/",
$filename, $matches);
if ($matched) {
$frame['filename'] = $filename = $matches[1];
@@ -219,7 +251,7 @@ private static function read_source_file($filename, $lineno, $context_lines = 5)
// "() : runtime-created function"
// Extract the correct filename + linenumber from the string.
$matches = array();
- $matched = preg_match("/^(.*?)\((\d+)\) : runtime-created function$/",
+ $matched = preg_match("/^(.*?)\\((\\d+)\\) : runtime-created function$/",
$filename, $matches);
if ($matched) {
$frame['filename'] = $filename = $matches[1];
diff --git a/lib/sentry/sentry/lib/Raven/TransactionStack.php b/lib/sentry/sentry/lib/Raven/TransactionStack.php
new file mode 100644
index 0000000..9446809
--- /dev/null
+++ b/lib/sentry/sentry/lib/Raven/TransactionStack.php
@@ -0,0 +1,54 @@
+stack = array();
+ }
+
+ public function clear()
+ {
+ $this->stack = array();
+ }
+
+ public function peek()
+ {
+ $len = count($this->stack);
+ if ($len === 0) {
+ return null;
+ }
+ return $this->stack[$len - 1];
+ }
+
+ public function push($context)
+ {
+ $this->stack[] = $context;
+ }
+
+ /** @noinspection PhpInconsistentReturnPointsInspection
+ * @param string|null $context
+ * @return mixed
+ */
+ public function pop($context = null)
+ {
+ if (!$context) {
+ return array_pop($this->stack);
+ }
+ while (!empty($this->stack)) {
+ if (array_pop($this->stack) === $context) {
+ return $context;
+ }
+ }
+ // @codeCoverageIgnoreStart
+ }
+ // @codeCoverageIgnoreEnd
+}
diff --git a/lib/sentry/raven/lib/Raven/Util.php b/lib/sentry/sentry/lib/Raven/Util.php
similarity index 75%
rename from lib/sentry/raven/lib/Raven/Util.php
rename to lib/sentry/sentry/lib/Raven/Util.php
index dbd2d11..8f684b5 100644
--- a/lib/sentry/raven/lib/Raven/Util.php
+++ b/lib/sentry/sentry/lib/Raven/Util.php
@@ -21,8 +21,13 @@ class Raven_Util
* Because we love Python, this works much like dict.get() in Python.
*
* Returns $var from $array if set, otherwise returns $default.
+ *
+ * @param array $array
+ * @param string $var
+ * @param mixed $default
+ * @return mixed
*/
- public static function get($array, $var, $default=null)
+ public static function get($array, $var, $default = null)
{
if (isset($array[$var])) {
return $array[$var];
diff --git a/lib/sentry/raven/lib/Raven/data/cacert.pem b/lib/sentry/sentry/lib/Raven/data/cacert.pem
similarity index 100%
rename from lib/sentry/raven/lib/Raven/data/cacert.pem
rename to lib/sentry/sentry/lib/Raven/data/cacert.pem
diff --git a/lib/sentry/raven/phpunit.xml b/lib/sentry/sentry/phpunit.xml
similarity index 89%
rename from lib/sentry/raven/phpunit.xml
rename to lib/sentry/sentry/phpunit.xml
index ad58dc6..9024d98 100644
--- a/lib/sentry/raven/phpunit.xml
+++ b/lib/sentry/sentry/phpunit.xml
@@ -1,7 +1,6 @@
- false,
+ ));
+
+ $handler = new \Raven_Breadcrumbs_ErrorHandler($client);
+ $handler->handleError(E_WARNING, 'message');
+
+ $crumbs = $client->breadcrumbs->fetch();
+ $this->assertEquals(count($crumbs), 1);
+ $this->assertEquals($crumbs[0]['message'], 'message');
+ $this->assertEquals($crumbs[0]['category'], 'error_reporting');
+ $this->assertEquals($crumbs[0]['level'], 'warning');
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/Breadcrumbs/MonologTest.php b/lib/sentry/sentry/test/Raven/Tests/Breadcrumbs/MonologTest.php
new file mode 100644
index 0000000..1c26f11
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/Breadcrumbs/MonologTest.php
@@ -0,0 +1,72 @@
+run(Object(Illuminate\Http\Request))
+#3 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(5053): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
+#4 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(715): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
+#5 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(696): Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request))
+#6 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(7825): Illuminate\Foundation\Application->handle(Object(Illuminate\Http\Request), 1, true)
+#7 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(8432): Illuminate\Session\Middleware->handle(Object(Illuminate\Http\Request), 1, true)
+#8 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(8379): Illuminate\Cookie\Queue->handle(Object(Illuminate\Http\Request), 1, true)
+#9 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(11123): Illuminate\Cookie\Guard->handle(Object(Illuminate\Http\Request), 1, true)
+#10 /sentry-laravel/examples/laravel-4.2/bootstrap/compiled.php(657): Stack\StackedHttpKernel->handle(Object(Illuminate\Http\Request))
+#11 /sentry-laravel/examples/laravel-4.2/public/index.php(49): Illuminate\Foundation\Application->run()
+#12 /sentry-laravel/examples/laravel-4.2/server.php(19): require_once('/Users/dcramer/...')
+#13 {main}
+EOF;
+ }
+
+ public function testSimple()
+ {
+ $client = new \Raven_Client(array(
+ 'install_default_breadcrumb_handlers' => false,
+ ));
+ $handler = new \Raven_Breadcrumbs_MonologHandler($client);
+
+ $logger = new Monolog\Logger('sentry');
+ $logger->pushHandler($handler);
+ $logger->addWarning('Foo');
+
+ $crumbs = $client->breadcrumbs->fetch();
+ $this->assertEquals(count($crumbs), 1);
+ $this->assertEquals($crumbs[0]['message'], 'Foo');
+ $this->assertEquals($crumbs[0]['category'], 'sentry');
+ $this->assertEquals($crumbs[0]['level'], 'warning');
+ }
+
+ public function testErrorInMessage()
+ {
+ $client = new \Raven_Client(array(
+ 'install_default_breadcrumb_handlers' => false,
+ ));
+ $handler = new \Raven_Breadcrumbs_MonologHandler($client);
+
+ $logger = new Monolog\Logger('sentry');
+ $logger->pushHandler($handler);
+ $logger->addError($this->getSampleErrorMessage());
+
+ $crumbs = $client->breadcrumbs->fetch();
+ $this->assertEquals(count($crumbs), 1);
+ $this->assertEquals($crumbs[0]['data']['type'], 'Exception');
+ $this->assertEquals($crumbs[0]['data']['value'], 'An unhandled exception');
+ $this->assertEquals($crumbs[0]['category'], 'sentry');
+ $this->assertEquals($crumbs[0]['level'], 'error');
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/BreadcrumbsTest.php b/lib/sentry/sentry/test/Raven/Tests/BreadcrumbsTest.php
new file mode 100644
index 0000000..5046459
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/BreadcrumbsTest.php
@@ -0,0 +1,38 @@
+record(array('message' => $i));
+ }
+
+ $results = $breadcrumbs->fetch();
+
+ $this->assertEquals(count($results), 10);
+ for ($i = 1; $i <= 10; $i++) {
+ $this->assertEquals($results[$i - 1]['message'], $i);
+ }
+ }
+
+ public function testJson()
+ {
+ $breadcrumbs = new Raven_Breadcrumbs(1);
+ $breadcrumbs->record(array('message' => 'test'));
+ $json = $breadcrumbs->to_json();
+
+ $this->assertEquals(count($json['values']), 1);
+ $this->assertEquals($json['values'][0]['message'], 'test');
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/ClientTest.php b/lib/sentry/sentry/test/Raven/Tests/ClientTest.php
new file mode 100644
index 0000000..bf420ee
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/ClientTest.php
@@ -0,0 +1,2226 @@
+__sent_events;
+ }
+
+ public function send(&$data)
+ {
+ if (is_callable($this->send_callback) && call_user_func_array($this->send_callback, array(&$data)) === false) {
+ // if send_callback returns falsely, end native send
+ return;
+ }
+ $this->__sent_events[] = $data;
+ }
+
+ public static function is_http_request()
+ {
+ return true;
+ }
+
+ public static function get_auth_header($timestamp, $client, $api_key, $secret_key)
+ {
+ return parent::get_auth_header($timestamp, $client, $api_key, $secret_key);
+ }
+
+ public function get_http_data()
+ {
+ return parent::get_http_data();
+ }
+
+ public function get_user_data()
+ {
+ return parent::get_user_data();
+ }
+
+ public function buildCurlCommand($url, $data, $headers)
+ {
+ return parent::buildCurlCommand($url, $data, $headers);
+ }
+
+ // short circuit breadcrumbs
+ public function registerDefaultBreadcrumbHandlers()
+ {
+ $this->dummy_breadcrumbs_handlers_has_set = true;
+ }
+
+ public function registerShutdownFunction()
+ {
+ $this->dummy_shutdown_handlers_has_set = true;
+ }
+
+ /**
+ * Expose the current url method to test it
+ *
+ * @return string
+ */
+ public function test_get_current_url()
+ {
+ return $this->get_current_url();
+ }
+}
+
+class Dummy_Raven_Client_With_Overrided_Direct_Send extends Raven_Client
+{
+ public $_send_http_asynchronous_curl_exec_called = false;
+ public $_send_http_synchronous = false;
+ public $_set_url;
+ public $_set_data;
+ public $_set_headers;
+ public static $_close_curl_resource_called = false;
+
+ public function send_http_asynchronous_curl_exec($url, $data, $headers)
+ {
+ $this->_send_http_asynchronous_curl_exec_called = true;
+ $this->_set_url = $url;
+ $this->_set_data = $data;
+ $this->_set_headers = $headers;
+ }
+
+ public function send_http_synchronous($url, $data, $headers)
+ {
+ $this->_send_http_synchronous = true;
+ $this->_set_url = $url;
+ $this->_set_data = $data;
+ $this->_set_headers = $headers;
+ }
+
+ public function get_curl_options()
+ {
+ $options = parent::get_curl_options();
+
+ return $options;
+ }
+
+ public function get_curl_handler()
+ {
+ return $this->_curl_handler;
+ }
+
+ public function set_curl_handler(Raven_CurlHandler $value)
+ {
+ $this->_curl_handler = $value;
+ }
+
+ public function close_curl_resource()
+ {
+ parent::close_curl_resource();
+ self::$_close_curl_resource_called = true;
+ }
+}
+
+class Dummy_Raven_Client_No_Http extends Dummy_Raven_Client
+{
+ /**
+ * @return bool
+ */
+ public static function is_http_request()
+ {
+ return false;
+ }
+}
+
+class Dummy_Raven_Client_With_Sync_Override extends Raven_Client
+{
+ private static $_test_data = null;
+
+ public static function get_test_data()
+ {
+ if (is_null(self::$_test_data)) {
+ self::$_test_data = '';
+ for ($i = 0; $i < 128; $i++) {
+ self::$_test_data .= chr(mt_rand(ord('a'), ord('z')));
+ }
+ }
+
+ return self::$_test_data;
+ }
+
+ public static function test_filename()
+ {
+ return sys_get_temp_dir().'/clientraven.tmp';
+ }
+
+ protected function buildCurlCommand($url, $data, $headers)
+ {
+ return 'echo '.escapeshellarg(self::get_test_data()).' > '.self::test_filename();
+ }
+}
+
+class Dummy_Raven_CurlHandler extends Raven_CurlHandler
+{
+ public $_set_url;
+ public $_set_data;
+ public $_set_headers;
+ public $_enqueue_called = false;
+ public $_join_called = false;
+
+ public function __construct($options = array(), $join_timeout = 5)
+ {
+ parent::__construct($options, $join_timeout);
+ }
+
+ public function enqueue($url, $data = null, $headers = array())
+ {
+ $this->_enqueue_called = true;
+ $this->_set_url = $url;
+ $this->_set_data = $data;
+ $this->_set_headers = $headers;
+
+ return 0;
+ }
+
+ public function join($timeout = null)
+ {
+ $this->_join_called = true;
+ }
+}
+
+class Raven_Tests_ClientTest extends PHPUnit_Framework_TestCase
+{
+ public function tearDown()
+ {
+ parent::tearDown();
+ if (file_exists(Dummy_Raven_Client_With_Sync_Override::test_filename())) {
+ unlink(Dummy_Raven_Client_With_Sync_Override::test_filename());
+ }
+ }
+
+ private function create_exception()
+ {
+ try {
+ throw new Exception('Foo bar');
+ } catch (Exception $ex) {
+ return $ex;
+ }
+ }
+
+ private function create_chained_exception()
+ {
+ try {
+ throw new Exception('Foo bar');
+ } catch (Exception $ex) {
+ try {
+ throw new Exception('Child exc', 0, $ex);
+ } catch (Exception $ex2) {
+ return $ex2;
+ }
+ }
+ }
+
+ public function testParseDSNHttp()
+ {
+ $result = Raven_Client::ParseDSN('http://public:secret@example.com/1');
+
+ $this->assertEquals(1, $result['project']);
+ $this->assertEquals('http://example.com/api/1/store/', $result['server']);
+ $this->assertEquals('public', $result['public_key']);
+ $this->assertEquals('secret', $result['secret_key']);
+ }
+
+ public function testParseDSNHttps()
+ {
+ $result = Raven_Client::ParseDSN('https://public:secret@example.com/1');
+
+ $this->assertEquals(1, $result['project']);
+ $this->assertEquals('https://example.com/api/1/store/', $result['server']);
+ $this->assertEquals('public', $result['public_key']);
+ $this->assertEquals('secret', $result['secret_key']);
+ }
+
+ public function testParseDSNPath()
+ {
+ $result = Raven_Client::ParseDSN('http://public:secret@example.com/app/1');
+
+ $this->assertEquals(1, $result['project']);
+ $this->assertEquals('http://example.com/app/api/1/store/', $result['server']);
+ $this->assertEquals('public', $result['public_key']);
+ $this->assertEquals('secret', $result['secret_key']);
+ }
+
+ public function testParseDSNPort()
+ {
+ $result = Raven_Client::ParseDSN('http://public:secret@example.com:9000/app/1');
+
+ $this->assertEquals(1, $result['project']);
+ $this->assertEquals('http://example.com:9000/app/api/1/store/', $result['server']);
+ $this->assertEquals('public', $result['public_key']);
+ $this->assertEquals('secret', $result['secret_key']);
+ }
+
+ public function testParseDSNInvalidScheme()
+ {
+ try {
+ Raven_Client::ParseDSN('gopher://public:secret@/1');
+ $this->fail();
+ } catch (Exception $e) {
+ return;
+ }
+ }
+
+ public function testParseDSNMissingNetloc()
+ {
+ try {
+ Raven_Client::ParseDSN('http://public:secret@/1');
+ $this->fail();
+ } catch (Exception $e) {
+ return;
+ }
+ }
+
+ public function testParseDSNMissingProject()
+ {
+ try {
+ Raven_Client::ParseDSN('http://public:secret@example.com');
+ $this->fail();
+ } catch (Exception $e) {
+ return;
+ }
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testParseDSNMissingPublicKey()
+ {
+ Raven_Client::ParseDSN('http://:secret@example.com/1');
+ }
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testParseDSNMissingSecretKey()
+ {
+ Raven_Client::ParseDSN('http://public@example.com/1');
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testDsnFirstArgument()
+ {
+ $client = new Dummy_Raven_Client('http://public:secret@example.com/1');
+
+ $this->assertEquals(1, $client->project);
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('public', $client->public_key);
+ $this->assertEquals('secret', $client->secret_key);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testDsnFirstArgumentWithOptions()
+ {
+ $client = new Dummy_Raven_Client('http://public:secret@example.com/1', array(
+ 'site' => 'foo',
+ ));
+
+ $this->assertEquals(1, $client->project);
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('public', $client->public_key);
+ $this->assertEquals('secret', $client->secret_key);
+ $this->assertEquals('foo', $client->site);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testOptionsFirstArgument()
+ {
+ $client = new Dummy_Raven_Client(array(
+ 'server' => 'http://example.com/api/1/store/',
+ 'project' => 1,
+ ));
+
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testDsnInOptionsFirstArg()
+ {
+ $client = new Dummy_Raven_Client(array(
+ 'dsn' => 'http://public:secret@example.com/1',
+ ));
+
+ $this->assertEquals(1, $client->project);
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('public', $client->public_key);
+ $this->assertEquals('secret', $client->secret_key);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testDsnInOptionsSecondArg()
+ {
+ $client = new Dummy_Raven_Client(null, array(
+ 'dsn' => 'http://public:secret@example.com/1',
+ ));
+
+ $this->assertEquals(1, $client->project);
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('public', $client->public_key);
+ $this->assertEquals('secret', $client->secret_key);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testOptionsFirstArgumentWithOptions()
+ {
+ $client = new Dummy_Raven_Client(array(
+ 'server' => 'http://example.com/api/1/store/',
+ 'project' => 1,
+ ), array(
+ 'site' => 'foo',
+ ));
+
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('foo', $client->site);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testOptionsExtraData()
+ {
+ $client = new Dummy_Raven_Client(array('extra' => array('foo' => 'bar')));
+
+ $client->captureMessage('Test Message %s', array('foo'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('bar', $event['extra']['foo']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testOptionsExtraDataWithNull()
+ {
+ $client = new Dummy_Raven_Client(array('extra' => array('foo' => 'bar')));
+
+ $client->captureMessage('Test Message %s', array('foo'), null);
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('bar', $event['extra']['foo']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testEmptyExtraData()
+ {
+ $client = new Dummy_Raven_Client(array('extra' => array()));
+
+ $client->captureMessage('Test Message %s', array('foo'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(array_key_exists('extra', $event), false);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageDoesHandleUninterpolatedMessage()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->captureMessage('Test Message %s');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('Test Message %s', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageDoesHandleInterpolatedMessage()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->captureMessage('Test Message %s', array('foo'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('Test Message foo', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageDoesHandleInterpolatedMessageWithRelease()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->setRelease(20160909144742);
+
+ $this->assertEquals(20160909144742, $client->getRelease());
+
+ $client->captureMessage('Test Message %s', array('foo'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(20160909144742, $event['release']);
+ $this->assertEquals('Test Message foo', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageSetsInterface()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->captureMessage('Test Message %s', array('foo'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(array(
+ 'message' => 'Test Message %s',
+ 'params' => array('foo'),
+ 'formatted' => 'Test Message foo',
+ ), $event['sentry.interfaces.Message']);
+ $this->assertEquals('Test Message foo', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageHandlesOptionsAsThirdArg()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->captureMessage('Test Message %s', array('foo'), array(
+ 'level' => Dummy_Raven_Client::WARNING,
+ 'extra' => array('foo' => 'bar')
+ ));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(Dummy_Raven_Client::WARNING, $event['level']);
+ $this->assertEquals('bar', $event['extra']['foo']);
+ $this->assertEquals('Test Message foo', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageHandlesLevelAsThirdArg()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->captureMessage('Test Message %s', array('foo'), Dummy_Raven_Client::WARNING);
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(Dummy_Raven_Client::WARNING, $event['level']);
+ $this->assertEquals('Test Message foo', $event['message']);
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionSetsInterfaces()
+ {
+ # TODO: it'd be nice if we could mock the stacktrace extraction function here
+ $client = new Dummy_Raven_Client();
+ $ex = $this->create_exception();
+ $client->captureException($ex);
+
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+
+ $exc = $event['exception'];
+ $this->assertEquals(1, count($exc['values']));
+ $this->assertEquals('Foo bar', $exc['values'][0]['value']);
+ $this->assertEquals('Exception', $exc['values'][0]['type']);
+
+ $this->assertFalse(empty($exc['values'][0]['stacktrace']['frames']));
+ $frames = $exc['values'][0]['stacktrace']['frames'];
+ $frame = $frames[count($frames) - 1];
+ $this->assertTrue($frame['lineno'] > 0);
+ $this->assertEquals('create_exception', $frame['function']);
+ $this->assertFalse(isset($frame['vars']));
+ $this->assertEquals(' throw new Exception(\'Foo bar\');', $frame['context_line']);
+ $this->assertFalse(empty($frame['pre_context']));
+ $this->assertFalse(empty($frame['post_context']));
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionChainedException()
+ {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
+ }
+
+ # TODO: it'd be nice if we could mock the stacktrace extraction function here
+ $client = new Dummy_Raven_Client();
+ $ex = $this->create_chained_exception();
+ $client->captureException($ex);
+
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+
+ $exc = $event['exception'];
+ $this->assertEquals(2, count($exc['values']));
+ $this->assertEquals('Foo bar', $exc['values'][0]['value']);
+ $this->assertEquals('Child exc', $exc['values'][1]['value']);
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionDifferentLevelsInChainedExceptionsBug()
+ {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ $this->markTestSkipped('PHP 5.3 required for chained exceptions.');
+ }
+
+ $client = new Dummy_Raven_Client();
+ $e1 = new ErrorException('First', 0, E_DEPRECATED);
+ $e2 = new ErrorException('Second', 0, E_NOTICE, __FILE__, __LINE__, $e1);
+ $e3 = new ErrorException('Third', 0, E_ERROR, __FILE__, __LINE__, $e2);
+
+ $client->captureException($e1);
+ $client->captureException($e2);
+ $client->captureException($e3);
+ $events = $client->getSentEvents();
+
+ $event = array_pop($events);
+ $this->assertEquals(Dummy_Raven_Client::ERROR, $event['level']);
+
+ $event = array_pop($events);
+ $this->assertEquals(Dummy_Raven_Client::INFO, $event['level']);
+
+ $event = array_pop($events);
+ $this->assertEquals(Dummy_Raven_Client::WARNING, $event['level']);
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionHandlesOptionsAsSecondArg()
+ {
+ $client = new Dummy_Raven_Client();
+ $ex = $this->create_exception();
+ $client->captureException($ex, array('culprit' => 'test'));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('test', $event['culprit']);
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionHandlesExcludeOption()
+ {
+ $client = new Dummy_Raven_Client(array(
+ 'exclude' => array('Exception'),
+ ));
+ $ex = $this->create_exception();
+ $client->captureException($ex, 'test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(0, count($events));
+ }
+
+ public function testCaptureExceptionInvalidUTF8()
+ {
+ $client = new Dummy_Raven_Client();
+ try {
+ invalid_encoding();
+ } catch (Exception $ex) {
+ $client->captureException($ex);
+ }
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+
+ // if this fails to encode it returns false
+ $message = $client->encode($events[0]);
+ $this->assertNotFalse($message, $client->getLastError());
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function testDoesRegisterProcessors()
+ {
+ $client = new Dummy_Raven_Client(array(
+ 'processors' => array('Raven_Processor_SanitizeDataProcessor'),
+ ));
+
+ $this->assertEquals(1, count($client->processors));
+ $this->assertInstanceOf('Raven_Processor_SanitizeDataProcessor', $client->processors[0]);
+ }
+
+ public function testProcessDoesCallProcessors()
+ {
+ $data = array("key"=>"value");
+
+ $processor = $this->getMockBuilder('Processor')
+ ->setMethods(array('process'))
+ ->getMock();
+ $processor->expects($this->once())
+ ->method('process')
+ ->with($data);
+
+ $client = new Dummy_Raven_Client();
+ $client->processors[] = $processor;
+ $client->process($data);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ * @covers Raven_Client::getDefaultProcessors
+ */
+ public function testDefaultProcessorsAreUsed()
+ {
+ $client = new Dummy_Raven_Client();
+ $defaults = Dummy_Raven_Client::getDefaultProcessors();
+
+ $this->assertEquals(count($defaults), count($client->processors));
+ }
+
+ /**
+ * @covers Raven_Client::getDefaultProcessors
+ */
+ public function testDefaultProcessorsContainSanitizeDataProcessor()
+ {
+ $this->assertContains('Raven_Processor_SanitizeDataProcessor', Dummy_Raven_Client::getDefaultProcessors());
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ * @covers Raven_Client::get_default_data
+ */
+ public function testGetDefaultData()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->transaction->push('test');
+ $expected = array(
+ 'platform' => 'php',
+ 'project' => $client->project,
+ 'server_name' => $client->name,
+ 'site' => $client->site,
+ 'logger' => $client->logger,
+ 'tags' => $client->tags,
+ 'sdk' => array(
+ 'name' => 'sentry-php',
+ 'version' => $client::VERSION,
+ ),
+ 'culprit' => 'test',
+ );
+ $this->assertEquals($expected, $client->get_default_data());
+ }
+
+ /**
+ * @backupGlobals
+ * @covers Raven_Client::get_http_data
+ */
+ public function testGetHttpData()
+ {
+ $_SERVER = array(
+ 'REDIRECT_STATUS' => '200',
+ 'CONTENT_TYPE' => 'text/xml',
+ 'CONTENT_LENGTH' => '99',
+ 'HTTP_HOST' => 'getsentry.com',
+ 'HTTP_ACCEPT' => 'text/html',
+ 'HTTP_ACCEPT_CHARSET' => 'utf-8',
+ 'HTTP_COOKIE' => 'cupcake: strawberry',
+ 'SERVER_PORT' => '443',
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ 'REQUEST_METHOD' => 'PATCH',
+ 'QUERY_STRING' => 'q=bitch&l=en',
+ 'REQUEST_URI' => '/welcome/',
+ 'SCRIPT_NAME' => '/index.php',
+ );
+ $_POST = array(
+ 'stamp' => '1c',
+ );
+ $_COOKIE = array(
+ 'donut' => 'chocolat',
+ );
+
+ $expected = array(
+ 'request' => array(
+ 'method' => 'PATCH',
+ 'url' => 'https://getsentry.com/welcome/',
+ 'query_string' => 'q=bitch&l=en',
+ 'data' => array(
+ 'stamp' => '1c',
+ ),
+ 'cookies' => array(
+ 'donut' => 'chocolat',
+ ),
+ 'headers' => array(
+ 'Host' => 'getsentry.com',
+ 'Accept' => 'text/html',
+ 'Accept-Charset' => 'utf-8',
+ 'Cookie' => 'cupcake: strawberry',
+ 'Content-Type' => 'text/xml',
+ 'Content-Length' => '99',
+ ),
+ )
+ );
+
+ $client = new Dummy_Raven_Client();
+ $this->assertEquals($expected, $client->get_http_data());
+ }
+
+ /**
+ * @covers Raven_Client::user_context
+ * @covers Raven_Client::get_user_data
+ */
+ public function testGetUserDataWithSetUser()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $id = 'unique_id';
+ $email = 'foo@example.com';
+ $client->user_context(array('id' => $id, 'email' => $email, 'username' => 'my_user', ));
+
+ $expected = array(
+ 'user' => array(
+ 'id' => $id,
+ 'username' => 'my_user',
+ 'email' => $email,
+ )
+ );
+
+ $this->assertEquals($expected, $client->get_user_data());
+ }
+
+ /**
+ * @covers Raven_Client::get_user_data
+ */
+ public function testGetUserDataWithNoUser()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $expected = array(
+ 'user' => array(
+ 'id' => session_id(),
+ )
+ );
+ $this->assertEquals($expected, $client->get_user_data());
+ }
+
+ /**
+ * @covers Raven_Client::get_auth_header
+ */
+ public function testGet_Auth_Header()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $clientstring = 'sentry-php/test';
+ $timestamp = '1234341324.340000';
+
+ $expected = "Sentry sentry_timestamp={$timestamp}, sentry_client={$clientstring}, " .
+ "sentry_version=" . Dummy_Raven_Client::PROTOCOL . ", " .
+ "sentry_key=publickey, sentry_secret=secretkey";
+
+ $this->assertEquals($expected, $client->get_auth_header($timestamp, 'sentry-php/test', 'publickey', 'secretkey'));
+ }
+
+ /**
+ * @covers Raven_Client::getAuthHeader
+ */
+ public function testGetAuthHeader()
+ {
+ $client = new Dummy_Raven_Client();
+ $ts1 = microtime(true);
+ $header = $client->getAuthHeader();
+ $ts2 = microtime(true);
+ $this->assertEquals(1, preg_match('/sentry_timestamp=([0-9.]+)/', $header, $a));
+ $this->assertRegExp('/^[0-9]+(\\.[0-9]+)?$/', $a[1]);
+ $this->assertGreaterThanOrEqual($ts1, (double)$a[1]);
+ $this->assertLessThanOrEqual($ts2, (double)$a[1]);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageWithUserContext()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->user_context(array('email' => 'foo@example.com'));
+
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(array(
+ 'email' => 'foo@example.com',
+ ), $event['user']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ */
+ public function testCaptureMessageWithUnserializableUserData()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->user_context(array(
+ 'email' => 'foo@example.com',
+ 'data' => array(
+ 'error' => new Exception('test'),
+ )
+ ));
+
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ // we're just asserting that this goes off without a hitch
+ $this->assertEquals(1, count($events));
+ array_pop($events);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ * @covers Raven_Client::tags_context
+ */
+ public function testCaptureMessageWithTagsContext()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->tags_context(array('foo' => 'bar'));
+ $client->tags_context(array('biz' => 'boz'));
+ $client->tags_context(array('biz' => 'baz'));
+
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(array(
+ 'foo' => 'bar',
+ 'biz' => 'baz',
+ ), $event['tags']);
+ }
+
+ /**
+ * @covers Raven_Client::captureMessage
+ * @covers Raven_Client::extra_context
+ */
+ public function testCaptureMessageWithExtraContext()
+ {
+ $client = new Dummy_Raven_Client();
+
+ $client->extra_context(array('foo' => 'bar'));
+ $client->extra_context(array('biz' => 'boz'));
+ $client->extra_context(array('biz' => 'baz'));
+
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals(array(
+ 'foo' => 'bar',
+ 'biz' => 'baz',
+ ), $event['extra']);
+ }
+
+ /**
+ * @covers Raven_Client::captureException
+ */
+ public function testCaptureExceptionContainingLatin1()
+ {
+ // If somebody has a non-utf8 codebase, she/he should add the encoding to the detection order
+ $options = array(
+ 'mb_detect_order' => array(
+ 'ISO-8859-1', 'ASCII', 'UTF-8'
+ )
+ );
+
+ $client = new Dummy_Raven_Client($options);
+
+ // we need a non-utf8 string here.
+ // nobody writes non-utf8 in exceptions, but it is the easiest way to test.
+ // in real live non-utf8 may be somewhere in the exception's stacktrace
+ $utf8String = 'äöü';
+ $latin1String = utf8_decode($utf8String);
+ $client->captureException(new \Exception($latin1String));
+
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+
+ $this->assertEquals($utf8String, $event['exception']['values'][0]['value']);
+ }
+
+
+ public function testCaptureExceptionInLatin1File()
+ {
+ // If somebody has a non-utf8 codebase, she/he should add the encoding to the detection order
+ $options = array(
+ 'mb_detect_order' => array(
+ 'ISO-8859-1', 'ASCII', 'UTF-8'
+ )
+ );
+
+ $client = new Dummy_Raven_Client($options);
+
+ require_once(__DIR__.'/resources/captureExceptionInLatin1File.php');
+
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+
+ $stackTrace = array_pop($event['exception']['values'][0]['stacktrace']['frames']);
+
+ $utf8String = "// äöü";
+ $found = false;
+ foreach ($stackTrace['pre_context'] as $line) {
+ if ($line == $utf8String) {
+ $found = true;
+ break;
+ }
+ }
+
+ $this->assertTrue($found);
+ }
+
+ /**
+ * @covers Raven_Client::captureLastError
+ */
+ public function testCaptureLastError()
+ {
+ if (function_exists('error_clear_last')) {
+ error_clear_last();
+ }
+ $client = new Dummy_Raven_Client();
+ $this->assertNull($client->captureLastError());
+ $this->assertEquals(0, count($client->getSentEvents()));
+
+ @$undefined;
+
+ $client->captureLastError();
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('Undefined variable: undefined', $event['exception']['values'][0]['value']);
+ }
+
+ /**
+ * @covers Raven_Client::getLastEventID
+ */
+ public function testGetLastEventID()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->capture(array('message' => 'test', 'event_id' => 'abc'));
+ $this->assertEquals('abc', $client->getLastEventID());
+ }
+
+ /**
+ * @covers Raven_Client::setTransport
+ */
+ public function testCustomTransport()
+ {
+ $events = array();
+
+ // transport test requires default client
+ $client = new Raven_Client('https://public:secret@sentry.example.com/1', array(
+ 'install_default_breadcrumb_handlers' => false,
+ ));
+ $client->setTransport(function ($client, $data) use (&$events) {
+ $events[] = $data;
+ });
+ $client->capture(array('message' => 'test', 'event_id' => 'abc'));
+ $this->assertEquals(1, count($events));
+ }
+
+ /**
+ * @covers Raven_Client::setAppPath
+ */
+ public function testAppPathLinux()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->setAppPath('/foo/bar');
+
+ $this->assertEquals('/foo/bar/', $client->getAppPath());
+
+ $client->setAppPath('/foo/baz/');
+
+ $this->assertEquals('/foo/baz/', $client->getAppPath());
+ }
+
+ /**
+ * @covers Raven_Client::setAppPath
+ */
+ public function testAppPathWindows()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->setAppPath('C:\\foo\\bar\\');
+
+ $this->assertEquals('C:\\foo\\bar\\', $client->getAppPath());
+ }
+
+ /**
+ * @expectedException Raven_Exception
+ * @expectedExceptionMessage Raven_Client->install() must only be called once
+ */
+ public function testCannotInstallTwice()
+ {
+ $client = new Dummy_Raven_Client('https://public:secret@sentry.example.com/1');
+ $client->install();
+ $client->install();
+ }
+
+ public function cb1($data)
+ {
+ $this->assertEquals('test', $data['message']);
+ return false;
+ }
+
+ public function cb2($data)
+ {
+ $this->assertEquals('test', $data['message']);
+ return true;
+ }
+
+ public function cb3(&$data)
+ {
+ unset($data['message']);
+ return true;
+ }
+
+ /**
+ * @covers Raven_Client::send
+ */
+ public function testSendCallback()
+ {
+ $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb1')));
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(0, count($events));
+
+ $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb2')));
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+
+ $client = new Dummy_Raven_Client(array('send_callback' => array($this, 'cb3')));
+ $client->captureMessage('test');
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $this->assertTrue(empty($events[0]['message']));
+ }
+
+ /**
+ * @covers Raven_Client::sanitize
+ */
+ public function testSanitizeExtra()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('extra' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, array(2), 3
+ ),
+ ),
+ ));
+ $client->sanitize($data);
+
+ $this->assertEquals(array('extra' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, 'Array of length 1', 3
+ ),
+ ),
+ )), $data);
+ }
+
+ /**
+ * @covers Raven_Client::sanitize
+ */
+ public function testSanitizeTags()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('tags' => array(
+ 'foo' => 'bar',
+ 'baz' => array('biz'),
+ ));
+ $client->sanitize($data);
+
+ $this->assertEquals(array('tags' => array(
+ 'foo' => 'bar',
+ 'baz' => 'Array',
+ )), $data);
+ }
+
+ /**
+ * @covers Raven_Client::sanitize
+ */
+ public function testSanitizeUser()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('user' => array(
+ 'email' => 'foo@example.com',
+ ));
+ $client->sanitize($data);
+
+ $this->assertEquals(array('user' => array(
+ 'email' => 'foo@example.com',
+ )), $data);
+ }
+
+ /**
+ * @covers Raven_Client::sanitize
+ */
+ public function testSanitizeRequest()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('request' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, array(2), 3
+ ),
+ ),
+ ));
+ $client->sanitize($data);
+
+ $this->assertEquals(array('request' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, 'Array of length 1', 3
+ ),
+ ),
+ )), $data);
+ }
+
+ /**
+ * @covers Raven_Client::sanitize
+ */
+ public function testSanitizeContexts()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('contexts' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, array(
+ 'foo' => 'bar',
+ 'level4' => array(array('level5', 'level5 a'), 2),
+ ), 3
+ ),
+ ),
+ ));
+ $client->sanitize($data);
+
+ $this->assertEquals(array('contexts' => array(
+ 'context' => array(
+ 'line' => 1216,
+ 'stack' => array(
+ 1, array(
+ 'foo' => 'bar',
+ 'level4' => array('Array of length 2', 2),
+ ), 3
+ ),
+ ),
+ )), $data);
+ }
+
+ /**
+ * @covers Raven_Client::buildCurlCommand
+ */
+ public function testBuildCurlCommandEscapesInput()
+ {
+ $data = '{"foo": "\'; ls;"}';
+ $client = new Dummy_Raven_Client();
+ $result = $client->buildCurlCommand('http://foo.com', $data, array());
+ $this->assertEquals('curl -X POST -d \'{"foo": "\'\\\'\'; ls;"}\' \'http://foo.com\' -m 5 > /dev/null 2>&1 &', $result);
+
+ $result = $client->buildCurlCommand('http://foo.com', $data, array('key' => 'value'));
+ $this->assertEquals('curl -X POST -H \'key: value\' -d \'{"foo": "\'\\\'\'; ls;"}\' \'http://foo.com\' -m 5 > /dev/null 2>&1 &', $result);
+
+ $client->verify_ssl = false;
+ $result = $client->buildCurlCommand('http://foo.com', $data, array());
+ $this->assertEquals('curl -X POST -d \'{"foo": "\'\\\'\'; ls;"}\' \'http://foo.com\' -m 5 -k > /dev/null 2>&1 &', $result);
+
+ $result = $client->buildCurlCommand('http://foo.com', $data, array('key' => 'value'));
+ $this->assertEquals('curl -X POST -H \'key: value\' -d \'{"foo": "\'\\\'\'; ls;"}\' \'http://foo.com\' -m 5 -k > /dev/null 2>&1 &', $result);
+ }
+
+ /**
+ * @covers Raven_Client::user_context
+ */
+ public function testUserContextWithoutMerge()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->user_context(array('foo' => 'bar'), false);
+ $client->user_context(array('baz' => 'bar'), false);
+ $this->assertEquals(array('baz' => 'bar'), $client->context->user);
+ }
+
+ /**
+ * @covers Raven_Client::user_context
+ */
+ public function testUserContextWithMerge()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->user_context(array('foo' => 'bar'), true);
+ $client->user_context(array('baz' => 'bar'), true);
+ $this->assertEquals(array('foo' => 'bar', 'baz' => 'bar'), $client->context->user);
+ }
+
+ /**
+ * @covers Raven_Client::user_context
+ */
+ public function testUserContextWithMergeAndNull()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->user_context(array('foo' => 'bar'), true);
+ $client->user_context(null, true);
+ $this->assertEquals(array('foo' => 'bar'), $client->context->user);
+ }
+
+ /**
+ * Set the server array to the test values, check the current url
+ *
+ * @dataProvider currentUrlProvider
+ * @param array $serverVars
+ * @param array $options
+ * @param string $expected - the url expected
+ * @param string $message - fail message
+ * @covers Raven_Client::get_current_url
+ * @covers Raven_Client::isHttps
+ */
+ public function testCurrentUrl($serverVars, $options, $expected, $message)
+ {
+ $_SERVER = $serverVars;
+
+ $client = new Dummy_Raven_Client($options);
+ $result = $client->test_get_current_url();
+
+ $this->assertSame($expected, $result, $message);
+ }
+
+ /**
+ * Arrays of:
+ * $_SERVER data
+ * config
+ * expected url
+ * Fail message
+ *
+ * @return array
+ */
+ public function currentUrlProvider()
+ {
+ return array(
+ array(
+ array(),
+ array(),
+ null,
+ 'No url expected for empty REQUEST_URI'
+ ),
+ array(
+ array(
+ 'REQUEST_URI' => '/',
+ 'HTTP_HOST' => 'example.com',
+ ),
+ array(),
+ 'http://example.com/',
+ 'The url is expected to be http with the request uri'
+ ),
+ array(
+ array(
+ 'REQUEST_URI' => '/',
+ 'HTTP_HOST' => 'example.com',
+ 'HTTPS' => 'on'
+ ),
+ array(),
+ 'https://example.com/',
+ 'The url is expected to be https because of HTTPS on'
+ ),
+ array(
+ array(
+ 'REQUEST_URI' => '/',
+ 'HTTP_HOST' => 'example.com',
+ 'SERVER_PORT' => '443'
+ ),
+ array(),
+ 'https://example.com/',
+ 'The url is expected to be https because of the server port'
+ ),
+ array(
+ array(
+ 'REQUEST_URI' => '/',
+ 'HTTP_HOST' => 'example.com',
+ 'X-FORWARDED-PROTO' => 'https'
+ ),
+ array(),
+ 'http://example.com/',
+ 'The url is expected to be http because the X-Forwarded header is ignored'
+ ),
+ array(
+ array(
+ 'REQUEST_URI' => '/',
+ 'HTTP_HOST' => 'example.com',
+ 'X-FORWARDED-PROTO' => 'https'
+ ),
+ array('trust_x_forwarded_proto' => true),
+ 'https://example.com/',
+ 'The url is expected to be https because the X-Forwarded header is trusted'
+ )
+ );
+ }
+
+ /**
+ * @covers Raven_Client::uuid4()
+ */
+ public function testUuid4()
+ {
+ $method = new ReflectionMethod('Raven_Client', 'uuid4');
+ $method->setAccessible(true);
+ for ($i = 0; $i < 1000; $i++) {
+ $this->assertRegExp('/^[0-9a-z-]+$/', $method->invoke(null));
+ }
+ }
+
+ /**
+ * @covers Raven_Client::getEnvironment
+ * @covers Raven_Client::setEnvironment
+ * @covers Raven_Client::getRelease
+ * @covers Raven_Client::setRelease
+ * @covers Raven_Client::getAppPath
+ * @covers Raven_Client::setAppPath
+ * @covers Raven_Client::getExcludedAppPaths
+ * @covers Raven_Client::setExcludedAppPaths
+ * @covers Raven_Client::getPrefixes
+ * @covers Raven_Client::setPrefixes
+ * @covers Raven_Client::getSendCallback
+ * @covers Raven_Client::setSendCallback
+ * @covers Raven_Client::getTransport
+ * @covers Raven_Client::setTransport
+ * @covers Raven_Client::getServerEndpoint
+ * @covers Raven_Client::getLastError
+ * @covers Raven_Client::getLastEventID
+ * @covers Raven_Client::get_extra_data
+ * @covers Raven_Client::setProcessors
+ * @covers Raven_Client::getLastSentryError
+ * @covers Raven_Client::getShutdownFunctionHasBeenSet
+ */
+ public function testGettersAndSetters()
+ {
+ $client = new Dummy_Raven_Client();
+ $property_method__convert_path = new ReflectionMethod('Raven_Client', '_convertPath');
+ $property_method__convert_path->setAccessible(true);
+ $callable = array($this, 'stabClosureVoid');
+
+ $data = array(
+ array('environment', null, 'value', ),
+ array('environment', null, null, ),
+ array('release', null, 'value', ),
+ array('release', null, null, ),
+ array('app_path', null, 'value', $property_method__convert_path->invoke($client, 'value')),
+ array('app_path', null, null, ),
+ array('app_path', null, false, null, ),
+ array('excluded_app_paths', null, array('value'),
+ array($property_method__convert_path->invoke($client, 'value'))),
+ array('excluded_app_paths', null, array(), null),
+ array('excluded_app_paths', null, null),
+ array('prefixes', null, array('value'), array($property_method__convert_path->invoke($client, 'value'))),
+ array('prefixes', null, array()),
+ array('send_callback', null, $callable),
+ array('send_callback', null, null),
+ array('transport', null, $callable),
+ array('transport', null, null),
+ array('server', 'ServerEndpoint', 'http://example.com/'),
+ array('server', 'ServerEndpoint', 'http://example.org/'),
+ array('_lasterror', null, null, ),
+ array('_lasterror', null, 'value', ),
+ array('_lasterror', null, mt_rand(100, 999), ),
+ array('_last_sentry_error', null, (object)array('error' => 'test',), ),
+ array('_last_event_id', null, mt_rand(100, 999), ),
+ array('_last_event_id', null, 'value', ),
+ array('extra_data', '_extra_data', array('key' => 'value'), ),
+ array('processors', 'processors', array(), ),
+ array('processors', 'processors', array('key' => 'value'), ),
+ array('_shutdown_function_has_been_set', null, true),
+ array('_shutdown_function_has_been_set', null, false),
+ );
+ foreach ($data as &$datum) {
+ $this->subTestGettersAndSettersDatum($client, $datum);
+ }
+ foreach ($data as &$datum) {
+ $client = new Dummy_Raven_Client();
+ $this->subTestGettersAndSettersDatum($client, $datum);
+ }
+ }
+
+ private function subTestGettersAndSettersDatum(Raven_Client $client, $datum)
+ {
+ if (count($datum) == 3) {
+ list($property_name, $function_name, $value_in) = $datum;
+ $value_out = $value_in;
+ } else {
+ list($property_name, $function_name, $value_in, $value_out) = $datum;
+ }
+ if (is_null($function_name)) {
+ $function_name = str_replace('_', '', $property_name);
+ }
+
+ $method_get_name = 'get'.$function_name;
+ $method_set_name = 'set'.$function_name;
+ $property = new ReflectionProperty('Raven_Client', $property_name);
+ $property->setAccessible(true);
+
+ if (method_exists($client, $method_set_name)) {
+ $setter_output = $client->$method_set_name($value_in);
+ if (!is_null($setter_output) and is_object($setter_output)) {
+ // chaining call test
+ $this->assertEquals(spl_object_hash($client), spl_object_hash($setter_output));
+ }
+ $actual_value = $property->getValue($client);
+ $this->assertMixedValueAndArray($value_out, $actual_value);
+ }
+
+ if (method_exists($client, $method_get_name)) {
+ $property->setValue($client, $value_out);
+ $reflection = new ReflectionMethod('Raven_Client', $method_get_name);
+ if ($reflection->isPublic()) {
+ $actual_value = $client->$method_get_name();
+ $this->assertMixedValueAndArray($value_out, $actual_value);
+ }
+ }
+ }
+
+ private function assertMixedValueAndArray($expected_value, $actual_value)
+ {
+ if (is_null($expected_value)) {
+ $this->assertNull($actual_value);
+ } elseif ($expected_value === true) {
+ $this->assertTrue($actual_value);
+ } elseif ($expected_value === false) {
+ $this->assertFalse($actual_value);
+ } elseif (is_string($expected_value) or is_integer($expected_value) or is_double($expected_value)) {
+ $this->assertEquals($expected_value, $actual_value);
+ } elseif (is_array($expected_value)) {
+ $this->assertInternalType('array', $actual_value);
+ $this->assertEquals(count($expected_value), count($actual_value));
+ foreach ($expected_value as $key => $value) {
+ $this->assertArrayHasKey($key, $actual_value);
+ $this->assertMixedValueAndArray($value, $actual_value[$key]);
+ }
+ } elseif (is_callable($expected_value) or is_object($expected_value)) {
+ $this->assertEquals(spl_object_hash($expected_value), spl_object_hash($actual_value));
+ }
+ }
+
+ /**
+ * @covers Raven_Client::_convertPath
+ */
+ public function test_convertPath()
+ {
+ $property = new ReflectionMethod('Raven_Client', '_convertPath');
+ $property->setAccessible(true);
+
+ $this->assertEquals('/foo/bar/', $property->invoke(null, '/foo/bar'));
+ $this->assertEquals('/foo/bar/', $property->invoke(null, '/foo/bar/'));
+ $this->assertEquals('foo/bar', $property->invoke(null, 'foo/bar'));
+ $this->assertEquals('foo/bar/', $property->invoke(null, 'foo/bar/'));
+ $this->assertEquals(dirname(__DIR__).'/', $property->invoke(null, __DIR__.'/../'));
+ $this->assertEquals(dirname(dirname(__DIR__)).'/', $property->invoke(null, __DIR__.'/../../'));
+ }
+
+ /**
+ * @covers Raven_Client::getDefaultProcessors
+ */
+ public function testGetDefaultProcessors()
+ {
+ foreach (Raven_Client::getDefaultProcessors() as $class_name) {
+ $this->assertInternalType('string', $class_name);
+ $this->assertTrue(class_exists($class_name));
+ $reflection = new ReflectionClass($class_name);
+ $this->assertTrue($reflection->isSubclassOf('Raven_Processor'));
+ $this->assertFalse($reflection->isAbstract());
+ }
+ }
+
+ /**
+ * @covers Raven_Client::get_default_ca_cert
+ */
+ public function testGet_default_ca_cert()
+ {
+ $reflection = new ReflectionMethod('Raven_Client', 'get_default_ca_cert');
+ $reflection->setAccessible(true);
+ $this->assertFileExists($reflection->invoke(null));
+ }
+
+ /**
+ * @covers Raven_Client::translateSeverity
+ * @covers Raven_Client::registerSeverityMap
+ */
+ public function testTranslateSeverity()
+ {
+ $reflection = new ReflectionProperty('Raven_Client', 'severity_map');
+ $reflection->setAccessible(true);
+ $client = new Dummy_Raven_Client();
+
+ $predefined = array(E_ERROR, E_WARNING, E_PARSE, E_NOTICE, E_CORE_ERROR, E_CORE_WARNING,
+ E_COMPILE_ERROR, E_COMPILE_WARNING, E_USER_ERROR, E_USER_WARNING,
+ E_USER_NOTICE, E_STRICT, E_RECOVERABLE_ERROR, );
+ if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
+ $predefined[] = E_DEPRECATED;
+ $predefined[] = E_USER_DEPRECATED;
+ }
+ $predefined_values = array('debug', 'info', 'warning', 'warning', 'error', 'fatal', );
+
+ // step 1
+ foreach ($predefined as &$key) {
+ $this->assertContains($client->translateSeverity($key), $predefined_values);
+ }
+ $this->assertEquals('error', $client->translateSeverity(123456));
+ // step 2
+ $client->registerSeverityMap(array());
+ $this->assertMixedValueAndArray(array(), $reflection->getValue($client));
+ foreach ($predefined as &$key) {
+ $this->assertContains($client->translateSeverity($key), $predefined_values);
+ }
+ $this->assertEquals('error', $client->translateSeverity(123456));
+ $this->assertEquals('error', $client->translateSeverity(123456));
+ // step 3
+ $client->registerSeverityMap(array(123456 => 'foo', ));
+ $this->assertMixedValueAndArray(array(123456 => 'foo'), $reflection->getValue($client));
+ foreach ($predefined as &$key) {
+ $this->assertContains($client->translateSeverity($key), $predefined_values);
+ }
+ $this->assertEquals('foo', $client->translateSeverity(123456));
+ $this->assertEquals('error', $client->translateSeverity(123457));
+ // step 4
+ $client->registerSeverityMap(array(E_USER_ERROR => 'bar', ));
+ $this->assertEquals('bar', $client->translateSeverity(E_USER_ERROR));
+ $this->assertEquals('error', $client->translateSeverity(123456));
+ $this->assertEquals('error', $client->translateSeverity(123457));
+ // step 5
+ $client->registerSeverityMap(array(E_USER_ERROR => 'bar', 123456 => 'foo', ));
+ $this->assertEquals('bar', $client->translateSeverity(E_USER_ERROR));
+ $this->assertEquals('foo', $client->translateSeverity(123456));
+ $this->assertEquals('error', $client->translateSeverity(123457));
+ }
+
+ /**
+ * @covers Raven_Client::getUserAgent
+ */
+ public function testGetUserAgent()
+ {
+ $this->assertRegExp('|^[0-9a-z./_-]+$|i', Raven_Client::getUserAgent());
+ }
+
+ public function testCaptureExceptionWithLogger()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->captureException(new Exception(), null, 'foobar');
+
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+ $this->assertEquals('foobar', $event['logger']);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ * @covers Raven_Client::send
+ * @covers Raven_Client::send_remote
+ * @covers Raven_Client::send_http
+ */
+ public function testCurl_method()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'foobar',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $client->captureMessage('foobar');
+ $this->assertTrue($client->_send_http_synchronous);
+ $this->assertFalse($client->_send_http_asynchronous_curl_exec_called);
+
+ // step 2
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'exec',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $client->captureMessage('foobar');
+ $this->assertFalse($client->_send_http_synchronous);
+ $this->assertTrue($client->_send_http_asynchronous_curl_exec_called);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ * @covers Raven_Client::send
+ * @covers Raven_Client::send_remote
+ * @covers Raven_Client::send_http
+ */
+ public function testCurl_method_async()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'async',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $object = $client->get_curl_handler();
+ $this->assertInternalType('object', $object);
+ $this->assertEquals('Raven_CurlHandler', get_class($object));
+
+ $reflection = new ReflectionProperty('Raven_CurlHandler', 'options');
+ $reflection->setAccessible(true);
+ $this->assertEquals($reflection->getValue($object), $client->get_curl_options());
+
+ // step 2
+ $ch = new Dummy_Raven_CurlHandler();
+ $client->set_curl_handler($ch);
+ $client->captureMessage('foobar');
+ $this->assertFalse($client->_send_http_synchronous);
+ $this->assertFalse($client->_send_http_asynchronous_curl_exec_called);
+ $this->assertTrue($ch->_enqueue_called);
+ }
+
+ /**
+ * @backupGlobals
+ * @covers Raven_Client::__construct
+ */
+ public function testConstructWithServerDSN()
+ {
+ $_SERVER['SENTRY_DSN'] = 'http://public:secret@example.com/1';
+ $client = new Dummy_Raven_Client();
+ $this->assertEquals(1, $client->project);
+ $this->assertEquals('http://example.com/api/1/store/', $client->server);
+ $this->assertEquals('public', $client->public_key);
+ $this->assertEquals('secret', $client->secret_key);
+ }
+
+ /**
+ * @backupGlobals
+ * @covers Raven_Client::_server_variable
+ */
+ public function test_server_variable()
+ {
+ $method = new ReflectionMethod('Raven_Client', '_server_variable');
+ $method->setAccessible(true);
+ foreach ($_SERVER as $key => $value) {
+ $actual = $method->invoke(null, $key);
+ $this->assertNotNull($actual);
+ $this->assertEquals($value, $actual);
+ }
+ foreach (array('foo', 'bar', 'foobar', '123456', 'SomeLongNonExistedKey') as $key => $value) {
+ if (!isset($_SERVER[$key])) {
+ $actual = $method->invoke(null, $key);
+ $this->assertNotNull($actual);
+ $this->assertEquals('', $actual);
+ }
+ unset($_SERVER[$key]);
+ $actual = $method->invoke(null, $key);
+ $this->assertNotNull($actual);
+ $this->assertEquals('', $actual);
+ }
+ }
+
+ public function testEncodeTooDepth()
+ {
+ $client = new Dummy_Raven_Client();
+ $data_broken = array();
+ for ($i = 0; $i < 1024; $i++) {
+ $data_broken = array($data_broken);
+ }
+ $value = $client->encode($data_broken);
+ if (!function_exists('json_encode') or version_compare(PHP_VERSION, '5.5.0', '>=')) {
+ $this->assertFalse($value, 'Broken data encoded successfully with '.
+ (function_exists('json_encode') ? 'native method' : 'Raven_Compat::_json_encode'));
+ } else {
+ if ($value !== false) {
+ $this->markTestSkipped();
+ } else {
+ $this->assertEquals('eJyLjh4Fo2AUjFgQOwpGwSgYuQAA3Q7g1w==', $value, 'Native json_encode error');
+ }
+ }
+ }
+
+ public function testEncode()
+ {
+ $client = new Dummy_Raven_Client();
+ $data = array('some' => (object)array('value' => 'data'), 'foo' => array('bar', null, 123), false);
+ $json_stringify = Raven_Compat::json_encode($data);
+ $value = $client->encode($data);
+ $this->assertNotFalse($value);
+ $this->assertRegExp('_^[a-zA-Z0-9/=]+$_', $value, 'Raven_Client::encode returned malformed data');
+ $decoded = base64_decode($value);
+ $this->assertInternalType('string', $decoded, 'Can not use base64 decode on the encoded blob');
+ if (function_exists("gzcompress")) {
+ $decoded = gzuncompress($decoded);
+ $this->assertEquals($json_stringify, $decoded, 'Can not decompress compressed blob');
+ } else {
+ $this->assertEquals($json_stringify, $decoded);
+ }
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ * @covers Raven_Client::registerDefaultBreadcrumbHandlers
+ */
+ public function testRegisterDefaultBreadcrumbHandlers()
+ {
+ if (isset($_ENV['HHVM']) and ($_ENV['HHVM'] == 1)) {
+ $this->markTestSkipped('HHVM stacktrace behaviour');
+ return;
+ }
+ $previous = set_error_handler(array($this, 'stabClosureErrorHandler'), E_USER_NOTICE);
+ new Raven_Client(null, array());
+ $this->_closure_called = false;
+ trigger_error('foobar', E_USER_NOTICE);
+ $u = $this->_closure_called;
+ $debug_backtrace = $this->_debug_backtrace;
+ set_error_handler($previous, E_ALL);
+ $this->assertTrue($u);
+ if (isset($debug_backtrace[1]['function']) and ($debug_backtrace[1]['function'] == 'call_user_func')
+ and version_compare(PHP_VERSION, '7.0', '>=')
+ ) {
+ $offset = 2;
+ } elseif (version_compare(PHP_VERSION, '7.0', '>=')) {
+ $offset = 1;
+ } else {
+ $offset = 2;
+ }
+ $this->assertEquals('Raven_Breadcrumbs_ErrorHandler', $debug_backtrace[$offset]['class']);
+ }
+
+ private $_closure_called = false;
+
+ public function stabClosureVoid()
+ {
+ $this->_closure_called = true;
+ }
+
+ public function stabClosureNull()
+ {
+ $this->_closure_called = true;
+
+ return null;
+ }
+
+ public function stabClosureFalse()
+ {
+ $this->_closure_called = true;
+
+ return false;
+ }
+
+ private $_debug_backtrace = array();
+
+ public function stabClosureErrorHandler($code, $message, $file = '', $line = 0, $context = array())
+ {
+ $this->_closure_called = true;
+ $this->_debug_backtrace = debug_backtrace();
+
+ return true;
+ }
+
+ /**
+ * @covers Raven_Client::onShutdown
+ * @covers Raven_Client::sendUnsentErrors
+ * @covers Raven_Client::capture
+ */
+ public function testOnShutdown()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'foobar',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $this->assertEquals(0, count($client->_pending_events));
+ $client->_pending_events[] = array('foo' => 'bar');
+ $client->sendUnsentErrors();
+ $this->assertTrue($client->_send_http_synchronous);
+ $this->assertFalse($client->_send_http_asynchronous_curl_exec_called);
+ $this->assertEquals(0, count($client->_pending_events));
+
+ // step 2
+ $client->_send_http_synchronous = false;
+ $client->_send_http_asynchronous_curl_exec_called = false;
+
+ $client->store_errors_for_bulk_send = true;
+ $client->captureMessage('foobar');
+ $this->assertEquals(1, count($client->_pending_events));
+ $this->assertFalse($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ $client->_send_http_synchronous = false;
+ $client->_send_http_asynchronous_curl_exec_called = false;
+
+ // step 3
+ $client->onShutdown();
+ $this->assertTrue($client->_send_http_synchronous);
+ $this->assertFalse($client->_send_http_asynchronous_curl_exec_called);
+ $this->assertEquals(0, count($client->_pending_events));
+
+ // step 1
+ $client = null;
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'async',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $ch = new Dummy_Raven_CurlHandler();
+ $client->set_curl_handler($ch);
+ $client->captureMessage('foobar');
+ $client->onShutdown();
+ $client = null;
+ $this->assertTrue($ch->_join_called);
+ }
+
+ /**
+ * @covers Raven_Client::send
+ */
+ public function testNonWorkingSendSendCallback()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'foobar',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $this->_closure_called = false;
+ $client->setSendCallback(array($this, 'stabClosureNull'));
+ $this->assertFalse($this->_closure_called);
+ $data = array('foo' => 'bar');
+ $client->send($data);
+ $this->assertTrue($this->_closure_called);
+ $this->assertTrue($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ // step 2
+ $this->_closure_called = false;
+ $client->_send_http_synchronous = false;
+ $client->_send_http_asynchronous_curl_exec_called = false;
+ $client->setSendCallback(array($this, 'stabClosureFalse'));
+ $this->assertFalse($this->_closure_called);
+ $data = array('foo' => 'bar');
+ $client->send($data);
+ $this->assertTrue($this->_closure_called);
+ $this->assertFalse($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ }
+
+ /**
+ * @covers Raven_Client::send
+ */
+ public function testNonWorkingSendDSNEmpty()
+ {
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'foobar',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $client->server = null;
+ $data = array('foo' => 'bar');
+ $client->send($data);
+ $this->assertFalse($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ }
+
+ /**
+ * @covers Raven_Client::send
+ */
+ public function testNonWorkingSendSetTransport()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'foobar',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ $this->_closure_called = false;
+ $client->setTransport(array($this, 'stabClosureNull'));
+ $this->assertFalse($this->_closure_called);
+ $data = array('foo' => 'bar');
+ $client->send($data);
+ $this->assertTrue($this->_closure_called);
+ $this->assertFalse($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ // step 2
+ $this->_closure_called = false;
+ $client->setSendCallback(array($this, 'stabClosureFalse'));
+ $this->assertFalse($this->_closure_called);
+ $data = array('foo' => 'bar');
+ $client->send($data);
+ $this->assertTrue($this->_closure_called);
+ $this->assertFalse($client->_send_http_synchronous or $client->_send_http_asynchronous_curl_exec_called);
+ }
+
+ /**
+ * @covers Raven_Client::__construct
+ */
+ public function test__construct_handlers()
+ {
+ foreach (array(true, false) as $u1) {
+ foreach (array(true, false) as $u2) {
+ $client = new Dummy_Raven_Client(
+ null, array(
+ 'install_default_breadcrumb_handlers' => $u1,
+ 'install_shutdown_handler' => $u2,
+ )
+ );
+ $this->assertEquals($u1, $client->dummy_breadcrumbs_handlers_has_set);
+ $this->assertEquals($u2, $client->dummy_shutdown_handlers_has_set);
+ }
+ }
+ }
+
+ /**
+ * @covers Raven_Client::__destruct
+ * @covers Raven_Client::close_all_children_link
+ */
+ public function test__destruct_calls_close_functions()
+ {
+ $client = new Dummy_Raven_Client_With_Overrided_Direct_Send(
+ 'http://public:secret@example.com/1', array(
+ 'install_default_breadcrumb_handlers' => false,
+ 'install_shutdown_handler' => false,
+ )
+ );
+ $client::$_close_curl_resource_called = false;
+ $client->close_all_children_link();
+ unset($client);
+ $this->assertTrue(Dummy_Raven_Client_With_Overrided_Direct_Send::$_close_curl_resource_called);
+ }
+
+ /**
+ * @covers Raven_Client::get_user_data
+ */
+ public function testGet_user_data()
+ {
+ // step 1
+ $client = new Dummy_Raven_Client();
+ $output = $client->get_user_data();
+ $this->assertInternalType('array', $output);
+ $this->assertArrayHasKey('user', $output);
+ $this->assertArrayHasKey('id', $output['user']);
+ $session_old = $_SESSION;
+
+ // step 2
+ $session_id = session_id();
+ session_write_close();
+ session_id('');
+ $output = $client->get_user_data();
+ $this->assertInternalType('array', $output);
+ $this->assertEquals(0, count($output));
+
+ // step 3
+ session_id($session_id);
+ @session_start(array('use_cookies' => false, ));
+ $_SESSION = array('foo' => 'bar');
+ $output = $client->get_user_data();
+ $this->assertInternalType('array', $output);
+ $this->assertArrayHasKey('user', $output);
+ $this->assertArrayHasKey('id', $output['user']);
+ $this->assertArrayHasKey('data', $output['user']);
+ $this->assertArrayHasKey('foo', $output['user']['data']);
+ $this->assertEquals('bar', $output['user']['data']['foo']);
+ $_SESSION = $session_old;
+ }
+
+ /**
+ * @covers Raven_Client::capture
+ * @covers Raven_Client::setRelease
+ * @covers Raven_Client::setEnvironment
+ */
+ public function testCaptureLevel()
+ {
+ foreach (array(Raven_Client::MESSAGE_LIMIT * 3, 100) as $length) {
+ $message = '';
+ for ($i = 0; $i < $length; $i++) {
+ $message .= chr($i % 256);
+ }
+ $client = new Dummy_Raven_Client();
+ $client->capture(array('message' => $message, ));
+ $events = $client->getSentEvents();
+ $this->assertEquals(1, count($events));
+ $event = array_pop($events);
+
+ $this->assertEquals('error', $event['level']);
+ $this->assertEquals(substr($message, 0, min(Raven_Client::MESSAGE_LIMIT, $length)), $event['message']);
+ $this->assertArrayNotHasKey('release', $event);
+ $this->assertArrayNotHasKey('environment', $event);
+ }
+
+ $client = new Dummy_Raven_Client();
+ $client->capture(array('message' => 'foobar'));
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ $input = $client->get_http_data();
+ $this->assertEquals($input['request'], $event['request']);
+ $this->assertArrayNotHasKey('release', $event);
+ $this->assertArrayNotHasKey('environment', $event);
+
+ $client = new Dummy_Raven_Client();
+ $client->capture(array('message' => 'foobar', 'request' => array('foo' => 'bar'), ));
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ $this->assertEquals(array('foo' => 'bar'), $event['request']);
+ $this->assertArrayNotHasKey('release', $event);
+ $this->assertArrayNotHasKey('environment', $event);
+
+ foreach (array(false, true) as $u1) {
+ foreach (array(false, true) as $u2) {
+ $client = new Dummy_Raven_Client();
+ if ($u1) {
+ $client->setRelease('foo');
+ }
+ if ($u2) {
+ $client->setEnvironment('bar');
+ }
+ $client->capture(array('message' => 'foobar', ));
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ if ($u1) {
+ $this->assertEquals('foo', $event['release']);
+ } else {
+ $this->assertArrayNotHasKey('release', $event);
+ }
+ if ($u2) {
+ $this->assertEquals('bar', $event['environment']);
+ } else {
+ $this->assertArrayNotHasKey('environment', $event);
+ }
+ }
+ }
+ }
+
+ /**
+ * @covers Raven_Client::capture
+ */
+ public function testCaptureNoUserAndRequest()
+ {
+ $client = new Dummy_Raven_Client_No_Http(null, array(
+ 'install_default_breadcrumb_handlers' => false,
+ ));
+ $session_id = session_id();
+ session_write_close();
+ session_id('');
+ $client->capture(array('user' => '', 'request' => ''));
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ $this->assertArrayNotHasKey('user', $event);
+ $this->assertArrayNotHasKey('request', $event);
+
+ // step 3
+ session_id($session_id);
+ @session_start(array('use_cookies' => false, ));
+ }
+
+ /**
+ * @covers Raven_Client::capture
+ */
+ public function testCaptureNonEmptyBreadcrumb()
+ {
+ $client = new Dummy_Raven_Client();
+ $ts1 = microtime(true);
+ $client->breadcrumbs->record(array('foo' => 'bar'));
+ $client->breadcrumbs->record(array('honey' => 'clover'));
+ $client->capture(array());
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ foreach ($event['breadcrumbs'] as &$crumb) {
+ $this->assertGreaterThanOrEqual($ts1, $crumb['timestamp']);
+ unset($crumb['timestamp']);
+ }
+ $this->assertEquals(array(
+ array('foo' => 'bar'),
+ array('honey' => 'clover'),
+ ), $event['breadcrumbs']);
+ }
+
+
+ /**
+ * @covers Raven_Client::capture
+ */
+ public function testCaptureAutoLogStacks()
+ {
+ $client = new Dummy_Raven_Client();
+ $client->capture(array('auto_log_stacks' => true), true);
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+ $this->assertArrayHasKey('stacktrace', $event);
+ $this->assertInternalType('array', $event['stacktrace']['frames']);
+ }
+
+ /**
+ * @covers Raven_Client::send_http_asynchronous_curl_exec
+ */
+ public function testSend_http_asynchronous_curl_exec()
+ {
+ $client = new Dummy_Raven_Client_With_Sync_Override(
+ 'http://public:secret@example.com/1', array(
+ 'curl_method' => 'exec',
+ 'install_default_breadcrumb_handlers' => false,
+ )
+ );
+ if (file_exists(Dummy_Raven_Client_With_Sync_Override::test_filename())) {
+ unlink(Dummy_Raven_Client_With_Sync_Override::test_filename());
+ }
+ $client->captureMessage('foobar');
+ $test_data = Dummy_Raven_Client_With_Sync_Override::get_test_data();
+ $this->assertStringEqualsFile(Dummy_Raven_Client_With_Sync_Override::test_filename(), $test_data."\n");
+ }
+
+ /**
+ * @covers Raven_Client::close_curl_resource
+ */
+ public function testClose_curl_resource()
+ {
+ $raven = new Dummy_Raven_Client();
+ $reflection = new ReflectionProperty('Raven_Client', '_curl_instance');
+ $reflection->setAccessible(true);
+ $ch = curl_init();
+ $reflection->setValue($raven, $ch);
+ unset($ch);
+
+ $this->assertInternalType('resource', $reflection->getValue($raven));
+ $raven->close_curl_resource();
+ $this->assertNull($reflection->getValue($raven));
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/CompatTest.php b/lib/sentry/sentry/test/Raven/Tests/CompatTest.php
new file mode 100644
index 0000000..4d558d6
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/CompatTest.php
@@ -0,0 +1,113 @@
+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('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
+
+ $result = Raven_Compat::_hash_hmac('sha1', 'foo', 'bar');
+ $this->assertEquals('85d155c55ed286a300bd1cf124de08d87e914f3a', $result);
+
+ $long_key = '0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF';
+ $result = Raven_Compat::_hash_hmac('md5', 'data', $long_key);
+ $this->assertEquals('951038f9ab8a10c929ab6dbc5f927207', $result);
+
+ $result = Raven_Compat::_hash_hmac('sha1', 'data', $long_key);
+ $this->assertEquals('cbf0d1ca10d211da2bc15cb3b579ecfebf3056d2', $result);
+
+ $result = Raven_Compat::_hash_hmac('md5', 'foobar', $long_key);
+ $this->assertEquals('5490f3cddeb9665bce3239cbc4c15e2c', $result);
+
+ $result = Raven_Compat::_hash_hmac('sha1', 'foobar', $long_key);
+ $this->assertEquals('5729f50ff2fbb8f8bf81d7a86f69a89f7574697c', $result);
+
+
+ $result = Raven_Compat::_hash_hmac('md5', 'foo', $long_key);
+ $this->assertEquals('ab193328035cbd3a48dea9d64ba92736', $result);
+
+ $result = Raven_Compat::_hash_hmac('sha1', 'foo', $long_key);
+ $this->assertEquals('8f883d0755115314930968496573f27735eb0c41', $result);
+ }
+
+ public function test_json_encode()
+ {
+ $result = Raven_Compat::json_encode(array('foo' => array('bar' => 1)));
+ $this->assertEquals('{"foo":{"bar":1}}', $result);
+
+ $result = Raven_Compat::_json_encode(array('foo' => array('bar' => 1)));
+ $this->assertEquals('{"foo":{"bar":1}}', $result);
+
+ $result = Raven_Compat::_json_encode(array(1, 2, 3, 4, 'foo', 'bar'));
+ $this->assertEquals('[1,2,3,4,"foo","bar"]', $result);
+
+ $result = Raven_Compat::_json_encode(array(1, 'foo', 'foobar' => 'bar'));
+ $this->assertEquals('{0:1,1:"foo","foobar":"bar"}', $result);
+
+ $result = Raven_Compat::_json_encode(array(array()));
+ $this->assertEquals('[[]]', $result);
+
+ $result = Raven_Compat::_json_encode(array(null, false, true, 1.5));
+ $this->assertEquals('[null,false,true,1.5]', $result);
+ }
+
+ /**
+ * @covers Raven_Compat::_json_encode
+ * @covers Raven_Compat::_json_encode_lowlevel
+ *
+ * I show you how deep the rabbit hole goes
+ */
+ public function test_json_encode_with_broken_data()
+ {
+ $data_broken_named = array();
+ $data_broken_named_510 = null;
+ $data_broken_named_511 = null;
+
+ $data_broken = array();
+ $data_broken_510 = null;
+ $data_broken_511 = null;
+ for ($i = 0; $i < 1024; $i++) {
+ $data_broken = array($data_broken);
+ $data_broken_named = array('a' => $data_broken_named);
+ switch ($i) {
+ case 510:
+ $data_broken_510 = $data_broken;
+ $data_broken_named_510 = $data_broken_named;
+ break;
+ case 511:
+ $data_broken_511 = $data_broken;
+ $data_broken_named_511 = $data_broken_named;
+ break;
+ }
+ }
+ $value_1024 = Raven_Compat::_json_encode($data_broken);
+ $value_510 = Raven_Compat::_json_encode($data_broken_510);
+ $value_511 = Raven_Compat::_json_encode($data_broken_511);
+ $this->assertFalse($value_1024, 'Broken data encoded successfully with Raven_Compat::_json_encode');
+ $this->assertNotFalse($value_510);
+ $this->assertFalse($value_511);
+
+ $value_1024 = Raven_Compat::_json_encode($data_broken_named);
+ $value_510 = Raven_Compat::_json_encode($data_broken_named_510);
+ $value_511 = Raven_Compat::_json_encode($data_broken_named_511);
+ $this->assertFalse($value_1024, 'Broken data encoded successfully with Raven_Compat::_json_encode');
+ $this->assertNotFalse($value_510);
+ $this->assertFalse($value_511);
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/ErrorHandlerTest.php b/lib/sentry/sentry/test/Raven/Tests/ErrorHandlerTest.php
new file mode 100644
index 0000000..64cfc4c
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/ErrorHandlerTest.php
@@ -0,0 +1,246 @@
+errorLevel = error_reporting();
+ $this->errorHandlerCalled = false;
+ $this->existingErrorHandler = set_error_handler(array($this, 'errorHandler'), -1);
+ // improves the reliability of tests
+ if (function_exists('error_clear_last')) {
+ error_clear_last();
+ }
+ }
+
+ public function errorHandler()
+ {
+ $this->errorHandlerCalled = true;
+ }
+
+ public function tearDown()
+ {
+ restore_exception_handler();
+ set_error_handler($this->existingErrorHandler);
+ // // XXX(dcramer): this isn't great as it doesnt restore the old error reporting level
+ // set_error_handler(array($this, 'errorHandler'), error_reporting());
+ error_reporting($this->errorLevel);
+ }
+
+ public function testErrorsAreLoggedAsExceptions()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException', 'sendUnsentErrors'))
+ ->getMock();
+ $client->expects($this->once())
+ ->method('captureException')
+ ->with($this->isInstanceOf('ErrorException'));
+
+ $handler = new Raven_ErrorHandler($client, E_ALL);
+ $handler->handleError(E_WARNING, 'message');
+ }
+
+ public function testExceptionsAreLogged()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $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);
+ }
+
+ public function testErrorHandlerPassErrorReportingPass()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->once())
+ ->method('captureException');
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(false, -1);
+
+ error_reporting(E_USER_WARNING);
+ trigger_error('Warning', E_USER_WARNING);
+ }
+
+ public function testErrorHandlerPropagates()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->never())
+ ->method('captureException');
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(true, E_DEPRECATED);
+
+ error_reporting(E_USER_WARNING);
+ trigger_error('Warning', E_USER_WARNING);
+
+ $this->assertEquals($this->errorHandlerCalled, 1);
+ }
+
+ public function testExceptionHandlerPropagatesToNative()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->exactly(2))
+ ->method('captureException')
+ ->with($this->isInstanceOf('Exception'));
+
+ $handler = new Raven_ErrorHandler($client);
+
+ set_exception_handler(null);
+ $handler->registerExceptionHandler(false);
+
+ $testException = new Exception('Test exception');
+
+ $didRethrow = false;
+ try {
+ $handler->handleException($testException);
+ } catch (Exception $e) {
+ $didRethrow = true;
+ }
+
+ $this->assertFalse($didRethrow);
+
+ set_exception_handler(null);
+ $handler->registerExceptionHandler(true);
+
+ $didRethrow = false;
+ $rethrownException = null;
+ try {
+ $handler->handleException($testException);
+ } catch (Exception $e) {
+ $didRethrow = true;
+ $rethrownException = $e;
+ }
+
+ $this->assertTrue($didRethrow);
+ $this->assertSame($testException, $rethrownException);
+ }
+
+ public function testErrorHandlerRespectsErrorReportingDefault()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->once())
+ ->method('captureException');
+
+ error_reporting(E_DEPRECATED);
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(true);
+
+ error_reporting(E_ALL);
+ trigger_error('Warning', E_USER_WARNING);
+
+ $this->assertEquals($this->errorHandlerCalled, 1);
+ }
+
+ // Because we cannot **know** that a user silenced an error, we always
+ // defer to respecting the error reporting settings.
+ public function testSilentErrorsAreNotReportedWithGlobal()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->never())
+ ->method('captureException');
+
+ error_reporting(E_ALL);
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(true);
+
+ @$undefined;
+
+ // also ensure it doesnt get reported by the fatal handler
+ $handler->handleFatalError();
+ }
+
+ // Because we cannot **know** that a user silenced an error, we always
+ // defer to respecting the error reporting settings.
+ public function testSilentErrorsAreNotReportedWithLocal()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->never())
+ ->method('captureException');
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(true, E_ALL);
+
+ @$my_array[2];
+
+ // also ensure it doesnt get reported by the fatal handler
+ $handler->handleFatalError();
+ }
+
+ public function testShouldCaptureFatalErrorBehavior()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $handler = new Raven_ErrorHandler($client);
+
+ $this->assertEquals($handler->shouldCaptureFatalError(E_ERROR), true);
+
+ $this->assertEquals($handler->shouldCaptureFatalError(E_WARNING), false);
+ }
+
+ public function testErrorHandlerDefaultsErrorReporting()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $client->expects($this->never())
+ ->method('captureException');
+
+ error_reporting(E_USER_ERROR);
+
+ $handler = new Raven_ErrorHandler($client);
+ $handler->registerErrorHandler(false);
+
+ trigger_error('Warning', E_USER_WARNING);
+ }
+
+ public function testFluidInterface()
+ {
+ $client = $this->getMockBuilder('Client')
+ ->setMethods(array('captureException'))
+ ->getMock();
+ $handler = new Raven_ErrorHandler($client);
+ $result = $handler->registerErrorHandler();
+ $this->assertEquals($result, $handler);
+ $result = $handler->registerExceptionHandler();
+ $this->assertEquals($result, $handler);
+ // TODO(dcramer): cant find a great way to test resetting the shutdown
+ // handler
+ // $result = $handler->registerShutdownHandler();
+ // $this->assertEquals($result, $handler);
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/IntegrationTest.php b/lib/sentry/sentry/test/Raven/Tests/IntegrationTest.php
new file mode 100644
index 0000000..be5f67b
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/IntegrationTest.php
@@ -0,0 +1,69 @@
+__sent_events;
+ }
+ public function send(&$data)
+ {
+ if (is_callable($this->send_callback) && call_user_func_array($this->send_callback, array(&$data)) === false) {
+ // if send_callback returns falsely, end native send
+ return;
+ }
+ $this->__sent_events[] = $data;
+ }
+ public static function is_http_request()
+ {
+ return true;
+ }
+ // short circuit breadcrumbs
+ public function registerDefaultBreadcrumbHandlers()
+ {
+ }
+}
+
+class Raven_Tests_IntegrationTest extends PHPUnit_Framework_TestCase
+{
+ private function create_chained_exception()
+ {
+ try {
+ throw new Exception('Foo bar');
+ } catch (Exception $ex) {
+ try {
+ throw new Exception('Child exc', 0, $ex);
+ } catch (Exception $ex2) {
+ return $ex2;
+ }
+ }
+ }
+
+ public function testCaptureSimpleError()
+ {
+ $client = new DummyIntegration_Raven_Client('https://public:secret@example.com/1');
+
+ @mkdir('/no/way');
+
+ $client->captureLastError();
+
+ $events = $client->getSentEvents();
+ $event = array_pop($events);
+
+ $exc = $event['exception']['values'][0];
+ $this->assertEquals($exc['value'], 'mkdir(): No such file or directory');
+ $stack = $exc['stacktrace']['frames'];
+ $lastFrame = $stack[count($stack) - 1];
+ $this->assertEquals(@$lastFrame['filename'], 'test/Raven/Tests/IntegrationTest.php');
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveCookiesProcessorTest.php b/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveCookiesProcessorTest.php
new file mode 100644
index 0000000..c1fe7f2
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveCookiesProcessorTest.php
@@ -0,0 +1,78 @@
+getMockBuilder('\Raven_Client')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->processor = new Raven_Processor_RemoveCookiesProcessor($client);
+ }
+
+ /**
+ * @dataProvider processDataProvider
+ */
+ public function testProcess($inputData, $expectedData)
+ {
+ $this->processor->process($inputData);
+
+ $this->assertArraySubset($expectedData, $inputData);
+ }
+
+ public function processDataProvider()
+ {
+ return array(
+ array(
+ array(
+ 'request' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'foo' => 'bar',
+ 'cookies' => 'baz',
+ 'headers' => array(
+ 'Cookie' => 'bar',
+ 'AnotherHeader' => 'foo',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'foo' => 'bar',
+ 'cookies' => Raven_Processor::STRING_MASK,
+ 'headers' => array(
+ 'Cookie' => Raven_Processor::STRING_MASK,
+ 'AnotherHeader' => 'foo',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveHttpBodyProcessorTest.php b/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveHttpBodyProcessorTest.php
new file mode 100644
index 0000000..d273eba
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/Processor/RemoveHttpBodyProcessorTest.php
@@ -0,0 +1,121 @@
+getMockBuilder('\Raven_Client')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->processor = new Raven_Processor_RemoveHttpBodyProcessor($client);
+ }
+
+ /**
+ * @dataProvider processDataProvider
+ */
+ public function testProcess($inputData, $expectedData)
+ {
+ $this->processor->process($inputData);
+
+ $this->assertArraySubset($expectedData, $inputData);
+ }
+
+ public function processDataProvider()
+ {
+ return array(
+ array(
+ array(
+ 'request' => array(
+ 'method' => 'POST',
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'data' => Raven_Processor::STRING_MASK,
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'method' => 'PUT',
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'data' => Raven_Processor::STRING_MASK,
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'method' => 'PATCH',
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'data' => Raven_Processor::STRING_MASK,
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'method' => 'DELETE',
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'data' => Raven_Processor::STRING_MASK,
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'method' => 'GET',
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'data' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/sentry/raven/test/Raven/Tests/SanitizeDataProcessorTest.php b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeDataProcessorTest.php
similarity index 52%
rename from lib/sentry/raven/test/Raven/Tests/SanitizeDataProcessorTest.php
rename to lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeDataProcessorTest.php
index 40c6aa6..8747dbb 100644
--- a/lib/sentry/raven/test/Raven/Tests/SanitizeDataProcessorTest.php
+++ b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeDataProcessorTest.php
@@ -32,21 +32,21 @@ public function testDoesFilterHttpData()
)
);
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
+ $client = new Dummy_Raven_Client();
+ $processor = new Raven_Processor_SanitizeDataProcessor($client);
$processor->process($data);
$vars = $data['request']['data'];
$this->assertEquals($vars['foo'], 'bar');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['password']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['the_secret']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['a_password_here']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['mypasswd']);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['authorization']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['password']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['the_secret']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['a_password_here']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['mypasswd']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['authorization']);
$this->markTestIncomplete('Array scrubbing has not been implemented yet.');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['card_number']['0']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['card_number']['0']);
}
public function testDoesFilterSessionId()
@@ -59,35 +59,33 @@ public function testDoesFilterSessionId()
)
);
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
+ $client = new Dummy_Raven_Client();
+ $processor = new Raven_Processor_SanitizeDataProcessor($client);
$processor->process($data);
$cookies = $data['request']['cookies'];
- $this->assertEquals($cookies[ini_get('session.name')], Raven_SanitizeDataProcessor::MASK);
+ $this->assertEquals($cookies[ini_get('session.name')], Raven_Processor_SanitizeDataProcessor::STRING_MASK);
}
public function testDoesFilterCreditCard()
{
$data = array(
- 'ccnumba' => '4242424242424242'
+ 'extra' => array(
+ 'ccnumba' => '4242424242424242',
+ ),
);
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
+ $client = new Dummy_Raven_Client();
+ $processor = new Raven_Processor_SanitizeDataProcessor($client);
$processor->process($data);
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $data['ccnumba']);
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $data['extra']['ccnumba']);
}
- /**
- * @covers setProcessorOptions
- *
- */
public function testSettingProcessorOptions()
{
- $client = new Raven_Client();
- $processor = new Raven_SanitizeDataProcessor($client);
+ $client = new Dummy_Raven_Client();
+ $processor = new Raven_Processor_SanitizeDataProcessor($client);
$this->assertEquals($processor->getFieldsRe(), '/(authorization|password|passwd|secret|password_confirmation|card_number|auth_pw)/i', 'got default fields');
$this->assertEquals($processor->getValuesRe(), '/^(?:\d[ -]*?){13,16}$/', 'got default values');
@@ -112,12 +110,15 @@ public function testSettingProcessorOptions()
*/
public function testOverrideOptions($processorOptions, $client_options, $dsn)
{
- $client = new Raven_Client($dsn, $client_options);
+ $client = new Dummy_Raven_Client($dsn, $client_options);
+ /**
+ * @var Raven_Processor_SanitizeDataProcessor $processor
+ */
$processor = $client->processors[0];
- $this->assertInstanceOf('Raven_SanitizeDataProcessor', $processor);
- $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
- $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_SanitizeDataProcessor']['values_re'], 'overwrote values');
+ $this->assertInstanceOf('Raven_Processor_SanitizeDataProcessor', $processor);
+ $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_Processor_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
+ $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_Processor_SanitizeDataProcessor']['values_re'], 'overwrote values');
}
/**
@@ -148,12 +149,15 @@ public function testOverridenSanitize($processorOptions, $client_options, $dsn)
)
);
- $client = new Raven_Client($dsn, $client_options);
+ $client = new Dummy_Raven_Client($dsn, $client_options);
+ /**
+ * @var Raven_Processor_SanitizeDataProcessor $processor
+ */
$processor = $client->processors[0];
- $this->assertInstanceOf('Raven_SanitizeDataProcessor', $processor);
- $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
- $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_SanitizeDataProcessor']['values_re'], 'overwrote values');
+ $this->assertInstanceOf('Raven_Processor_SanitizeDataProcessor', $processor);
+ $this->assertEquals($processor->getFieldsRe(), $processorOptions['Raven_Processor_SanitizeDataProcessor']['fields_re'], 'overwrote fields');
+ $this->assertEquals($processor->getValuesRe(), $processorOptions['Raven_Processor_SanitizeDataProcessor']['values_re'], 'overwrote values');
$processor->process($data);
@@ -164,9 +168,9 @@ public function testOverridenSanitize($processorOptions, $client_options, $dsn)
$this->assertEquals($vars['a_password_here'], 'hello', 'did not alter a_password_here');
$this->assertEquals($vars['mypasswd'], 'hello', 'did not alter mypasswd');
$this->assertEquals($vars['authorization'], 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=', 'did not alter authorization');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['api_token'], 'masked api_token');
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['api_token'], 'masked api_token');
- $this->assertEquals(Raven_SanitizeDataProcessor::MASK, $vars['card_number']['0'], 'masked card_number[0]');
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $vars['card_number']['0'], 'masked card_number[0]');
$this->assertEquals($vars['card_number']['1'], $vars['card_number']['1'], 'did not alter card_number[1]');
}
@@ -178,14 +182,14 @@ public function testOverridenSanitize($processorOptions, $client_options, $dsn)
public static function overrideDataProvider()
{
$processorOptions = array(
- 'Raven_SanitizeDataProcessor' => array(
+ 'Raven_Processor_SanitizeDataProcessor' => array(
'fields_re' => '/(api_token)/i',
'values_re' => '/^(?:\d[ -]*?){15,16}$/'
)
);
$client_options = array(
- 'processors' => array('Raven_SanitizeDataProcessor'),
+ 'processors' => array('Raven_Processor_SanitizeDataProcessor'),
'processorOptions' => $processorOptions
);
@@ -195,4 +199,53 @@ public static function overrideDataProvider()
array($processorOptions, $client_options, $dsn)
);
}
+
+ public function testDoesFilterExceptionDataWithMultipleValues()
+ {
+ // Prerequisite: create an array with an 'exception' that contains 2 entry for 'values' key both containing at
+ // least 1 key that must be masked (i.e. 'password') in one of their 'vars' array in 'frames'.
+ $data = array(
+ 'exception' => array(
+ 'values' => array(
+ array(
+ 'stacktrace' => array(
+ 'frames' => array(
+ array(
+ 'vars' => array(
+ 'credentials' => array(
+ 'password' => 'secretPassword'
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'stacktrace' => array(
+ 'frames' => array(
+ array(
+ 'vars' => array(
+ 'credentials' => array(
+ 'password' => 'anotherSecretPassword'
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $client = new Dummy_Raven_Client();
+ $processor = new Raven_Processor_SanitizeDataProcessor($client);
+ // Action
+ $processor->process($data);
+
+ // Expectation: make sure we mask password in both the values array
+ $passwordValue0 = $data['exception']['values'][0]['stacktrace']['frames'][0]['vars']['credentials']['password'];
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $passwordValue0);
+ $passwordValue1 = $data['exception']['values'][1]['stacktrace']['frames'][0]['vars']['credentials']['password'];
+ $this->assertEquals(Raven_Processor_SanitizeDataProcessor::STRING_MASK, $passwordValue1);
+ }
}
diff --git a/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeHttpHeadersProcessorTest.php b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeHttpHeadersProcessorTest.php
new file mode 100644
index 0000000..a2e56ad
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeHttpHeadersProcessorTest.php
@@ -0,0 +1,83 @@
+getMockBuilder('\Raven_Client')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->processor = new Raven_Processor_SanitizeHttpHeadersProcessor($client);
+ $this->processor->setProcessorOptions(array(
+ 'sanitize_http_headers' => array('User-Defined-Header'),
+ ));
+ }
+
+ /**
+ * @dataProvider processDataProvider
+ */
+ public function testProcess($inputData, $expectedData)
+ {
+ $this->processor->process($inputData);
+
+ $this->assertArraySubset($expectedData, $inputData);
+ }
+
+ public function processDataProvider()
+ {
+ return array(
+ array(
+ array(
+ 'request' => array(
+ 'headers' => array(
+ 'Authorization' => 'foo',
+ 'AnotherHeader' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'headers' => array(
+ 'Authorization' => Raven_Processor::STRING_MASK,
+ 'AnotherHeader' => 'bar',
+ ),
+ ),
+ ),
+ ),
+ array(
+ array(
+ 'request' => array(
+ 'headers' => array(
+ 'User-Defined-Header' => 'foo',
+ 'AnotherHeader' => 'bar',
+ ),
+ ),
+ ),
+ array(
+ 'request' => array(
+ 'headers' => array(
+ 'User-Defined-Header' => Raven_Processor::STRING_MASK,
+ 'AnotherHeader' => 'bar',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeStacktraceProcessorTest.php b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeStacktraceProcessorTest.php
new file mode 100644
index 0000000..b2342c3
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/Processor/SanitizeStacktraceProcessorTest.php
@@ -0,0 +1,113 @@
+client = $this->getMockBuilder('Raven_Client')
+ ->setMethods(array_diff($this->getClassMethods('Raven_Client'), array('captureException', 'capture', 'get_default_data', 'get_http_data', 'get_user_data', 'get_extra_data')))
+ ->getMock();
+
+ $this->client->store_errors_for_bulk_send = true;
+
+ $this->processor = new Raven_Processor_SanitizeStacktraceProcessor($this->client);
+ }
+
+ public function testProcess()
+ {
+ try {
+ throw new \Exception();
+ } catch (\Exception $exception) {
+ $this->client->captureException($exception);
+ }
+
+ foreach ($this->client->_pending_events[0]['exception']['values'] as $exceptionValue) {
+ foreach ($exceptionValue['stacktrace']['frames'] as $frame) {
+ $this->assertArrayHasKey('pre_context', $frame);
+ $this->assertArrayHasKey('context_line', $frame);
+ $this->assertArrayHasKey('post_context', $frame);
+ }
+ }
+
+ $this->processor->process($this->client->_pending_events[0]);
+
+ foreach ($this->client->_pending_events[0]['exception']['values'] as $exceptionValue) {
+ foreach ($exceptionValue['stacktrace']['frames'] as $frame) {
+ $this->assertArrayNotHasKey('pre_context', $frame);
+ $this->assertArrayNotHasKey('context_line', $frame);
+ $this->assertArrayNotHasKey('post_context', $frame);
+ }
+ }
+ }
+
+ public function testProcessWithPreviousException()
+ {
+ try {
+ try {
+ throw new \Exception('foo');
+ } catch (\Exception $exception) {
+ throw new \Exception('bar', 0, $exception);
+ }
+ } catch (\Exception $exception) {
+ $this->client->captureException($exception);
+ }
+
+ foreach ($this->client->_pending_events[0]['exception']['values'] as $exceptionValue) {
+ foreach ($exceptionValue['stacktrace']['frames'] as $frame) {
+ $this->assertArrayHasKey('pre_context', $frame);
+ $this->assertArrayHasKey('context_line', $frame);
+ $this->assertArrayHasKey('post_context', $frame);
+ }
+ }
+
+ $this->processor->process($this->client->_pending_events[0]);
+
+ foreach ($this->client->_pending_events[0]['exception']['values'] as $exceptionValue) {
+ foreach ($exceptionValue['stacktrace']['frames'] as $frame) {
+ $this->assertArrayNotHasKey('pre_context', $frame);
+ $this->assertArrayNotHasKey('context_line', $frame);
+ $this->assertArrayNotHasKey('post_context', $frame);
+ }
+ }
+ }
+
+ /**
+ * Gets all the public and abstracts methods of a given class.
+ *
+ * @param string $className The FCQN of the class
+ *
+ * @return array
+ */
+ private function getClassMethods($className)
+ {
+ $class = new ReflectionClass($className);
+ $methods = array();
+
+ foreach ($class->getMethods() as $method) {
+ if ($method->isPublic() || $method->isAbstract()) {
+ $methods[] = $method->getName();
+ }
+ }
+
+ return $methods;
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/ReprSerializerTest.php b/lib/sentry/sentry/test/Raven/Tests/ReprSerializerTest.php
new file mode 100644
index 0000000..8c8c176
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/ReprSerializerTest.php
@@ -0,0 +1,112 @@
+serialize($input);
+ $this->assertEquals(array('1', '2', '3'), $result);
+ }
+
+ public function testObjectsAreStrings()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = new Raven_StacktraceTestObject();
+ $result = $serializer->serialize($input);
+ $this->assertEquals('Object Raven_StacktraceTestObject', $result);
+ }
+
+ public function testIntsAreInts()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = 1;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals(1, $result);
+ }
+
+ public function testFloats()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = 1.5;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('1.5', $result);
+ }
+
+ public function testBooleans()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = true;
+ $result = $serializer->serialize($input);
+ $this->assertEquals('true', $result);
+
+ $input = false;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('false', $result);
+ }
+
+ public function testNull()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = null;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('null', $result);
+ }
+
+ public function testRecursionMaxDepth()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $input = array();
+ $input[] = &$input;
+ $result = $serializer->serialize($input, 3);
+ $this->assertEquals(array(array(array('Array of length 1'))), $result);
+ }
+
+ /**
+ * @covers Raven_ReprSerializer::serializeValue
+ */
+ public function testSerializeValueResource()
+ {
+ $serializer = new Raven_ReprSerializer();
+ $filename = tempnam(sys_get_temp_dir(), 'sentry_test_');
+ $fo = fopen($filename, 'wb');
+
+ $result = $serializer->serialize($fo);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('Resource stream', $result);
+ }
+
+ /**
+ * @covers Raven_ReprSerializer::serializeValue
+ */
+ public function testSerializeRoundedFloat()
+ {
+ $serializer = new Raven_ReprSerializer();
+
+ $result = $serializer->serialize((double)1);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('1.0', $result);
+
+ $result = $serializer->serialize((double)floor(5 / 2));
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('2.0', $result);
+
+ $result = $serializer->serialize((double)floor(12345.678901234));
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('12345.0', $result);
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/SerializerTest.php b/lib/sentry/sentry/test/Raven/Tests/SerializerTest.php
new file mode 100644
index 0000000..9d8a025
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/SerializerTest.php
@@ -0,0 +1,147 @@
+serialize($input);
+ $this->assertEquals(array('1', '2', '3'), $result);
+ }
+
+ public function testStdClassAreArrays()
+ {
+ $serializer = new Raven_Serializer();
+ $input = new stdClass();
+ $input->foo = 'BAR';
+ $result = $serializer->serialize($input);
+ $this->assertEquals(array('foo' => 'BAR'), $result);
+ }
+
+ public function testObjectsAreStrings()
+ {
+ $serializer = new Raven_Serializer();
+ $input = new Raven_SerializerTestObject();
+ $result = $serializer->serialize($input);
+ $this->assertEquals('Object Raven_SerializerTestObject', $result);
+ }
+
+ public function testIntsAreInts()
+ {
+ $serializer = new Raven_Serializer();
+ $input = 1;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('integer', $result);
+ $this->assertEquals(1, $result);
+ }
+
+ public function testFloats()
+ {
+ $serializer = new Raven_Serializer();
+ $input = 1.5;
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('double', $result);
+ $this->assertEquals(1.5, $result);
+ }
+
+ public function testBooleans()
+ {
+ $serializer = new Raven_Serializer();
+ $input = true;
+ $result = $serializer->serialize($input);
+ $this->assertTrue($result);
+
+ $input = false;
+ $result = $serializer->serialize($input);
+ $this->assertFalse($result);
+ }
+
+ public function testNull()
+ {
+ $serializer = new Raven_Serializer();
+ $input = null;
+ $result = $serializer->serialize($input);
+ $this->assertNull($result);
+ }
+
+ public function testRecursionMaxDepth()
+ {
+ $serializer = new Raven_Serializer();
+ $input = array();
+ $input[] = &$input;
+ $result = $serializer->serialize($input, 3);
+ $this->assertEquals(array(array(array('Array of length 1'))), $result);
+ }
+
+ public function testObjectInArray()
+ {
+ $serializer = new Raven_Serializer();
+ $input = array('foo' => new Raven_Serializer());
+ $result = $serializer->serialize($input);
+ $this->assertEquals(array('foo' => 'Object Raven_Serializer'), $result);
+ }
+
+ /**
+ * @covers Raven_Serializer::serializeString
+ */
+ public function testBrokenEncoding()
+ {
+ $serializer = new Raven_Serializer();
+ foreach (array('7efbce4384', 'b782b5d8e5', '9dde8d1427', '8fd4c373ca', '9b8e84cb90') as $key) {
+ $input = pack('H*', $key);
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ if (function_exists('mb_detect_encoding')) {
+ $this->assertContains(mb_detect_encoding($result), array('ASCII', 'UTF-8'));
+ }
+ }
+ }
+
+ /**
+ * @covers Raven_Serializer::serializeString
+ */
+ public function testLongString()
+ {
+ $serializer = new Raven_Serializer();
+ for ($i = 0; $i < 100; $i++) {
+ foreach (array(100, 1000, 1010, 1024, 1050, 1100, 10000) as $length) {
+ $input = '';
+ for ($i = 0; $i < $length; $i++) {
+ $input .= chr(mt_rand(0, 255));
+ }
+ $result = $serializer->serialize($input);
+ $this->assertInternalType('string', $result);
+ $this->assertLessThanOrEqual(1024, strlen($result));
+ }
+ }
+ }
+
+ /**
+ * @covers Raven_Serializer::serializeValue
+ */
+ public function testSerializeValueResource()
+ {
+ $serializer = new Raven_Serializer();
+ $filename = tempnam(sys_get_temp_dir(), 'sentry_test_');
+ $fo = fopen($filename, 'wb');
+
+ $result = $serializer->serialize($fo);
+ $this->assertInternalType('string', $result);
+ $this->assertEquals('Resource stream', $result);
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/StacktraceTest.php b/lib/sentry/sentry/test/Raven/Tests/StacktraceTest.php
new file mode 100644
index 0000000..f967acf
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/StacktraceTest.php
@@ -0,0 +1,248 @@
+ 0) {
+ return call_user_func('raven_test_recurse', $times, $callback);
+ }
+
+ return call_user_func($callback);
+}
+
+function raven_test_create_stacktrace($args=null, $times=3)
+{
+ return raven_test_recurse($times, 'debug_backtrace');
+}
+
+class Raven_Tests_StacktraceTest extends PHPUnit_Framework_TestCase
+{
+ public function testCanTraceParamContext()
+ {
+ $stack = raven_test_create_stacktrace(array('biz', 'baz'), 0);
+
+ if (isset($stack[0]['function']) and ($stack[0]['function'] == 'call_user_func')) {
+ $offset = 2;
+ } else {
+ $offset = 1;
+ }
+ $frame = $stack[$offset];
+ $params = Raven_Stacktrace::get_frame_context($frame);
+ $this->assertEquals($params['args'], array('biz', 'baz'));
+ $this->assertEquals($params['times'], 0);
+ }
+
+ public function testSimpleTrace()
+ {
+ $stack = array(
+ array(
+ 'file' => dirname(__FILE__).'/resources/a.php',
+ 'line' => 9,
+ 'function' => 'a_test',
+ 'args' => array('friend'),
+ ),
+ array(
+ 'file' => dirname(__FILE__).'/resources/b.php',
+ 'line' => 2,
+ 'args' => array(
+ dirname(__FILE__).'/resources/a.php',
+ ),
+ 'function' => 'include_once',
+ )
+ );
+
+ $frames = Raven_Stacktrace::get_stack_info($stack, true);
+
+ $frame = $frames[0];
+ $this->assertEquals(2, $frame['lineno']);
+ $this->assertNull($frame['function']);
+ $this->assertEquals("include_once 'a.php';", $frame['context_line']);
+ $this->assertFalse(isset($frame['vars']));
+ $frame = $frames[1];
+ $this->assertEquals(9, $frame['lineno']);
+ $this->assertEquals('include_once', $frame['function']);
+ $this->assertEquals('a_test($foo);', $frame['context_line']);
+ $this->assertEquals(dirname(__FILE__) . '/resources/a.php', $frame['vars']['param1']);
+ }
+
+ public function testDoesNotModifyCaptureVars()
+ {
+
+ // PHP's errcontext as passed to the error handler contains REFERENCES to any vars that were in the global scope.
+ // Modification of these would be really bad, since if control is returned (non-fatal error) we'll have altered the state of things!
+ $originalFoo = 'bloopblarp';
+ $newFoo = $originalFoo;
+ $nestedArray = array(
+ 'key' => 'xxxxxxxxxx',
+ );
+
+ $frame = array(
+ "file" => dirname(__FILE__) . "/resources/a.php",
+ "line" => 9,
+ "args"=> array(
+ &$newFoo,
+ &$nestedArray,
+ ),
+ "function" => "a_test",
+ );
+
+ $result = Raven_Stacktrace::get_frame_context($frame, 5);
+
+ // Check we haven't modified our vars.
+ $this->assertEquals($originalFoo, 'bloopblarp');
+ $this->assertEquals($nestedArray['key'], 'xxxxxxxxxx');
+
+ // Check that we did truncate the variable in our output
+ $this->assertEquals($result['param1'], 'bloop');
+ $this->assertEquals($result['param2']['key'], 'xxxxx');
+ }
+
+ public function testDoesFixFrameInfo()
+ {
+ if (isset($_ENV['HHVM']) and ($_ENV['HHVM'] == 1)) {
+ $this->markTestSkipped('HHVM stacktrace behaviour');
+ return;
+ }
+
+ /**
+ * 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.
+ */
+ $stack = raven_test_create_stacktrace();
+
+ $frames = Raven_Stacktrace::get_stack_info($stack, true);
+ // just grab the last few frames
+ $frames = array_slice($frames, -6);
+ $skip_call_user_func_fix = false;
+ if (version_compare(PHP_VERSION, '7.0', '>=')) {
+ $skip_call_user_func_fix = true;
+ foreach ($frames as &$frame) {
+ if (isset($frame['function']) and ($frame['function'] == 'call_user_func')) {
+ $skip_call_user_func_fix = false;
+ break;
+ }
+ }
+ unset($frame);
+ }
+
+ if ($skip_call_user_func_fix) {
+ $frame = $frames[3];
+ $this->assertEquals('raven_test_create_stacktrace', $frame['function']);
+ $frame = $frames[4];
+ $this->assertEquals('raven_test_recurse', $frame['function']);
+ $frame = $frames[5];
+ $this->assertEquals('raven_test_recurse', $frame['function']);
+ } else {
+ $frame = $frames[0];
+ $this->assertEquals('raven_test_create_stacktrace', $frame['function']);
+ $frame = $frames[1];
+ $this->assertEquals('raven_test_recurse', $frame['function']);
+ $frame = $frames[2];
+ $this->assertEquals('call_user_func', $frame['function']);
+ $frame = $frames[3];
+ $this->assertEquals('raven_test_recurse', $frame['function']);
+ $frame = $frames[4];
+ $this->assertEquals('call_user_func', $frame['function']);
+ $frame = $frames[5];
+ $this->assertEquals('raven_test_recurse', $frame['function']);
+ }
+ }
+
+ public function testInApp()
+ {
+ $stack = array(
+ array(
+ "file" => dirname(__FILE__) . "/resources/a.php",
+ "line" => 11,
+ "function" => "a_test",
+ ),
+ array(
+ "file" => dirname(__FILE__) . "/resources/b.php",
+ "line" => 3,
+ "function" => "include_once",
+ ),
+ );
+
+ $frames = Raven_Stacktrace::get_stack_info($stack, true, null, 0, null, dirname(__FILE__));
+
+ $this->assertEquals($frames[0]['in_app'], true);
+ $this->assertEquals($frames[1]['in_app'], true);
+ }
+
+ public function testInAppWithExclusion()
+ {
+ $stack = array(
+ array(
+ "file" => dirname(__FILE__) . '/resources/foo/a.php',
+ "line" => 11,
+ "function" => "a_test",
+ ),
+ array(
+ "file" => dirname(__FILE__) . '/resources/bar/b.php',
+ "line" => 3,
+ "function" => "include_once",
+ ),
+ );
+
+ $frames = Raven_Stacktrace::get_stack_info(
+ $stack, true, null, 0, null, dirname(__FILE__) . '/',
+ array(dirname(__FILE__) . '/resources/bar/'));
+
+ // stack gets reversed
+ $this->assertEquals($frames[0]['in_app'], false);
+ $this->assertEquals($frames[1]['in_app'], true);
+ }
+
+ public function testBasePath()
+ {
+ $stack = array(
+ array(
+ "file" => dirname(__FILE__) . "/resources/a.php",
+ "line" => 11,
+ "function" => "a_test",
+ ),
+ );
+
+ $frames = Raven_Stacktrace::get_stack_info($stack, true, null, 0, array(dirname(__FILE__) . '/'));
+
+ $this->assertEquals($frames[0]['filename'], 'resources/a.php');
+ }
+
+ public function testNoBasePath()
+ {
+ $stack = array(
+ array(
+ "file" => dirname(__FILE__) . "/resources/a.php",
+ "line" => 11,
+ "function" => "a_test",
+ ),
+ );
+
+ $frames = Raven_Stacktrace::get_stack_info($stack);
+ $this->assertEquals($frames[0]['filename'], dirname(__FILE__) . '/resources/a.php');
+ }
+
+ public function testWithEvaldCode()
+ {
+ try {
+ eval("throw new Exception('foobar');");
+ } catch (Exception $ex) {
+ $trace = $ex->getTrace();
+ $frames = Raven_Stacktrace::get_stack_info($trace);
+ }
+ /**
+ * @var array $frames
+ */
+ $this->assertEquals($frames[count($frames) -1]['filename'], __FILE__);
+ }
+}
diff --git a/lib/sentry/sentry/test/Raven/Tests/TransactionStackTest.php b/lib/sentry/sentry/test/Raven/Tests/TransactionStackTest.php
new file mode 100644
index 0000000..1994180
--- /dev/null
+++ b/lib/sentry/sentry/test/Raven/Tests/TransactionStackTest.php
@@ -0,0 +1,35 @@
+push('hello');
+ /** @noinspection PhpVoidFunctionResultUsedInspection */
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $foo = $stack->push('foo');
+ $stack->push('bar');
+ $stack->push('world');
+ $this->assertEquals($stack->peek(), 'world');
+ $this->assertEquals($stack->pop(), 'world');
+ $this->assertEquals($stack->pop('foo'), 'foo');
+ $this->assertEquals($stack->peek(), 'hello');
+ $this->assertEquals($stack->pop(), 'hello');
+ $this->assertEquals($stack->peek(), null);
+
+ $stack->clear();
+ $this->assertInternalType('array', $stack->stack);
+ $this->assertEquals(0, count($stack->stack));
+ }
+}
diff --git a/lib/sentry/raven/test/Raven/Tests/UtilTest.php b/lib/sentry/sentry/test/Raven/Tests/UtilTest.php
similarity index 100%
rename from lib/sentry/raven/test/Raven/Tests/UtilTest.php
rename to lib/sentry/sentry/test/Raven/Tests/UtilTest.php
diff --git a/lib/sentry/raven/test/Raven/Tests/resources/a.php b/lib/sentry/sentry/test/Raven/Tests/resources/a.php
similarity index 82%
rename from lib/sentry/raven/test/Raven/Tests/resources/a.php
rename to lib/sentry/sentry/test/Raven/Tests/resources/a.php
index 78ae29c..1d8ed2e 100644
--- a/lib/sentry/raven/test/Raven/Tests/resources/a.php
+++ b/lib/sentry/sentry/test/Raven/Tests/resources/a.php
@@ -1,6 +1,4 @@
captureException(new \Exception());
diff --git a/lib/sentry/raven/test/bootstrap.php b/lib/sentry/sentry/test/bootstrap.php
similarity index 100%
rename from lib/sentry/raven/test/bootstrap.php
rename to lib/sentry/sentry/test/bootstrap.php
diff --git a/lib/sentry/sentry/test/data/binary b/lib/sentry/sentry/test/data/binary
new file mode 100644
index 0000000000000000000000000000000000000000..a10c242e0ddc267623eaddba058ab8554d687ea3
GIT binary patch
literal 128
zcmV-`0Du2IPfVTpcWcyB=dagn7|>m@0z2ew>--#YD^o_57e9z
literal 0
HcmV?d00001
From e6e01697a5cfc5df4128378fc968db8097f6af13 Mon Sep 17 00:00:00 2001
From: Kevin Krieger
Date: Tue, 19 Sep 2017 21:39:41 +0200
Subject: [PATCH 2/4] add mapping remove sentry package
---
composer.json | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 9a81383..30813e4 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,6 @@
"require": {
"magento-hackathon/magento-composer-installer": "*",
"firegento/logger": "1.*",
- "sentry/sentry": "*"
},
"extra": {
"magento-root-dir": "./",
@@ -28,6 +27,10 @@
"./app/code/community/Hackathon/LoggerSentry",
"./app/code/community/Hackathon/LoggerSentry"
],
+ [
+ "./lib/sentry",
+ "./lib/sentry",
+ ],
[
"./app/etc/modules/Hackathon_LoggerSentry.xml",
"./app/etc/modules/Hackathon_LoggerSentry.xml"
From 583fce13eda0e51b3fb1af04ea448f512967a947 Mon Sep 17 00:00:00 2001
From: Kevin Krieger
Date: Tue, 19 Sep 2017 21:41:50 +0200
Subject: [PATCH 3/4] fix syntax
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 30813e4..1c134a6 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
],
"require": {
"magento-hackathon/magento-composer-installer": "*",
- "firegento/logger": "1.*",
+ "firegento/logger": "1.*"
},
"extra": {
"magento-root-dir": "./",
From abb548369c32a0571cee455af82e1912f4e901a9 Mon Sep 17 00:00:00 2001
From: Kevin Krieger
Date: Tue, 19 Sep 2017 21:45:00 +0200
Subject: [PATCH 4/4] fix syntax
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 1c134a6..6b8d93c 100644
--- a/composer.json
+++ b/composer.json
@@ -29,7 +29,7 @@
],
[
"./lib/sentry",
- "./lib/sentry",
+ "./lib/sentry"
],
[
"./app/etc/modules/Hackathon_LoggerSentry.xml",