From f61a8fef380c8479b5b5b75fea404db8e35848bd Mon Sep 17 00:00:00 2001 From: truerainbow Date: Wed, 19 Oct 2016 12:55:11 +0600 Subject: [PATCH 01/45] check global var --- src/DataBuilder.php | 47 +++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 18ccee0d..680ac659 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -482,14 +482,20 @@ protected function getRequest() $scrubFields = $this->getScrubFields(); $request = new Request(); $request->setUrl($this->getUrl($scrubFields)) - ->setMethod($this->tryGet($_SERVER, 'REQUEST_METHOD')) ->setHeaders($this->getScrubbedHeaders($scrubFields)) ->setParams($this->getRequestParams()) - ->setGet(self::scrub($_GET, $scrubFields)) - ->setQueryString(self::scrubUrl($this->tryGet($_SERVER, "QUERY_STRING"), $scrubFields)) - ->setPost(self::scrub($_POST, $scrubFields)) ->setBody($this->getRequestBody()) ->setUserIp($this->getUserIp()); + if (isset($_SERVER)) { + $request->setMethod($this->tryGet($_SERVER, 'REQUEST_METHOD')) + ->setQueryString(self::scrubUrl($this->tryGet($_SERVER, "QUERY_STRING"), $scrubFields)); + } + if (isset($_GET)) { + $request->setGet(self::scrub($_GET, $scrubFields)); + } + if (isset($_POST)) { + $request->setPost(self::scrub($_POST, $scrubFields)); + } $extras = $this->getRequestExtras(); if (!$extras) { $extras = array(); @@ -501,7 +507,7 @@ protected function getRequest() $request->$key = $val; } } - if (is_array($_SESSION) && count($_SESSION) > 0) { + if (isset($_SESSION) && is_array($_SESSION) && count($_SESSION) > 0) { $request->session = self::scrub($_SESSION, $scrubFields); } return $request; @@ -538,13 +544,15 @@ protected function getUrl($scrubFields) $port = 80; } - $path = Utilities::coalesce($this->tryGet($_SERVER, 'REQUEST_URI'), '/'); $url = $proto . '://' . $host; if (($proto == 'https' && $port != 443) || ($proto == 'http' && $port != 80)) { $url .= ':' . $port; } - $url .= $path; + if (isset($_SERVER)) { + $path = Utilities::coalesce($this->tryGet($_SERVER, 'REQUEST_URI'), '/'); + $url .= $path; + } if ($host == 'unknown') { $url = null; @@ -562,16 +570,18 @@ protected function getScrubbedHeaders($scrubFields) protected function getHeaders() { $headers = array(); - foreach ($_SERVER as $key => $val) { - if (substr($key, 0, 5) == 'HTTP_') { - // convert HTTP_CONTENT_TYPE to Content-Type, HTTP_HOST to Host, etc. - $name = strtolower(substr($key, 5)); - if (strpos($name, '_') != -1) { - $name = preg_replace('/ /', '-', ucwords(preg_replace('/_/', ' ', $name))); - } else { - $name = ucfirst($name); + if (isset($_SERVER)) { + foreach ($_SERVER as $key => $val) { + if (substr($key, 0, 5) == 'HTTP_') { + // convert HTTP_CONTENT_TYPE to Content-Type, HTTP_HOST to Host, etc. + $name = strtolower(substr($key, 5)); + if (strpos($name, '_') != -1) { + $name = preg_replace('/ /', '-', ucwords(preg_replace('/_/', ' ', $name))); + } else { + $name = ucfirst($name); + } + $headers[$name] = $val; } - $headers[$name] = $val; } } if (count($headers) > 0) { @@ -593,6 +603,9 @@ protected function getRequestBody() protected function getUserIp() { + if (!isset($_SERVER)) { + return null; + } $forwardFor = $this->tryGet($_SERVER, 'HTTP_X_FORWARDED_FOR'); if ($forwardFor) { // return everything until the first comma @@ -660,7 +673,7 @@ protected function getServer() $server->$key = $val; } } - if (array_key_exists('argv', $_SERVER)) { + if (isset($_SERVER) && array_key_exists('argv', $_SERVER)) { $server->argv = $_SERVER['argv']; } return $server; From caea07956ab23015e99aee87428beb5eb3c89517 Mon Sep 17 00:00:00 2001 From: Andrei Baibaratsky Date: Tue, 9 May 2017 14:00:33 +0200 Subject: [PATCH 02/45] Added links to packages for Yii --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d6fd9082..576e0d4d 100644 --- a/README.md +++ b/README.md @@ -462,6 +462,10 @@ A CakePHP-specific package is avaliable for integrating with CakePHP 2.x: A Flow-specific package is available for integrating with Neos Flow: [m12/flow-rollbar](https://packagist.org/packages/m12/flow-rollbar) +Yii package: [baibaratsky/yii-rollbar](https://github.com/baibaratsky/yii-rollbar) + +Yii2 package: [baibaratsky/yii2-rollbar](https://github.com/baibaratsky/yii2-rollbar) + ## Help / Support If you run into any issues, please email us at [support@rollbar.com](mailto:support@rollbar.com) From 9c8d6843996aba281a19de5d247317bc7361969c Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Thu, 25 May 2017 14:41:56 +0000 Subject: [PATCH 03/45] github-173: only add arguments in backtraces if local vars dump is enabled --- src/DataBuilder.php | 12 +++++++++++- src/Defaults.php | 7 +++++++ tests/DataBuilderTest.php | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 4a452eeb..6eda9968 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -57,6 +57,7 @@ class DataBuilder implements DataBuilderInterface protected $includeExcCodeContext; protected $shiftFunction; protected $sendMessageTrace; + protected $localVarsDump; public function __construct($config) { @@ -90,6 +91,7 @@ public function __construct($config) $this->setIncludeCodeContext($config); $this->setIncludeExcCodeContext($config); $this->setSendMessageTrace($config); + $this->setLocalVarsDump($config); $this->shiftFunction = $this->tryGet($config, 'shift_function'); if (!isset($this->shiftFunction)) { @@ -161,6 +163,12 @@ protected function setSendMessageTrace($config) $this->sendMessageTrace = self::$defaults->sendMessageTrace($fromConfig); } + protected function setLocalVarsDump($config) + { + $fromConfig = $this->tryGet($config, 'local_vars_dump'); + $this->localVarsDump = self::$defaults->localVarsDump($fromConfig); + } + protected function setCodeVersion($config) { $fromConfig = $this->tryGet($config, 'codeVersion'); @@ -461,7 +469,9 @@ protected function getMessage($toLog, $context) return new Message( (string)$toLog, $context, - $this->sendMessageTrace ? debug_backtrace() : null + $this->sendMessageTrace ? + debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) : + null ); } diff --git a/src/Defaults.php b/src/Defaults.php index bf9e1fa3..3f34f70a 100644 --- a/src/Defaults.php +++ b/src/Defaults.php @@ -86,6 +86,11 @@ public function sendMessageTrace($sendMessageTrace = null) { return $sendMessageTrace ? $sendMessageTrace : $this->defaultSendMessageTrace; } + + public function localVarsDump($localVarsDump = null) + { + return $localVarsDump ? $localVarsDump : $this->defaultLocalVarsDump; + } private $defaultMessageLevel = "warning"; private $defaultExceptionLevel = "error"; @@ -102,6 +107,7 @@ public function sendMessageTrace($sendMessageTrace = null) private $defaultSendMessageTrace; private $defaultIncludeCodeContext; private $defaultIncludeExcCodeContext; + private $defaultLocalVarsDump; public function __construct() { @@ -151,6 +157,7 @@ public function __construct() $this->defaultSendMessageTrace = false; $this->defaultIncludeCodeContext = false; $this->defaultIncludeExcCodeContext = false; + $this->defaultLocalVarsDump = false; } public function messageLevel($level = null) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 73b6b2ce..bcb632da 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -348,6 +348,10 @@ public function testGetMessage() $result = $dataBuilder->makeData(Level::fromName('error'), "testing", array()); $this->assertNull($result->getBody()->getValue()->getBacktrace()); + } + + public function testGetMessageSendMessageTrace() + { $dataBuilder = new DataBuilder(array( 'accessToken' => 'abcd1234efef5678abcd1234567890be', @@ -357,6 +361,39 @@ public function testGetMessage() $result = $dataBuilder->makeData(Level::fromName('error'), "testing", array()); $this->assertNotEmpty($result->getBody()->getValue()->getBacktrace()); + + } + + public function testGetMessageTraceArguments() + { + // Negative test + $c = new Config(array( + 'access_token' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests', + 'send_message_trace' => true + )); + $dataBuilder = $c->getDataBuilder(); + + $result = $dataBuilder->makeData(Level::fromName('error'), 'testing', array()); + $frames = $result->getBody()->getValue()->getBacktrace(); + + $this->assertArrayNotHasKey('args', $frames[0], "Arguments in stack frames included when they should have not been."); + + // Positive test + $c = new Config(array( + 'access_token' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests', + 'send_message_trace' => true, + 'local_vars_dump' => true + )); + $dataBuilder = $c->getDataBuilder(); + + $expected = 'testing'; + $result = $dataBuilder->makeData(Level::fromName('error'), $expected, array()); + $frames = $result->getBody()->getValue()->getBacktrace(); + + $this->assertEquals($frames[0]['args'][0], $expected, "Arguments in stack frames NOT included when they should be."); + } public function testExceptionFramesWithoutContext() From b3c27d7f25708219b1cc8c4c7101792c1a834c4d Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Thu, 25 May 2017 15:08:54 +0000 Subject: [PATCH 04/45] github-173: add arguments to stack frames based on local vars dumpo --- src/DataBuilder.php | 6 +++++- tests/DataBuilderTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 6eda9968..9123580d 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -402,11 +402,15 @@ public function makeFrames($exception, $includeContext) $filename = Utilities::coalesce($this->tryGet($frameInfo, 'file'), ''); $lineno = Utilities::coalesce($this->tryGet($frameInfo, 'line'), 0); $method = $frameInfo['function']; - // TODO 4 (arguments are in $frame) + $args = Utilities::coalesce($this->tryGet($frameInfo, 'args'), null); $frame = new Frame($filename); $frame->setLineno($lineno) ->setMethod($method); + + if ($this->localVarsDump && $args !== null) { + $frame->setArgs($args); + } if ($includeContext) { $this->addCodeContextToFrame($frame, $filename, $lineno); diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index bcb632da..b22e4893 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -395,6 +395,35 @@ public function testGetMessageTraceArguments() $this->assertEquals($frames[0]['args'][0], $expected, "Arguments in stack frames NOT included when they should be."); } + + public function testExceptionTraceArguments() + { + // Negative test + $dataBuilder = new DataBuilder(array( + 'accessToken' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests' + )); + $ex = $this->exceptionTraceArgsHelper('trace args message'); + $frames = $dataBuilder->getExceptionTrace($ex)->getFrames(); + $this->assertNull($frames[0]->getArgs(), "Frames arguments available in trace when they should not be."); + + // Positive test + $dataBuilder = new DataBuilder(array( + 'accessToken' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests', + 'local_vars_dump' => true + )); + $expected = 'trace args message'; + $ex = $this->exceptionTraceArgsHelper($expected); + $frames = $dataBuilder->getExceptionTrace($ex)->getFrames(); + + $this->assertEquals($frames[0]->getArgs()[0], $expected, "Frames arguments NOT available in trace when they should be."); + } + + private function exceptionTraceArgsHelper($message) + { + return new \Exception($message); + } public function testExceptionFramesWithoutContext() { From 9add69e0b451c62eeef17a196097f46fb798c397 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Thu, 25 May 2017 19:39:14 +0000 Subject: [PATCH 05/45] github-173: add arguments to stack frames for errors depending on local vars dump config --- src/DataBuilder.php | 21 +++++++++++++++++++++ src/Rollbar.php | 11 +++++++---- src/RollbarLogger.php | 5 +++++ tests/DataBuilderTest.php | 7 +++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 9123580d..21a13240 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -994,4 +994,25 @@ public function needsTruncating(array $payload) { return strlen(json_encode($payload)) > self::MAX_PAYLOAD_SIZE; } + + /** + * Wrap a PHP error in an ErrorWrapper class and add backtrace information + * + * @param string $errno + * @param string $errstr + * @param string $errfile + * @param string $errline + * + * @return ErrorWrapper + */ + public function generateErrorWrapper($errno, $errstr, $errfile, $errline) + { + // removing this function and the handler function to make sure they're + // not part of the backtrace + $backTrace = array_slice( + debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS), + 2 + ); + return new ErrorWrapper($errno, $errstr, $errfile, $errline, $backTrace); + } } diff --git a/src/Rollbar.php b/src/Rollbar.php index 9ae373c5..2fceef83 100644 --- a/src/Rollbar.php +++ b/src/Rollbar.php @@ -108,10 +108,13 @@ public static function fatalHandler() private static function generateErrorWrapper($errno, $errstr, $errfile, $errline) { - // removing this function and the handler function to make sure they're - // not part of the backtrace - $backTrace = array_slice(debug_backtrace(), 2); - return new ErrorWrapper($errno, $errstr, $errfile, $errline, $backTrace); + if (null === self::$logger) { + return; + } + + $dataBuilder = self::$logger->getDataBuilder(); + + return $dataBuilder->generateErrorWrapper($errno, $errstr, $errfile, $errline); } private static function getNotInitializedResponse() diff --git a/src/RollbarLogger.php b/src/RollbarLogger.php index d7d5edbb..1109552d 100644 --- a/src/RollbarLogger.php +++ b/src/RollbarLogger.php @@ -65,6 +65,11 @@ protected function getAccessToken() { return $this->config->getAccessToken(); } + + public function getDataBuilder() + { + return $this->config->getDataBuilder(); + } protected function handleResponse($payload, $response) { diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index b22e4893..9401f68f 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1009,4 +1009,11 @@ public function truncateProvider() return $data; } + + public function testGenerateErrorWrapper() + { + $result = $this->dataBuilder->generateErrorWrapper(E_ERROR, 'bork', null, null); + + $this->assertInstanceOf(ErrorWrapper::class, $result); + } } From 858678b6857b4f9698403019522993cac6f8aebd Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Fri, 26 May 2017 15:22:45 +0000 Subject: [PATCH 06/45] github-173: add documentation for local_vars_dump to README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9d60625b..953689e2 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,12 @@ Default: No proxy Default: `false` +
local_vars_dump
+
Should backtraces include arguments passed to stack frames. + +Default: `false` +
+ Example use of error_sample_rates: From c0f90698b764d8a0ff6510318b849ca359d83070 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Sun, 28 May 2017 18:50:23 +0000 Subject: [PATCH 07/45] github-137: partial implementation of rollbar js helper --- data/rollbar.snippet.js | 1 + src/Config.php | 16 +++ src/RollbarJsHelper.php | 137 ++++++++++++++++++ tests/RollbarJsHelperTest.php | 258 ++++++++++++++++++++++++++++++++++ 4 files changed, 412 insertions(+) create mode 100644 data/rollbar.snippet.js create mode 100644 src/RollbarJsHelper.php create mode 100644 tests/RollbarJsHelperTest.php diff --git a/data/rollbar.snippet.js b/data/rollbar.snippet.js new file mode 100644 index 00000000..ef15e25c --- /dev/null +++ b/data/rollbar.snippet.js @@ -0,0 +1 @@ +!function(r){function e(t){if(o[t])return o[t].exports;var n=o[t]={exports:{},id:t,loaded:!1};return r[t].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var o={};return e.m=r,e.c=o,e.p="",e(0)}([function(r,e,o){"use strict";var t=o(1).Rollbar,n=o(2);_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://d37gvrvc0wt4s1.cloudfront.net/js/v1.9/rollbar.min.js";var a=t.init(window,_rollbarConfig),i=n(a,_rollbarConfig);a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,i)},function(r,e){"use strict";function o(r){return function(){try{return r.apply(this,arguments)}catch(e){try{console.error("[Rollbar]: Internal error",e)}catch(o){}}}}function t(r,e,o){window._rollbarWrappedError&&(o[4]||(o[4]=window._rollbarWrappedError),o[5]||(o[5]=window._rollbarWrappedError._rollbarContext),window._rollbarWrappedError=null),r.uncaughtError.apply(r,o),e&&e.apply(window,o)}function n(r){var e=function(){var e=Array.prototype.slice.call(arguments,0);t(r,r._rollbarOldOnError,e)};return e.belongsToShim=!0,e}function a(r){this.shimId=++c,this.notifier=null,this.parentShim=r,this._rollbarOldOnError=null}function i(r){var e=a;return o(function(){if(this.notifier)return this.notifier[r].apply(this.notifier,arguments);var o=this,t="scope"===r;t&&(o=new e(this));var n=Array.prototype.slice.call(arguments,0),a={shim:o,method:r,args:n,ts:new Date};return window._rollbarShimQueue.push(a),t?o:void 0})}function l(r,e){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){var o=e.addEventListener;e.addEventListener=function(e,t,n){o.call(this,e,r.wrap(t),n)};var t=e.removeEventListener;e.removeEventListener=function(r,e,o){t.call(this,r,e&&e._wrapped?e._wrapped:e,o)}}}var c=0;a.init=function(r,e){var t=e.globalAlias||"Rollbar";if("object"==typeof r[t])return r[t];r._rollbarShimQueue=[],r._rollbarWrappedError=null,e=e||{};var i=new a;return o(function(){if(i.configure(e),e.captureUncaught){i._rollbarOldOnError=r.onerror,r.onerror=n(i);var o,a,c="EventTarget,Window,Node,ApplicationCache,AudioTrackList,ChannelMergerNode,CryptoOperation,EventSource,FileReader,HTMLUnknownElement,IDBDatabase,IDBRequest,IDBTransaction,KeyOperation,MediaController,MessagePort,ModalWindow,Notification,SVGElementInstance,Screen,TextTrack,TextTrackCue,TextTrackList,WebSocket,WebSocketWorker,Worker,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload".split(",");for(o=0;osetResponseHandler($c); $this->setCheckIgnoreFunction($c); $this->setSendMessageTrace($c); + $this->setJsEnabled($c); if (isset($c['included_errno'])) { $this->included_errno = $c['included_errno']; @@ -232,6 +239,15 @@ private function setSendMessageTrace($c) $this->sendMessageTrace = $c['send_message_trace']; } + private function setJsEnabled($c) + { + if (!isset($c['js_enabled'])) { + return; + } + + $this->jsEnabled = $c['js_enabled']; + } + /** * Allows setting up configuration options that might be specified by class * name. Any interface used with `setupWithOptions` should be constructed diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php new file mode 100644 index 00000000..6c5c8296 --- /dev/null +++ b/src/RollbarJsHelper.php @@ -0,0 +1,137 @@ +config = $config; + // } + + /** + * Build RollbarJS script tag + * + * @param array $headers + * @param string $nonce + * + * @return string + */ + public function snippetJsTag($headers, $nonce = null) + { + return $this->scriptTag($this->jsSnippet(), $headers, $nonce); + } + + /** + * Build rollbar.snippet.js string + * + * @return string + */ + public function jsSnippet() + { + return file_get_contents( + $this->snippetPath() + ); + } + + /** + * @return string Path to the rollbar.snippet.js + */ + public function snippetPath() + { + return realpath(__DIR__ . "/../data/rollbar.snippet.js"); + } + + /** + * Should JS snippet be added to the HTTP response + * + * @param int $status + * @param array $headers + * + * @return boolean + */ + public function shouldAddJs($status, $headers) + { + return + $status == 200 && + $this->isHtml($headers) && + !$this->hasAttachment($headers); + + /** + * @todo not sure if below two conditions will be applicable + */ + /* !env[JS_IS_INJECTED_KEY] */ + /* && !streaming?(env) */ + } + + /** + * Is the HTTP response a valid HTML response + * + * @param array $headers + * + * @return boolean + */ + public function isHtml($headers) + { + return in_array('Content-Type: text/html', $headers); + } + + /** + * Does the HTTP response include an attachment + * + * @param array $headers + * + * @return boolean + */ + public function hasAttachment($headers) + { + return in_array('Content-Disposition: attachment', $headers); + } + + /** + * Is `nonce` attribute on the script tag needed? + * + * @param array $headers + * + * @return boolean + */ + public function shouldAppendNonce($headers) + { + foreach ($headers as $header) { + if (strpos($header, 'Content-Security-Policy') !== false && + strpos($header, "'unsafe-inline'") !== false) { + + return true; + + } + } + + return false; + } + + /** + * Build safe HTML script tag + * + * @param string $content + * @param array $headers + * @param + * + * @return string + */ + public function scriptTag($content, $headers, $nonce = null) + { + if ($this->shouldAppendNonce($headers)) { + + if (!$nonce) { + throw new \Exception('Content-Security-Policy is script-src '. + 'inline-unsafe but nonce value not provided.'); + } + + return "\n"; + } else { + return "\n"; + } + } +} \ No newline at end of file diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php new file mode 100644 index 00000000..7ab1b634 --- /dev/null +++ b/tests/RollbarJsHelperTest.php @@ -0,0 +1,258 @@ +jsHelper = new RollbarJsHelper(); + $this->testSnippetPath = realpath(__DIR__ . "/../data/rollbar.snippet.js"); + } + + public function testSnippetPath() + { + $this->assertEquals( + $this->testSnippetPath, + $this->jsHelper->snippetPath() + ); + } + + /** + * @dataProvider shouldAddJsProvider + */ + public function testShouldAddJs($setup, $expected) + { + $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); + + $mock->shouldReceive('isEnabled') + ->andReturn($setup['isEnabled']); + + $status = $setup['status']; + + $mock->shouldReceive('isHtml') + ->andReturn($setup['isHtml']); + + $mock->shouldReceive('hasAttachment') + ->andReturn($setup['hasAttachment']); + + $mock->shouldReceive('shouldAddJs') + ->passthru(); + + $this->assertEquals($expected, $mock->shouldAddJs($status, array())); + } + + public function shouldAddJsProvider() + { + return array( + array( + array( + 'status' => 200, + 'isHtml' => true, + 'hasAttachment' => false + ), + true + ), + array( + array( + 'status' => 500, + 'isHtml' => true, + 'hasAttachment' => false + ), + false + ), + array( + array( + 'status' => 200, + 'isHtml' => false, + 'hasAttachment' => false + ), + false + ), + array( + array( + 'status' => 200, + 'isHtml' => true, + 'hasAttachment' => true + ), + false + ), + ); + } + + /** + * @dataProvider isHtmlProvider + */ + public function testIsHtml($headers, $expected) + { + $this->assertEquals( + $expected, + $this->jsHelper->isHtml($headers) + ); + } + + public function isHtmlProvider() + { + return array( + array( + array( + 'Content-Type: text/html' + ), + true + ), + array( + array( + 'Content-Type: text/plain' + ), + false + ), + ); + } + + /** + * @dataProvider hasAttachmentProvider + */ + public function testHasAttachment($headers, $expected) + { + $this->assertEquals( + $expected, + $this->jsHelper->hasAttachment($headers) + ); + } + + public function hasAttachmentProvider() + { + return array( + array( + array( + 'Content-Disposition: attachment' + ), + true + ), + array( + array( + ), + false + ), + ); + } + + public function testJsSnippet() + { + $expected = file_get_contents($this->testSnippetPath); + + $this->assertEquals($expected, $this->jsHelper->jsSnippet()); + } + + /** + * @dataProvider shouldAppendNonceProvider + */ + public function testShouldAppendNonce($headers, $expected) + { + $this->assertEquals( + $expected, + $this->jsHelper->shouldAppendNonce($headers) + ); + } + + public function shouldAppendNonceProvider() + { + return array( + array( + array( + "Content-Security-Policy: script-src 'unsafe-inline'" + ), + true + ), + array( + array( + "Content-Type: text/html" + ), + false + ), + array( + array( + "Content-Security-Policy: default-src 'self'" + ), + false + ), + ); + } + + /** + * @dataProvider scriptTagProvider + */ + public function testScriptTag($content, $headers, $nonce, $expected) + { + if ($expected === 'Exception') { + try { + + $result = $this->jsHelper->scriptTag($content, $headers, $nonce); + + $this->fail(); + + } catch (\Exception $e) { + + $this->assertTrue(true); + return; + + } + } else { + + $result = $this->jsHelper->scriptTag($content, $headers, $nonce); + + $this->assertEquals($expected, $result); + + } + } + + public function scriptTagProvider() + { + return array( + 'nonce script' => array( + 'var test = "value 1";', + array( + "Content-Security-Policy: script-src 'unsafe-inline'" + ), + '123', + "\n" + ), + 'script-src inline-unsafe throws Exception' => array( + 'var test = "value 1";', + array( + "Content-Security-Policy: script-src 'inline-unsafe'" + ), + null, + 'Exception' + ), + array( + 'var test = "value 1";', + array(), + null, + "\n" + ), + ); + + } + + public function testSnippetJsTag() + { + $headers = array(); + $nonce = 'nonce-string'; + + $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); + + $mock->shouldReceive('jsSnippet') + ->andReturn('stubJsSnippet'); + + $mock->shouldReceive('scriptTag') + ->with('stubJsSnippet') + ->with($headers) + ->with($nonce); + + $mock->shouldReceive('snippetJsTag')->passthru(); + + $snippetJsTag = $mock->snippetJsTag($headers, $nonce); + } +} \ No newline at end of file From 75af146d61ba579d9981b34e750dee0173254ac8 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 17:52:31 +0000 Subject: [PATCH 08/45] github-137: addJs method --- src/Config.php | 4 +- src/RollbarJsHelper.php | 88 +++++++++++++++++++++++------------ tests/RollbarJsHelperTest.php | 58 ++++++++++++++++++----- 3 files changed, 106 insertions(+), 44 deletions(-) diff --git a/src/Config.php b/src/Config.php index b748a472..93dd3e8c 100644 --- a/src/Config.php +++ b/src/Config.php @@ -52,10 +52,10 @@ class Config private $sendMessageTrace = false; /** - * @var boolean In case you want to report your JavaScript errors using + * @var boolean In case you want to report your JavaScript errors using * Rollbar.js, you can configure the SDK to enable Rollbar.js on your site. */ - private $jsEnabled = false; + private $jsEnabled = false; public function __construct(array $configArray) { diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index 6c5c8296..bb5189e0 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -2,31 +2,62 @@ class RollbarJsHelper { - const JS_IS_INJECTED_KEY = 'rollbar.js_is_injected'; - + protected $config; - // public function __construct($config) - // { - // $this->config = $config; - // } + public function __construct($config) + { + $this->config = $config; + } + + /** + * Build Javascript required to include RollbarJS on + * an HTML page + * + * @param array $headers Response headers usually retrieved through + * headers_list() used to verify if nonce should be added to script + * tags based on Content-Security-Policy + * @param string $nonce Content-Security-Policy nonce string if exists + * + * @return string + */ + public function addJs($headers = null, $nonce = null) + { + return + $this->configJsTag($headers = null, $nonce) . + $this->snippetJsTag($headers = null, $nonce); + } /** - * Build RollbarJS script tag - * + * Build RollbarJS snippet script tag + * * @param array $headers * @param string $nonce - * + * * @return string */ - public function snippetJsTag($headers, $nonce = null) + public function snippetJsTag($headers = null, $nonce = null) { return $this->scriptTag($this->jsSnippet(), $headers, $nonce); } + /** + * Build RollbarJS config script tag + * + * @param array $headers + * @param string $nonce + * + * @return string + */ + public function configJsTag($headers = null, $nonce = null) + { + $configJs = "var _rollbarConfig = " . json_encode($this->config['options']) . ";"; + return $this->scriptTag($configJs, $headers, $nonce); + } + /** * Build rollbar.snippet.js string - * + * * @return string */ public function jsSnippet() @@ -46,14 +77,14 @@ public function snippetPath() /** * Should JS snippet be added to the HTTP response - * + * * @param int $status * @param array $headers - * + * * @return boolean */ public function shouldAddJs($status, $headers) - { + { return $status == 200 && $this->isHtml($headers) && @@ -68,9 +99,9 @@ public function shouldAddJs($status, $headers) /** * Is the HTTP response a valid HTML response - * + * * @param array $headers - * + * * @return boolean */ public function isHtml($headers) @@ -80,9 +111,9 @@ public function isHtml($headers) /** * Does the HTTP response include an attachment - * + * * @param array $headers - * + * * @return boolean */ public function hasAttachment($headers) @@ -92,9 +123,9 @@ public function hasAttachment($headers) /** * Is `nonce` attribute on the script tag needed? - * + * * @param array $headers - * + * * @return boolean */ public function shouldAppendNonce($headers) @@ -102,9 +133,7 @@ public function shouldAppendNonce($headers) foreach ($headers as $header) { if (strpos($header, 'Content-Security-Policy') !== false && strpos($header, "'unsafe-inline'") !== false) { - return true; - } } @@ -113,25 +142,24 @@ public function shouldAppendNonce($headers) /** * Build safe HTML script tag - * + * * @param string $content * @param array $headers - * @param - * + * @param + * * @return string */ - public function scriptTag($content, $headers, $nonce = null) + public function scriptTag($content, $headers = null, $nonce = null) { - if ($this->shouldAppendNonce($headers)) { - + if ($headers !== null && $this->shouldAppendNonce($headers)) { if (!$nonce) { throw new \Exception('Content-Security-Policy is script-src '. 'inline-unsafe but nonce value not provided.'); } - return "\n"; + return "\n"; } else { return "\n"; } } -} \ No newline at end of file +} diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index 7ab1b634..fb4cbde4 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -7,7 +7,7 @@ class JsHelperTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->jsHelper = new RollbarJsHelper(); + $this->jsHelper = new RollbarJsHelper(array()); $this->testSnippetPath = realpath(__DIR__ . "/../data/rollbar.snippet.js"); } @@ -187,23 +187,17 @@ public function testScriptTag($content, $headers, $nonce, $expected) { if ($expected === 'Exception') { try { - $result = $this->jsHelper->scriptTag($content, $headers, $nonce); $this->fail(); - } catch (\Exception $e) { - $this->assertTrue(true); return; - } } else { - $result = $this->jsHelper->scriptTag($content, $headers, $nonce); $this->assertEquals($expected, $result); - } } @@ -233,7 +227,6 @@ public function scriptTagProvider() "\n" ), ); - } public function testSnippetJsTag() @@ -247,12 +240,53 @@ public function testSnippetJsTag() ->andReturn('stubJsSnippet'); $mock->shouldReceive('scriptTag') - ->with('stubJsSnippet') - ->with($headers) - ->with($nonce); + ->with('stubJsSnippet', $headers, $nonce); $mock->shouldReceive('snippetJsTag')->passthru(); $snippetJsTag = $mock->snippetJsTag($headers, $nonce); } -} \ No newline at end of file + + public function testConfigJsTag() + { + $headers = array(); + $nonce = 'nonce-string'; + $config = array( + 'options' => array( + 'config1' => 'value 1' + ) + ); + + $expectedJson = json_encode($config['options']); + $expected = "\n"; + + $helper = new RollbarJsHelper($config); + $result = $helper->configJsTag($headers, $nonce); + + $this->assertEquals($expected, $result); + } + + public function testAddJs() + { + $headers = array(); + $nonce = 'stub-nonce'; + + $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); + + $mock->shouldReceive('snippetJsTag') + ->andReturn('stubJsSnippet'); + + $mock->shouldReceive('configJsTag') + ->andReturn('stubJsConfig'); + + $mock->shouldReceive('addJs')->passthru(); + + $expected = 'stubJsConfig' . 'stubJsSnippet'; + + $result = $mock->addJs($headers, $nonce); + + $this->assertEquals($expected, $result); + } +} From 3e6229b82bce8a099c91c505d5dbf718471d0cca Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 17:55:30 +0000 Subject: [PATCH 09/45] github-137: doc for the constructor --- src/RollbarJsHelper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index bb5189e0..9102c896 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -5,6 +5,11 @@ class RollbarJsHelper protected $config; + /** + * @param array $config The array passed to he should have the same + * available options that you can find in Rollbar.js, using symbols or + * strings for the keys. + */ public function __construct($config) { $this->config = $config; From 79be38725df94ce548eab1537f70709f62e1d672 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 19:54:44 +0000 Subject: [PATCH 10/45] github-137: test for addJs --- src/RollbarJsHelper.php | 7 ++-- tests/RollbarJsHelperTest.php | 63 ++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index 9102c896..11c234be 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -29,8 +29,8 @@ public function __construct($config) public function addJs($headers = null, $nonce = null) { return - $this->configJsTag($headers = null, $nonce) . - $this->snippetJsTag($headers = null, $nonce); + $this->configJsTag($headers, $nonce) . + $this->snippetJsTag($headers, $nonce); } /** @@ -56,7 +56,8 @@ public function snippetJsTag($headers = null, $nonce = null) */ public function configJsTag($headers = null, $nonce = null) { - $configJs = "var _rollbarConfig = " . json_encode($this->config['options']) . ";"; + $config = isset($this->config['options']) ? $this->config['options'] : new \stdClass(); + $configJs = "var _rollbarConfig = " . json_encode($config) . ";"; return $this->scriptTag($configJs, $headers, $nonce); } diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index fb4cbde4..b8b2f3b3 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -268,25 +268,58 @@ public function testConfigJsTag() $this->assertEquals($expected, $result); } - public function testAddJs() + /** + * @dataProvider addJsProvider + */ + public function testAddJs($setup, $expected) { - $headers = array(); - $nonce = 'stub-nonce'; - - $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); - - $mock->shouldReceive('snippetJsTag') - ->andReturn('stubJsSnippet'); + extract($setup); - $mock->shouldReceive('configJsTag') - ->andReturn('stubJsConfig'); - - $mock->shouldReceive('addJs')->passthru(); - - $expected = 'stubJsConfig' . 'stubJsSnippet'; + $helper = new RollbarJsHelper($config); - $result = $mock->addJs($headers, $nonce); + $result = $helper->addJs($headers, $nonce); $this->assertEquals($expected, $result); } + + public function addJsProvider() + { + $this->setUp(); + $expectedJs = file_get_contents($this->testSnippetPath); + return array( + array( + array( + 'config' => array(), + 'headers' => array(), + 'nonce' => null + ), + "\n" . + "\n" + ), + array( + array( + 'config' => array( + 'options' => array( + 'foo' => 'bar' + ) + ), + 'headers' => array(), + 'nonce' => null + ), + "\n" . + "\n" + ), + array( + array( + 'config' => array(), + 'headers' => array( + 'Content-Security-Policy: script-src \'unsafe-inline\'' + ), + 'nonce' => 'stub-nonce' + ), + "\n" . + "\n" + ), + ); + } } From 70407c4bd2d33b527be0fc6b8a33ffef04a9a770 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 23:36:17 +0000 Subject: [PATCH 11/45] github-137: clean up isEnabled leftovers --- tests/RollbarJsHelperTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index b8b2f3b3..56198799 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -25,9 +25,6 @@ public function testSnippetPath() public function testShouldAddJs($setup, $expected) { $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); - - $mock->shouldReceive('isEnabled') - ->andReturn($setup['isEnabled']); $status = $setup['status']; From cf5086ea544d2d2cfe4eace6d939370f454f417e Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 23:37:33 +0000 Subject: [PATCH 12/45] github-137: more isEnabled clean up --- src/Config.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Config.php b/src/Config.php index 93dd3e8c..0404c5c2 100644 --- a/src/Config.php +++ b/src/Config.php @@ -50,12 +50,6 @@ class Config * sent through RollbarLogger::log() */ private $sendMessageTrace = false; - - /** - * @var boolean In case you want to report your JavaScript errors using - * Rollbar.js, you can configure the SDK to enable Rollbar.js on your site. - */ - private $jsEnabled = false; public function __construct(array $configArray) { @@ -239,15 +233,6 @@ private function setSendMessageTrace($c) $this->sendMessageTrace = $c['send_message_trace']; } - private function setJsEnabled($c) - { - if (!isset($c['js_enabled'])) { - return; - } - - $this->jsEnabled = $c['js_enabled']; - } - /** * Allows setting up configuration options that might be specified by class * name. Any interface used with `setupWithOptions` should be constructed From 5fcec92694124190b0376ff051bc679845d28e4d Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 23:38:49 +0000 Subject: [PATCH 13/45] github-137: more isEnabled clean up --- src/Config.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Config.php b/src/Config.php index 0404c5c2..4586d785 100644 --- a/src/Config.php +++ b/src/Config.php @@ -104,7 +104,6 @@ protected function updateConfig($c) $this->setResponseHandler($c); $this->setCheckIgnoreFunction($c); $this->setSendMessageTrace($c); - $this->setJsEnabled($c); if (isset($c['included_errno'])) { $this->included_errno = $c['included_errno']; From ccdd1f4935fd60adb397f9aa787480947dbf2efa Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Mon, 29 May 2017 23:39:44 +0000 Subject: [PATCH 14/45] github-137: composer fix --- src/RollbarJsHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index 11c234be..6f6fbdb1 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -6,8 +6,8 @@ class RollbarJsHelper protected $config; /** - * @param array $config The array passed to he should have the same - * available options that you can find in Rollbar.js, using symbols or + * @param array $config The array passed to he should have the same + * available options that you can find in Rollbar.js, using symbols or * strings for the keys. */ public function __construct($config) From ff9f55fc1b90d86cdfd029a32490352a9e9e4b7f Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 00:00:14 +0000 Subject: [PATCH 15/45] github-137: shortcut method for convenience; usage instructions in README.md --- README.md | 33 +++++++++++++++++++++++++++++++++ src/RollbarJsHelper.php | 14 ++++++++++++++ tests/RollbarJsHelperTest.php | 12 ++++++++++++ 3 files changed, 59 insertions(+) diff --git a/README.md b/README.md index 9d60625b..a77fe9ed 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,39 @@ Rollbar::init(array( ?> ``` +## Integration with Rollbar.js + +In case you want to report your JavaScript errors using [Rollbar.js](https://github.com/rollbar/rollbar.js), you can configure the SDK to enable Rollbar.js on your site. Example: + +```php +$rollbarJs = Rollbar\RollbarJsHelper::buildJs( + array( + "accessToken" => "POST_CLIENT_ITEM_ACCESS_TOKEN", + "captureUncaught" => true, + "payload" => array( + "environment" => "production" + ), + /* other configuration you want to pass to RollbarJS */ + ) +); +``` + +Or if you are using Content-Security-Policy: script-src 'unsafe-inline' +```php +$rollbarJs = Rollbar\RollbarJsHelper::buildJs( + array( + "accessToken" => "POST_CLIENT_ITEM_ACCESS_TOKEN", + "captureUncaught" => true, + "payload" => array( + "environment" => "production" + ), + /* other configuration you want to pass to RollbarJS */ + ), + headers_list(), + $yourNonceString +); +``` + ## Basic Usage That's it! Uncaught errors and exceptions will now be reported to Rollbar. diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index 6f6fbdb1..ff613923 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -15,6 +15,20 @@ public function __construct($config) $this->config = $config; } + /** + * Shortcut method for building the RollbarJS Javascript + * + * @param array $config @see addJs() + * @param string $nonce @see addJs() + * + * @return string + */ + public static function buildJs($config, $headers = null, $nonce = null) + { + $helper = new self($config); + return $helper->addJs($headers, $nonce); + } + /** * Build Javascript required to include RollbarJS on * an HTML page diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index 56198799..cfd6dbe1 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -265,6 +265,18 @@ public function testConfigJsTag() $this->assertEquals($expected, $result); } + /** + * @dataProvider addJsProvider + */ + public function testBuildJs($setup, $expected) + { + extract($setup); + + $result = RollbarJsHelper::buildJs($config, $headers, $nonce); + + $this->assertEquals($expected, $result); + } + /** * @dataProvider addJsProvider */ From 18b0cd3cd90d6b64644b166c81f6160e146c1e12 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 00:01:39 +0000 Subject: [PATCH 16/45] github-137: composer fix --- src/RollbarJsHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index ff613923..a4044b57 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -17,10 +17,10 @@ public function __construct($config) /** * Shortcut method for building the RollbarJS Javascript - * + * * @param array $config @see addJs() * @param string $nonce @see addJs() - * + * * @return string */ public static function buildJs($config, $headers = null, $nonce = null) From 54cde10251e58d2a51021e04d6259d1e0e75f94c Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 00:55:22 +0000 Subject: [PATCH 17/45] github-137: test for endpoint config and deprecated base_api_url --- README.md | 9 ++++++++- src/Config.php | 11 ++++++++++- src/Senders/CurlSender.php | 5 +++++ tests/ConfigTest.php | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 338b1f91..70197968 100644 --- a/README.md +++ b/README.md @@ -224,9 +224,16 @@ All of the following options can be passed as keys in the `$config` array. Default: `/var/www` +
endpoint +
+
The API URL to post to. Note: the URL has to end with a trailing slash. + +Default: `https://api.rollbar.com/api/1/` +
+
base_api_url
-
The base api url to post to. +
Deprecated (use endpoint instead). The base api url to post to. Default: `https://api.rollbar.com/api/1/`
diff --git a/src/Config.php b/src/Config.php index 0fd130ef..aef2d041 100644 --- a/src/Config.php +++ b/src/Config.php @@ -162,7 +162,11 @@ private function setSender($c) $default = "Rollbar\Senders\CurlSender"; if (array_key_exists('base_api_url', $c)) { - $c['senderOptions']['endpoint'] = $c['base_api_url']; + $c['senderOptions']['endpoint'] = $c['base_api_url'] . 'item/'; + } + + if (array_key_exists('endpoint', $c)) { + $c['senderOptions']['endpoint'] = $c['endpoint'] . 'item/'; } if (array_key_exists('timeout', $c)) { @@ -263,6 +267,11 @@ public function getDataBuilder() { return $this->dataBuilder; } + + public function getSender() + { + return $this->sender; + } /** * @param Payload $payload diff --git a/src/Senders/CurlSender.php b/src/Senders/CurlSender.php index 78844070..0afe667a 100644 --- a/src/Senders/CurlSender.php +++ b/src/Senders/CurlSender.php @@ -38,6 +38,11 @@ public function __construct($opts) $this->verifyPeer = $opts['verifyPeer']; } } + + public function getEndpoint() + { + return $this->endpoint; + } public function send($scrubbedPayload, $accessToken) { diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 54e37e40..5423848d 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -207,6 +207,40 @@ public function testSender() )); $c->send($p, $this->token); } + + public function testEndpoint() + { + $payload = m::mock("Rollbar\Payload\Payload"); + + $config = new Config(array( + "access_token" => $this->token, + "environment" => $this->env, + "sender" => $sender, + "endpoint" => "http://localhost/api/1/" + )); + + $this->assertEquals( + "http://localhost/api/1/item/", + $config->getSender()->getEndpoint() + ); + } + + public function testBaseApiUrl() + { + $payload = m::mock("Rollbar\Payload\Payload"); + + $config = new Config(array( + "access_token" => $this->token, + "environment" => $this->env, + "sender" => $sender, + "base_api_url" => "http://localhost/api/1/" + )); + + $this->assertEquals( + "http://localhost/api/1/item/", + $config->getSender()->getEndpoint() + ); + } public function testCheckIgnore() { From ed91a889d1a6443ce48a08e8c028dbcbf26de2c9 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 01:02:44 +0000 Subject: [PATCH 18/45] github-137: not passing a sender --- tests/ConfigTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 0e6514c8..c5e3845d 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -215,7 +215,6 @@ public function testEndpoint() $config = new Config(array( "access_token" => $this->token, "environment" => $this->env, - "sender" => $sender, "endpoint" => "http://localhost/api/1/" )); @@ -232,7 +231,6 @@ public function testBaseApiUrl() $config = new Config(array( "access_token" => $this->token, "environment" => $this->env, - "sender" => $sender, "base_api_url" => "http://localhost/api/1/" )); From afe67884100e1d229cb6442c37f465a7ebd392cd Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 30 May 2017 14:16:27 +0200 Subject: [PATCH 19/45] Decoupling of RollbarLogger in init Allow passing a `RollbarLogger` in init instead of creating one from config. This allows to use a custom `RollbarLogger` by extending the class. You can also get the logger from a container for container based frameworks. --- src/Rollbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rollbar.php b/src/Rollbar.php index 9ae373c5..ea2d8d02 100644 --- a/src/Rollbar.php +++ b/src/Rollbar.php @@ -18,7 +18,7 @@ public static function init( $handleFatal = true ) { if (is_null(self::$logger)) { - self::$logger = new RollbarLogger($config); + self::$logger = $config instanceof RollbarLogger ? $config : new RollbarLogger($config); if ($handleException) { self::setupExceptionHandling(); From 3fb911113bdd415da07ab5c1c5c8d6a937c0e609 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 13:21:43 +0000 Subject: [PATCH 20/45] github-173: fix square brackets usage --- tests/DataBuilderTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 9401f68f..c0fc4260 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -416,8 +416,9 @@ public function testExceptionTraceArguments() $expected = 'trace args message'; $ex = $this->exceptionTraceArgsHelper($expected); $frames = $dataBuilder->getExceptionTrace($ex)->getFrames(); + $args = $frames[0]->getArgs(); - $this->assertEquals($frames[0]->getArgs()[0], $expected, "Frames arguments NOT available in trace when they should be."); + $this->assertEquals($expected, $args[0], "Frames arguments NOT available in trace when they should be."); } private function exceptionTraceArgsHelper($message) From b9e27da3eebee026d0af4d6916e92fb9b3a4b917 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 13:34:02 +0000 Subject: [PATCH 21/45] github-173: use string instead of ::class --- tests/DataBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index c0fc4260..744c7f91 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1015,6 +1015,6 @@ public function testGenerateErrorWrapper() { $result = $this->dataBuilder->generateErrorWrapper(E_ERROR, 'bork', null, null); - $this->assertInstanceOf(ErrorWrapper::class, $result); + $this->assertInstanceOf("ErrorWrapper", $result); } } From 8f10196723d92147aff5c4d33fabd0553555d58b Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 13:45:28 +0000 Subject: [PATCH 22/45] github-173: use instanceof instead --- tests/DataBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 744c7f91..80eca67b 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1015,6 +1015,6 @@ public function testGenerateErrorWrapper() { $result = $this->dataBuilder->generateErrorWrapper(E_ERROR, 'bork', null, null); - $this->assertInstanceOf("ErrorWrapper", $result); + $this->assertTrue($result instanceof ErrorWrapper); } } From 9c3b1bf17b0168126b24a3c6f63f57b34922015e Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 13:54:54 +0000 Subject: [PATCH 23/45] github-173: composer fix --- src/DataBuilder.php | 8 ++++---- tests/DataBuilderTest.php | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 21a13240..467b38fd 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -473,8 +473,8 @@ protected function getMessage($toLog, $context) return new Message( (string)$toLog, $context, - $this->sendMessageTrace ? - debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) : + $this->sendMessageTrace ? + debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS) : null ); } @@ -997,12 +997,12 @@ public function needsTruncating(array $payload) /** * Wrap a PHP error in an ErrorWrapper class and add backtrace information - * + * * @param string $errno * @param string $errstr * @param string $errfile * @param string $errline - * + * * @return ErrorWrapper */ public function generateErrorWrapper($errno, $errstr, $errfile, $errline) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 80eca67b..a24d81ce 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -361,7 +361,6 @@ public function testGetMessageSendMessageTrace() $result = $dataBuilder->makeData(Level::fromName('error'), "testing", array()); $this->assertNotEmpty($result->getBody()->getValue()->getBacktrace()); - } public function testGetMessageTraceArguments() @@ -393,7 +392,6 @@ public function testGetMessageTraceArguments() $frames = $result->getBody()->getValue()->getBacktrace(); $this->assertEquals($frames[0]['args'][0], $expected, "Arguments in stack frames NOT included when they should be."); - } public function testExceptionTraceArguments() From aad133e6c8c15fee9900a719a2af247d3a4a5cde Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 15:13:44 +0000 Subject: [PATCH 24/45] github-173: clean up line lenghts --- tests/DataBuilderTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index a24d81ce..4ef323c7 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -376,7 +376,11 @@ public function testGetMessageTraceArguments() $result = $dataBuilder->makeData(Level::fromName('error'), 'testing', array()); $frames = $result->getBody()->getValue()->getBacktrace(); - $this->assertArrayNotHasKey('args', $frames[0], "Arguments in stack frames included when they should have not been."); + $this->assertArrayNotHasKey( + 'args', + $frames[0], + "Arguments in stack frames included when they should have not been." + ); // Positive test $c = new Config(array( @@ -391,7 +395,11 @@ public function testGetMessageTraceArguments() $result = $dataBuilder->makeData(Level::fromName('error'), $expected, array()); $frames = $result->getBody()->getValue()->getBacktrace(); - $this->assertEquals($frames[0]['args'][0], $expected, "Arguments in stack frames NOT included when they should be."); + $this->assertEquals( + $expected, + $frames[0]['args'][0], + "Arguments in stack frames NOT included when they should be." + ); } public function testExceptionTraceArguments() From b49478d7b0ef7c328c080021d91941b1dc1ff089 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 15:20:41 +0000 Subject: [PATCH 25/45] github-173: composer fix --- tests/DataBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 4ef323c7..a45cc5d3 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -378,7 +378,7 @@ public function testGetMessageTraceArguments() $this->assertArrayNotHasKey( 'args', - $frames[0], + $frames[0], "Arguments in stack frames included when they should have not been." ); From a7c489a8b2c036b193e9df1a04182520c82e0740 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 15:51:30 +0000 Subject: [PATCH 26/45] github-173: capture_error_stacktraces implementation --- src/Config.php | 2 +- src/DataBuilder.php | 29 +++++++++++++++------ src/Defaults.php | 11 +++++++- tests/ConfigTest.php | 20 +++++++++++++++ tests/DataBuilderTest.php | 53 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/Config.php b/src/Config.php index 4586d785..58c82095 100644 --- a/src/Config.php +++ b/src/Config.php @@ -231,7 +231,7 @@ private function setSendMessageTrace($c) $this->sendMessageTrace = $c['send_message_trace']; } - + /** * Allows setting up configuration options that might be specified by class * name. Any interface used with `setupWithOptions` should be constructed diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 467b38fd..669fda2e 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -58,6 +58,7 @@ class DataBuilder implements DataBuilderInterface protected $shiftFunction; protected $sendMessageTrace; protected $localVarsDump; + protected $captureErrorStacktraces; public function __construct($config) { @@ -92,6 +93,7 @@ public function __construct($config) $this->setIncludeExcCodeContext($config); $this->setSendMessageTrace($config); $this->setLocalVarsDump($config); + $this->setCaptureErrorStacktraces($config); $this->shiftFunction = $this->tryGet($config, 'shift_function'); if (!isset($this->shiftFunction)) { @@ -168,6 +170,12 @@ protected function setLocalVarsDump($config) $fromConfig = $this->tryGet($config, 'local_vars_dump'); $this->localVarsDump = self::$defaults->localVarsDump($fromConfig); } + + protected function setCaptureErrorStacktraces($config) + { + $fromConfig = $this->tryGet($config, 'capture_error_stacktraces'); + $this->captureErrorStacktraces = self::$defaults->captureErrorStacktraces($fromConfig); + } protected function setCodeVersion($config) { @@ -387,7 +395,12 @@ public function getExceptionTrace($exc) */ public function makeTrace($exception, $includeContext, $classOverride = null) { - $frames = $this->makeFrames($exception, $includeContext); + if ($this->captureErrorStacktraces) { + $frames = $this->makeFrames($exception, $includeContext); + } else { + $frames = array(); + } + $excInfo = new ExceptionInfo( Utilities::coalesce($classOverride, get_class($exception)), $exception->getMessage() @@ -1007,12 +1020,14 @@ public function needsTruncating(array $payload) */ public function generateErrorWrapper($errno, $errstr, $errfile, $errline) { - // removing this function and the handler function to make sure they're - // not part of the backtrace - $backTrace = array_slice( - debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS), - 2 - ); + if ($this->captureErrorStacktraces) { + $backTrace = array_slice( + debug_backtrace($this->localVarsDump ? 0 : DEBUG_BACKTRACE_IGNORE_ARGS), + 2 + ); + } else { + $backTrace = array(); + } return new ErrorWrapper($errno, $errstr, $errfile, $errline, $backTrace); } } diff --git a/src/Defaults.php b/src/Defaults.php index 3f34f70a..c46d9c70 100644 --- a/src/Defaults.php +++ b/src/Defaults.php @@ -84,7 +84,14 @@ private static function getScrubFields() public function sendMessageTrace($sendMessageTrace = null) { - return $sendMessageTrace ? $sendMessageTrace : $this->defaultSendMessageTrace; + return $sendMessageTrace !== null ? $sendMessageTrace : $this->defaultSendMessageTrace; + } + + public function captureErrorStacktraces($captureErrorStracktraces = null) + { + return $captureErrorStracktraces !== null ? + $captureErrorStracktraces : + $this->defaultCaptureErrorStacktraces; } public function localVarsDump($localVarsDump = null) @@ -108,6 +115,7 @@ public function localVarsDump($localVarsDump = null) private $defaultIncludeCodeContext; private $defaultIncludeExcCodeContext; private $defaultLocalVarsDump; + private $defaultCaptureErrorStacktraces; public function __construct() { @@ -158,6 +166,7 @@ public function __construct() $this->defaultIncludeCodeContext = false; $this->defaultIncludeExcCodeContext = false; $this->defaultLocalVarsDump = false; + $this->defaultCaptureErrorStacktraces = true; } public function messageLevel($level = null) diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index e05a6402..cb85788b 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -7,6 +7,7 @@ use Rollbar\Payload\Level; use Rollbar\Payload\Message; use Rollbar\Payload\Payload; +use Rollbar\RollbarLogger; use Psr\Log\LogLevel; class ConfigTest extends \PHPUnit_Framework_TestCase @@ -265,4 +266,23 @@ public function testCheckIgnoreParameters() $this->assertTrue($isUncaughtPassed); $this->assertEquals($this->error, $errorPassed); } + + public function testCaptureErrorStacktraces() + { + $logger = new RollbarLogger(array( + "access_token" => $this->token, + "environment" => $this->env, + "capture_error_stacktraces" => false + )); + + $dataBuilder = $logger->getDataBuilder(); + + $result = $dataBuilder->makeData( + Level::fromName('error'), + new \Exception(), + array() + ); + + $this->assertEmpty($result->getBody()->getValue()->getFrames()); + } } diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index a45cc5d3..10021806 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1023,4 +1023,57 @@ public function testGenerateErrorWrapper() $this->assertTrue($result instanceof ErrorWrapper); } + + /** + * @dataProvider captureErrorStacktracesProvider + */ + public function testCaptureErrorStacktracesException( + $captureErrorStacktraces, + $expected + ) { + + $dataBuilder = new DataBuilder(array( + 'accessToken' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests', + 'capture_error_stacktraces' => $captureErrorStacktraces + )); + + $result = $dataBuilder->makeData( + Level::fromName('error'), + new \Exception(), + array() + ); + + $this->assertEquals( + $expected, + empty($result->getBody()->getValue()->getFrames()) + ); + } + + /** + * @dataProvider captureErrorStacktracesProvider + */ + public function testCaptureErrorStacktracesError( + $captureErrorStacktraces, + $expected + ) { + + $dataBuilder = new DataBuilder(array( + 'accessToken' => 'abcd1234efef5678abcd1234567890be', + 'environment' => 'tests', + 'capture_error_stacktraces' => $captureErrorStacktraces + )); + + $result = $dataBuilder->generateErrorWrapper(E_ERROR, 'bork', null, null); + + $this->assertEquals($expected, empty($result->getBacktrace())); + } + + public function captureErrorStacktracesProvider() + { + return array( + array(false,true), + array(true, false) + ); + } } From c886c0c94c3ef5e0ff5f3d0d6af4f67f90d43142 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 16:00:13 +0000 Subject: [PATCH 27/45] github-166: break up usage of empty() for < 5.4. compatibility --- tests/DataBuilderTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 10021806..b14bb431 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1043,11 +1043,9 @@ public function testCaptureErrorStacktracesException( new \Exception(), array() ); + $result = empty($result->getBody()->getValue()->getFrames()); - $this->assertEquals( - $expected, - empty($result->getBody()->getValue()->getFrames()) - ); + $this->assertEquals($expected, $result); } /** From c5f04d1da509cb538c04a5706d5d28177de436a5 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 16:05:13 +0000 Subject: [PATCH 28/45] github-166: break up usage of empty() for < 5.4. compatibility --- tests/DataBuilderTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index b14bb431..11116cbb 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1043,7 +1043,8 @@ public function testCaptureErrorStacktracesException( new \Exception(), array() ); - $result = empty($result->getBody()->getValue()->getFrames()); + $frames = $result->getBody()->getValue()->getFrames() + $result = empty($frames); $this->assertEquals($expected, $result); } From 2a3b75a34a5757411da2e71d4c04a1e5d4106aaf Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 16:09:50 +0000 Subject: [PATCH 29/45] github-166: fix a typo --- tests/DataBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 11116cbb..40c1b717 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1043,7 +1043,7 @@ public function testCaptureErrorStacktracesException( new \Exception(), array() ); - $frames = $result->getBody()->getValue()->getFrames() + $frames = $result->getBody()->getValue()->getFrames(); $result = empty($frames); $this->assertEquals($expected, $result); From 9462611c14b2f64fae78a9861b48bfe86c582173 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Tue, 30 May 2017 16:14:42 +0000 Subject: [PATCH 30/45] github-166: relace empty() for less problematic count() === 0 --- tests/DataBuilderTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/DataBuilderTest.php b/tests/DataBuilderTest.php index 40c1b717..965b3f00 100644 --- a/tests/DataBuilderTest.php +++ b/tests/DataBuilderTest.php @@ -1044,9 +1044,8 @@ public function testCaptureErrorStacktracesException( array() ); $frames = $result->getBody()->getValue()->getFrames(); - $result = empty($frames); - $this->assertEquals($expected, $result); + $this->assertEquals($expected, count($frames) === 0); } /** @@ -1064,8 +1063,9 @@ public function testCaptureErrorStacktracesError( )); $result = $dataBuilder->generateErrorWrapper(E_ERROR, 'bork', null, null); + $frames = $result->getBacktrace(); - $this->assertEquals($expected, empty($result->getBacktrace())); + $this->assertEquals($expected, count($frames) === 0); } public function captureErrorStacktracesProvider() From 5f5fd24562dcd738a0507c5c68057877e4f85e66 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Wed, 31 May 2017 01:54:17 +0000 Subject: [PATCH 31/45] github-153: add test case for default endpoint and base_api_url --- tests/ConfigTest.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index c5e3845d..4864fdef 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -224,6 +224,21 @@ public function testEndpoint() ); } + public function testEndpointDefault() + { + $payload = m::mock("Rollbar\Payload\Payload"); + + $config = new Config(array( + "access_token" => $this->token, + "environment" => $this->env + )); + + $this->assertEquals( + "https://api.rollbar.com/api/1/item/", + $config->getSender()->getEndpoint() + ); + } + public function testBaseApiUrl() { $payload = m::mock("Rollbar\Payload\Payload"); @@ -239,6 +254,21 @@ public function testBaseApiUrl() $config->getSender()->getEndpoint() ); } + + public function testBaseApiUrlDefault() + { + $payload = m::mock("Rollbar\Payload\Payload"); + + $config = new Config(array( + "access_token" => $this->token, + "environment" => $this->env + )); + + $this->assertEquals( + "https://api.rollbar.com/api/1/item/", + $config->getSender()->getEndpoint() + ); + } public function testSendMessageTrace() { From 75d6497eef2dff5288214e55081a24bcb69db0e8 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Wed, 31 May 2017 02:06:21 +0000 Subject: [PATCH 32/45] github-137: put config and snippet in the same script tag --- src/RollbarJsHelper.php | 31 +++++++----------------- tests/RollbarJsHelperTest.php | 44 +++++++++++------------------------ 2 files changed, 22 insertions(+), 53 deletions(-) diff --git a/src/RollbarJsHelper.php b/src/RollbarJsHelper.php index a4044b57..6e60a970 100644 --- a/src/RollbarJsHelper.php +++ b/src/RollbarJsHelper.php @@ -42,37 +42,22 @@ public static function buildJs($config, $headers = null, $nonce = null) */ public function addJs($headers = null, $nonce = null) { - return - $this->configJsTag($headers, $nonce) . - $this->snippetJsTag($headers, $nonce); - } - - /** - * Build RollbarJS snippet script tag - * - * @param array $headers - * @param string $nonce - * - * @return string - */ - public function snippetJsTag($headers = null, $nonce = null) - { - return $this->scriptTag($this->jsSnippet(), $headers, $nonce); + return $this->scriptTag( + $this->configJsTag() .$this->jsSnippet(), + $headers, + $nonce + ); } /** - * Build RollbarJS config script tag - * - * @param array $headers - * @param string $nonce + * Build RollbarJS config script * * @return string */ - public function configJsTag($headers = null, $nonce = null) + public function configJsTag() { $config = isset($this->config['options']) ? $this->config['options'] : new \stdClass(); - $configJs = "var _rollbarConfig = " . json_encode($config) . ";"; - return $this->scriptTag($configJs, $headers, $nonce); + return "var _rollbarConfig = " . json_encode($config) . ";"; } /** diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index cfd6dbe1..5e9def7e 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -226,28 +226,8 @@ public function scriptTagProvider() ); } - public function testSnippetJsTag() - { - $headers = array(); - $nonce = 'nonce-string'; - - $mock = \Mockery::mock('Rollbar\RollbarJsHelper'); - - $mock->shouldReceive('jsSnippet') - ->andReturn('stubJsSnippet'); - - $mock->shouldReceive('scriptTag') - ->with('stubJsSnippet', $headers, $nonce); - - $mock->shouldReceive('snippetJsTag')->passthru(); - - $snippetJsTag = $mock->snippetJsTag($headers, $nonce); - } - public function testConfigJsTag() { - $headers = array(); - $nonce = 'nonce-string'; $config = array( 'options' => array( 'config1' => 'value 1' @@ -255,12 +235,10 @@ public function testConfigJsTag() ); $expectedJson = json_encode($config['options']); - $expected = "\n"; + $expected = "var _rollbarConfig = $expectedJson;"; $helper = new RollbarJsHelper($config); - $result = $helper->configJsTag($headers, $nonce); + $result = $helper->configJsTag(); $this->assertEquals($expected, $result); } @@ -302,8 +280,10 @@ public function addJsProvider() 'headers' => array(), 'nonce' => null ), - "\n" . - "\n" + "\n" ), array( array( @@ -315,8 +295,10 @@ public function addJsProvider() 'headers' => array(), 'nonce' => null ), - "\n" . - "\n" + "\n" ), array( array( @@ -326,8 +308,10 @@ public function addJsProvider() ), 'nonce' => 'stub-nonce' ), - "\n" . - "\n" + "\n" ), ); } From 269ef46a44715d7f61718c184ed5041e5c3d85a1 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Wed, 31 May 2017 02:07:50 +0000 Subject: [PATCH 33/45] github-137: composer fix --- tests/RollbarJsHelperTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/RollbarJsHelperTest.php b/tests/RollbarJsHelperTest.php index 5e9def7e..bae6b118 100644 --- a/tests/RollbarJsHelperTest.php +++ b/tests/RollbarJsHelperTest.php @@ -282,7 +282,7 @@ public function addJsProvider() ), "\n" ), array( @@ -295,7 +295,7 @@ public function addJsProvider() 'headers' => array(), 'nonce' => null ), - "\n" From 25831837023b3d54404bc0d9340bd82c803b0ef5 Mon Sep 17 00:00:00 2001 From: Vincent Dechenaux Date: Mon, 29 May 2017 15:54:21 +0200 Subject: [PATCH 34/45] Add failing test about PSR3 --- tests/RollbarLoggerTest.php | 88 +++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/RollbarLoggerTest.php b/tests/RollbarLoggerTest.php index fbe92b9e..539be508 100644 --- a/tests/RollbarLoggerTest.php +++ b/tests/RollbarLoggerTest.php @@ -292,4 +292,92 @@ public function testGetRequestScrubQueryString($testData) 'x' // query string is scrubbed with "x" rather than "*" ); } + + public function testPsr3Emergency() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->emergency("Testing PHP Notifier"); + } + + public function testPsr3Alert() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->alert("Testing PHP Notifier"); + } + + public function testPsr3Critical() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->critical("Testing PHP Notifier"); + } + + public function testPsr3Error() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->error("Testing PHP Notifier"); + } + + public function testPsr3Warning() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->warning("Testing PHP Notifier"); + } + + public function testPsr3Notice() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->notice("Testing PHP Notifier"); + } + + public function testPsr3Info() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->info("Testing PHP Notifier"); + } + + public function testPsr3Debug() + { + $l = new RollbarLogger(array( + "access_token" => "ad865e76e7fb496fab096ac07b1dbabb", + "environment" => "testing-php" + )); + + // Test that no \Psr\Log\InvalidArgumentException is thrown + $l->debug("Testing PHP Notifier"); + } } From e5cb998feacef078bf98aa4375cb4748ca01acfc Mon Sep 17 00:00:00 2001 From: Vincent Dechenaux Date: Mon, 29 May 2017 15:55:10 +0200 Subject: [PATCH 35/45] Map missing PSR3 levels to supported levels --- src/Payload/Level.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Payload/Level.php b/src/Payload/Level.php index 86671437..b2a8306a 100644 --- a/src/Payload/Level.php +++ b/src/Payload/Level.php @@ -8,9 +8,12 @@ private static function init() { if (is_null(self::$values)) { self::$values = array( + "emergency" => new Level("critical", 100000), + "alert" => new Level("critical", 100000), "critical" => new Level("critical", 100000), "error" => new Level("error", 10000), "warning" => new Level("warning", 1000), + "notice" => new Level("info", 100), "info" => new Level("info", 100), "debug" => new Level("debug", 10), "ignored" => new Level("ignore", 0), From 2f4a7170c9d01367560dac682a408817ed48eff3 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Thu, 1 Jun 2017 04:48:11 +0000 Subject: [PATCH 36/45] github-85: update link to Rollbar Laravel --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d90e98c8..7811af6d 100644 --- a/README.md +++ b/README.md @@ -537,7 +537,7 @@ $config['person_fn'] = 'get_current_user'; ## Related projects -A Laravel-specific package is available for integrating with Laravel: [Laravel-Rollbar](https://github.com/jenssegers/Laravel-Rollbar) +A Laravel-specific package is available for integrating with Laravel: [Rollbar Laravel](https://github.com/rollbar/rollbar-php-laravel) A CakePHP-specific package is avaliable for integrating with CakePHP 2.x: [CakeRollbar](https://github.com/tranfuga25s/CakeRollbar) From 3c504044bac7946770e5f073935782b0a2f6f726 Mon Sep 17 00:00:00 2001 From: Dmitry Kushnikov Date: Thu, 1 Jun 2017 10:34:50 +0300 Subject: [PATCH 37/45] Autocomplete support and inspection passing fix --- src/Payload/Level.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Payload/Level.php b/src/Payload/Level.php index 86671437..52360f5f 100644 --- a/src/Payload/Level.php +++ b/src/Payload/Level.php @@ -1,5 +1,14 @@ Date: Thu, 1 Jun 2017 10:56:49 -0700 Subject: [PATCH 38/45] Get rid of space change in Config.php --- src/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Config.php b/src/Config.php index 145b8fd2..10b67765 100644 --- a/src/Config.php +++ b/src/Config.php @@ -240,7 +240,7 @@ private function setSendMessageTrace($c) $this->sendMessageTrace = $c['send_message_trace']; } - + /** * Allows setting up configuration options that might be specified by class * name. Any interface used with `setupWithOptions` should be constructed From abeae8ab7625abf3593bc155d731fd3ffb009004 Mon Sep 17 00:00:00 2001 From: Andrew Ledvina Date: Thu, 1 Jun 2017 10:58:12 -0700 Subject: [PATCH 39/45] Change to checking for not null for localVarsDump --- src/Defaults.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Defaults.php b/src/Defaults.php index c46d9c70..aa6868fb 100644 --- a/src/Defaults.php +++ b/src/Defaults.php @@ -96,7 +96,7 @@ public function captureErrorStacktraces($captureErrorStracktraces = null) public function localVarsDump($localVarsDump = null) { - return $localVarsDump ? $localVarsDump : $this->defaultLocalVarsDump; + return $localVarsDump !== null ? $localVarsDump : $this->defaultLocalVarsDump; } private $defaultMessageLevel = "warning"; From 2abfbbeb9b0874f4602cff12cd6876671b954e4f Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 6 Jun 2017 17:06:21 +0200 Subject: [PATCH 40/45] Changes as suggested in PR #190 Renamed `$config` to `$configOrLogger` in `Rollbar::init()` Added tests Added DI section in README --- README.md | 17 +++++++++++++++ src/Rollbar.php | 23 ++++++++++++++++--- tests/RollbarTest.php | 51 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9d60625b..c326c725 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,23 @@ Rollbar::log( ?> ``` +## Using dependency injection + +If you're using dependency injection containers, you can create and get a `RollbarLogger` from the container and use it +to initialize Rollbar error logging. + +It's up to the container to properly create and configure the logger. + +```php +use Rollbar\Rollbar; +use Rollbar\RollbarLogger; + +$logger = $container->get(RollbarLogger::class); + +// installs global error and exception handlers +Rollbar::init($logger); +``` + ## Using Monolog Here is an example of how to use Rollbar as a handler for Monolog: diff --git a/src/Rollbar.php b/src/Rollbar.php index ea2d8d02..debe47b3 100644 --- a/src/Rollbar.php +++ b/src/Rollbar.php @@ -12,14 +12,16 @@ class Rollbar private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); public static function init( - $config, + $configOrLogger, $handleException = true, $handleError = true, $handleFatal = true ) { - if (is_null(self::$logger)) { - self::$logger = $config instanceof RollbarLogger ? $config : new RollbarLogger($config); + $setupHandlers = is_null(self::$logger); + + self::setLogger($configOrLogger); + if ($setupHandlers) { if ($handleException) { self::setupExceptionHandling(); } @@ -29,9 +31,24 @@ public static function init( if ($handleFatal) { self::setupFatalHandling(); } + } + } + + private static function setLogger($configOrLogger) + { + if ($configOrLogger instanceof RollbarLogger) { + $logger = $configOrLogger; } else { + $config = $configOrLogger; + } + + // Replacing the logger rather than configuring the existing logger breaks BC + if (self::$logger && isset($config)) { self::$logger->configure($config); + return; } + + self::$logger = isset($logger) ? $logger : new RollbarLogger($config); } public static function logger() diff --git a/tests/RollbarTest.php b/tests/RollbarTest.php index d2d7d673..3274f2af 100644 --- a/tests/RollbarTest.php +++ b/tests/RollbarTest.php @@ -15,13 +15,56 @@ class RollbarTest extends \PHPUnit_Framework_TestCase 'environment' => 'test' ); - public function setUp() + public function tearDown() + { + $reflLoggerProperty = new \ReflectionProperty(Rollbar::class, 'logger'); + $reflLoggerProperty->setAccessible(true); + $reflLoggerProperty->setValue(null); + } + + public function testInitWithConfig() { Rollbar::init(self::$simpleConfig); + + $this->assertInstanceOf(RollbarLogger::class, Rollbar::logger()); + $this->assertAttributeEquals(new Config(self::$simpleConfig), 'config', Rollbar::logger()); } + public function testInitWithLogger() + { + $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + + Rollbar::init($logger); + + $this->assertSame($logger, Rollbar::logger()); + } + + public function testInitConfigureLogger() + { + $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + $logger->expects($this->once())->method('configure')->with(self::$simpleConfig); + + Rollbar::init($logger); + Rollbar::init(self::$simpleConfig); + } + + public function testInitReplaceLogger() + { + Rollbar::init(self::$simpleConfig); + + $this->assertInstanceOf(RollbarLogger::class, Rollbar::logger()); + + $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + + Rollbar::init($logger); + + $this->assertSame($logger, Rollbar::logger()); + } + public function testLogException() { + Rollbar::init(self::$simpleConfig); + try { throw new \Exception('test exception'); } catch (\Exception $e) { @@ -33,12 +76,16 @@ public function testLogException() public function testLogMessage() { + Rollbar::init(self::$simpleConfig); + Rollbar::log(Level::info(), 'testing info level'); $this->assertTrue(true); } public function testLogExtraData() { + Rollbar::init(self::$simpleConfig); + Rollbar::log( Level::info(), 'testing extra data', @@ -84,6 +131,8 @@ public function testBackwardsSimpleException() public function testBackwardsFlush() { + Rollbar::init(self::$simpleConfig); + Rollbar::flush(); $this->assertTrue(true); } From b088ccf77495cc631f579effbd05d652208b485f Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 6 Jun 2017 17:23:50 +0200 Subject: [PATCH 41/45] Remove `else` as suggested by code climate. (Don't really agree) --- src/Rollbar.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Rollbar.php b/src/Rollbar.php index debe47b3..b4c269e0 100644 --- a/src/Rollbar.php +++ b/src/Rollbar.php @@ -38,17 +38,15 @@ private static function setLogger($configOrLogger) { if ($configOrLogger instanceof RollbarLogger) { $logger = $configOrLogger; - } else { - $config = $configOrLogger; } // Replacing the logger rather than configuring the existing logger breaks BC - if (self::$logger && isset($config)) { - self::$logger->configure($config); + if (self::$logger && !isset($logger)) { + self::$logger->configure($configOrLogger); return; } - self::$logger = isset($logger) ? $logger : new RollbarLogger($config); + self::$logger = isset($logger) ? $logger : new RollbarLogger($configOrLogger); } public static function logger() From 8efb5c90c0c98970c6675b378aac3bb37c1f11ec Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 6 Jun 2017 17:30:24 +0200 Subject: [PATCH 42/45] Unset the global logger before running RollbarTest. Not all tests properly clean up the global scope. --- tests/RollbarTest.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/RollbarTest.php b/tests/RollbarTest.php index 3274f2af..e5129892 100644 --- a/tests/RollbarTest.php +++ b/tests/RollbarTest.php @@ -14,14 +14,24 @@ class RollbarTest extends \PHPUnit_Framework_TestCase 'access_token' => ROLLBAR_TEST_TOKEN, 'environment' => 'test' ); - - public function tearDown() + + private static function clearLogger() { $reflLoggerProperty = new \ReflectionProperty(Rollbar::class, 'logger'); $reflLoggerProperty->setAccessible(true); $reflLoggerProperty->setValue(null); } + public static function setupBeforeClass() + { + self::clearLogger(); + } + + public function tearDown() + { + self::clearLogger(); + } + public function testInitWithConfig() { Rollbar::init(self::$simpleConfig); From ea3aec98142403805f2c33c9f4184a8d7bce3491 Mon Sep 17 00:00:00 2001 From: Arnold Daniels Date: Tue, 6 Jun 2017 17:44:52 +0200 Subject: [PATCH 43/45] Tests need to run on php 5.3 / 5.4. OMG --- tests/RollbarTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/RollbarTest.php b/tests/RollbarTest.php index e5129892..9467967c 100644 --- a/tests/RollbarTest.php +++ b/tests/RollbarTest.php @@ -17,7 +17,7 @@ class RollbarTest extends \PHPUnit_Framework_TestCase private static function clearLogger() { - $reflLoggerProperty = new \ReflectionProperty(Rollbar::class, 'logger'); + $reflLoggerProperty = new \ReflectionProperty('Rollbar\Rollbar', 'logger'); $reflLoggerProperty->setAccessible(true); $reflLoggerProperty->setValue(null); } @@ -36,13 +36,13 @@ public function testInitWithConfig() { Rollbar::init(self::$simpleConfig); - $this->assertInstanceOf(RollbarLogger::class, Rollbar::logger()); + $this->assertInstanceOf('Rollbar\RollbarLogger', Rollbar::logger()); $this->assertAttributeEquals(new Config(self::$simpleConfig), 'config', Rollbar::logger()); } public function testInitWithLogger() { - $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + $logger = $this->getMockBuilder('Rollbar\RollbarLogger')->disableOriginalConstructor()->getMock(); Rollbar::init($logger); @@ -51,7 +51,7 @@ public function testInitWithLogger() public function testInitConfigureLogger() { - $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + $logger = $this->getMockBuilder('Rollbar\RollbarLogger')->disableOriginalConstructor()->getMock(); $logger->expects($this->once())->method('configure')->with(self::$simpleConfig); Rollbar::init($logger); @@ -62,9 +62,9 @@ public function testInitReplaceLogger() { Rollbar::init(self::$simpleConfig); - $this->assertInstanceOf(RollbarLogger::class, Rollbar::logger()); + $this->assertInstanceOf('Rollbar\RollbarLogger', Rollbar::logger()); - $logger = $this->getMockBuilder(RollbarLogger::class)->disableOriginalConstructor()->getMock(); + $logger = $this->getMockBuilder('Rollbar\RollbarLogger')->disableOriginalConstructor()->getMock(); Rollbar::init($logger); From 2ec492eeea86959f17803d34a48e053c3234854c Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Sat, 10 Jun 2017 19:10:16 -0700 Subject: [PATCH 44/45] Remove the old calls to scrub methods that creeped in --- src/DataBuilder.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DataBuilder.php b/src/DataBuilder.php index 03547510..e69266d7 100644 --- a/src/DataBuilder.php +++ b/src/DataBuilder.php @@ -554,14 +554,14 @@ protected function getRequest() if (isset($_SERVER)) { $request->setMethod($this->tryGet($_SERVER, 'REQUEST_METHOD')) - ->setQueryString(self::scrubUrl($this->tryGet($_SERVER, "QUERY_STRING"), $scrubFields)); + ->setQueryString($this->tryGet($_SERVER, "QUERY_STRING")); } if (isset($_GET)) { - $request->setGet(self::scrub($_GET, $scrubFields)); + $request->setGet($_GET); } if (isset($_POST)) { - $request->setPost(self::scrub($_POST, $scrubFields)); + $request->setPost($_POST); } $extras = $this->getRequestExtras(); if (!$extras) { From 231b42de93b453713f6a90b7b84ba0802ee3fdbf Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Sat, 10 Jun 2017 19:31:26 -0700 Subject: [PATCH 45/45] Suppress the static access warnings Static access is intended in these tests so suppress the warning for PHPMD. --- tests/RollbarTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/RollbarTest.php b/tests/RollbarTest.php index 9467967c..bfbd48e0 100644 --- a/tests/RollbarTest.php +++ b/tests/RollbarTest.php @@ -7,6 +7,11 @@ use Rollbar\Rollbar; use Rollbar\Payload\Level; +/** + * Usage of static method Rollbar::logger() is intended here. + * + * @SuppressWarnings(PHPMD.StaticAccess) + */ class RollbarTest extends \PHPUnit_Framework_TestCase {