Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH support raygun4php SDK v2 #67

Merged
merged 2 commits into from
Dec 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions _config/cache.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
Name: raygun-cache
---
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.raygunCache:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "raygunCache"
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
],
"require": {
"php": ">=7.1",
"mindscape/raygun4php": "^1",
"silverstripe/framework": "^4.3",
"graze/monolog-extensions": "^2"
"mindscape/raygun4php": "^1 || ^2",
"silverstripe/framework": "^4.3"
},
"autoload": {
"psr-4": {
Expand Down
111 changes: 99 additions & 12 deletions src/RaygunClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -34,38 +41,80 @@ 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,
false,
$disableTracking
);

// set proxy
// Set proxy
if (!empty($params['proxyHost'])) {
$proxy = $params['proxyHost'];
if (!empty($params['proxyPort'])) {
$proxy .= ':' . $params['proxyPort'];
}
$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()
Expand All @@ -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();
}
}
73 changes: 73 additions & 0 deletions src/RaygunFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/*
* This file was originally part of Monolog Extensions
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Nature Delivered Ltd. <http://graze.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @see http://github.com/graze/MonologExtensions/blob/master/LICENSE
* @link http://github.com/graze/MonologExtensions
*/

namespace SilverStripe\Raygun;

use Monolog\Formatter\NormalizerFormatter;

class RaygunFormatter extends NormalizerFormatter
{
/**
* {@inheritdoc}
*
* @param array $record A record to format
*
* @return mixed The formatted record
*/
public function format(array $record)
{
$record = parent::format($record);

$record['tags'] = [];
$record['custom_data'] = [];
$record['timestamp'] = null;

foreach (['extra', 'context'] as $source) {
if (array_key_exists('tags', $record[$source]) && is_array($record[$source]['tags'])) {
$record['tags'] = array_merge($record['tags'], $record[$source]['tags']);
}
if (array_key_exists('timestamp', $record[$source]) && is_numeric($record[$source]['timestamp'])) {
$record['timestamp'] = $record[$source]['timestamp'];
}
unset($record[$source]['tags'], $record[$source]['timestamp']);
}

$record['custom_data'] = $record['extra'];
$record['extra'] = [];
foreach ($record['context'] as $key => $item) {
if (!in_array($key, ['file', 'line', 'exception'])) {
$record['custom_data'][$key] = $item;
unset($record['context'][$key]);
}
}

return $record;
}
}
Loading