From 62916abb469d54bb08dc0d7e737881658b040b90 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Mon, 29 Nov 2021 16:45:55 +1300 Subject: [PATCH] ENH: Provide support for raygun4php ^1 and ^2. --- _config/cache.yml | 8 +++ composer.json | 2 +- src/RaygunClientFactory.php | 111 ++++++++++++++++++++++++++++++++---- 3 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 _config/cache.yml diff --git a/_config/cache.yml b/_config/cache.yml new file mode 100644 index 0000000..263cb75 --- /dev/null +++ b/_config/cache.yml @@ -0,0 +1,8 @@ +--- +Name: raygun-cache +--- +SilverStripe\Core\Injector\Injector: + Psr\SimpleCache\CacheInterface.raygunCache: + factory: SilverStripe\Core\Cache\CacheFactory + constructor: + namespace: "raygunCache" diff --git a/composer.json b/composer.json index 640f869..f5402b4 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ ], "require": { "php": ">=7.1", - "mindscape/raygun4php": "^1", + "mindscape/raygun4php": "^1 || ^2", "silverstripe/framework": "^4.3" }, "autoload": { diff --git a/src/RaygunClientFactory.php b/src/RaygunClientFactory.php index e5cb947..f4a35fb 100644 --- a/src/RaygunClientFactory.php +++ b/src/RaygunClientFactory.php @@ -2,13 +2,20 @@ namespace SilverStripe\Raygun; +use GuzzleHttp\Client; +use LogicException; +use Psr\SimpleCache\CacheInterface; +use Raygun4php\RaygunClient; +use Raygun4php\Transports\GuzzleAsync; +use SilverStripe\Control\Director; use SilverStripe\Core\Config\Config; -use SilverStripe\Core\Injector\Factory; use SilverStripe\Core\Environment; -use SilverStripe\Control\Director; -use Raygun4php\RaygunClient; +use SilverStripe\Core\Flushable; +use SilverStripe\Core\Injector\Factory; +use SilverStripe\Core\Injector\Injector; +use SilverStripe\Core\Path; -class RaygunClientFactory implements Factory +class RaygunClientFactory implements Factory, Flushable { use CustomAppKeyProvider; @@ -34,19 +41,35 @@ public function create($service, array $params = []) { // extract api key from .env file $apiKey = $this->getCustomRaygunAppKey() ?? (string) Environment::getEnv(self::RAYGUN_APP_KEY_NAME); + + // log error to warn user that exceptions will not be logged to Raygun + if (empty($apiKey) && !Director::isDev()) { + $name = self::RAYGUN_APP_KEY_NAME; + user_error("You need to set the {$name} environment variable in order to log to Raygun.", E_USER_WARNING); + } + + // check if user tracking is enabled $disableTracking = Config::inst()->get( RaygunClient::class, 'disable_user_tracking' ); $disableTracking = is_bool($disableTracking) ? $disableTracking : false; - // log error to warn user that exceptions will not be logged to Raygun - if (empty($apiKey) && !Director::isDev()) { - $name = self::RAYGUN_APP_KEY_NAME; - user_error("You need to set the {$name} environment variable in order to log to Raygun.", E_USER_WARNING); + // Setup new client in the way that is best for the current SDK version. + if (substr(ltrim(static::getSdkVersion(), 'v'), 0, 2) === '1.') { + $this->createForV1($apiKey, $disableTracking, $params); + } else { + $this->createForV2($apiKey, $disableTracking, $params); } - // setup new client + $this->filterSensitiveData(); + + return $this->client; + } + + protected function createForV1($apiKey, $disableTracking, $params) + { + // Instantiate actual client $this->client = new RaygunClient( $apiKey, true, @@ -54,7 +77,7 @@ public function create($service, array $params = []) $disableTracking ); - // set proxy + // Set proxy if (!empty($params['proxyHost'])) { $proxy = $params['proxyHost']; if (!empty($params['proxyPort'])) { @@ -62,10 +85,36 @@ public function create($service, array $params = []) } $this->client->setProxy($proxy); } + } - $this->filterSensitiveData(); + protected function createForV2($apiKey, $disableTracking, $params) + { + // Prepare transport config. + $transportConfig = [ + 'base_uri' => 'https://api.raygun.com', + 'timeout' => 2.0, + 'headers' => [ + 'X-ApiKey' => $apiKey, + ], + ]; - return $this->client; + // Set proxy + if (!empty($params['proxyHost'])) { + $proxy = $params['proxyHost']; + if (!empty($params['proxyPort'])) { + $proxy .= ':' . $params['proxyPort']; + } + $transportConfig['proxy'] = $proxy; + } + + // Create raygun client using async transport. + $transport = new GuzzleAsync( + new Client($transportConfig) + ); + $this->client = new RaygunClient($transport, $disableTracking); + + // Ensure asynchronous requests are given time to finish. + register_shutdown_function([$transport, 'wait']); } protected function filterSensitiveData() @@ -86,4 +135,42 @@ protected function filterSensitiveData() 'Cookie' => true, ]); } + + /** + * Get the currently installed version of the raygun4php package according to composer.lock + * + * @return string + */ + public static function getSdkVersion() + { + $cache = Injector::inst()->get(CacheInterface::class . '.raygunCache'); + // If the SDK version isn't cached, get it from the composer.lock file. + // Note that this is called before flushing has occurred - if we're flushing, bypass the cache for now. + if (Director::isManifestFlushed() || !$version = $cache->get('raygun4phpVersion')) { + $composerLockRaw = file_get_contents(Path::join(Director::baseFolder(), 'composer.lock')); + if (!$composerLockRaw) { + throw new LogicException('composer.lock file is missing.'); + } + $packageList = json_decode($composerLockRaw, true)['packages']; + foreach ($packageList as $package) { + if ($package['name'] === 'mindscape/raygun4php') { + $version = $package['version']; + break; + } + } + if (!$version) { + throw new LogicException('mindscape/raygun4php not found in composer.lock'); + } + // Cache the SDK version so we don't have to do this every request. + $cache->set('raygun4phpVersion', $version); + } + + return $version; + } + + public static function flush() + { + $cache = Injector::inst()->get(CacheInterface::class . '.raygunCache'); + $cache->clear(); + } }