diff --git a/docs/tutorials/add-logger-adapter.md b/docs/tutorials/add-logger-adapter.md index 8b5850f..8e5dfd5 100644 --- a/docs/tutorials/add-logger-adapter.md +++ b/docs/tutorials/add-logger-adapter.md @@ -1,6 +1,6 @@ # Adding a new logger adapter 💾 -This document is part of the Utopia contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://raw.githubusercontent.com/utopia-php/logger/main/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://raw.githubusercontent.com/utopia-php/logger/main/CONTRIBUTING.md). +This document is part of the Utopia contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](../../CODE_OF_CONDUCT.md) and the [Contributing Guide](../../CONTRIBUTING.md). ## Getting started @@ -139,7 +139,7 @@ In `src/Logger/Logger.php` update variable `const PROVIDERS` to include your pro ## 3. Test your adapter -After you finished adding your new adapter, you should write a proper test for it. To do that, you enter `tests/LoggerTests.php` and take a look at `testAdapters()` method. In there, we already build a whole log object and all you need to do is to push the log using your provider. Take a look at how test for already existign adapter looks or use template below: +After you finished adding your new adapter, you should write a proper test for it. To do that, you enter `tests/LoggerTests.php` and take a look at `testAdapters()` method. In there, we already build a whole log object and all you need to do is to push the log using your provider. Take a look at how test for already existing adapter looks or use the template below: ```php // Test [ADAPTER_NAME] diff --git a/src/Logger/Adapter/HoneyBadger.php b/src/Logger/Adapter/HoneyBadger.php new file mode 100644 index 0000000..ae5fdef --- /dev/null +++ b/src/Logger/Adapter/HoneyBadger.php @@ -0,0 +1,176 @@ +getExtra() as $paramKey => $paramValue) { + $params[$paramKey] = var_export($paramValue, true); + } + + $breadcrumbsObject = $log->getBreadcrumbs(); + $breadcrumbsArray = []; + + foreach ($breadcrumbsObject as $breadcrumb) { + \array_push($breadcrumbsArray, [ + 'category' => $breadcrumb->getCategory(), + 'timestamp' => \intval($breadcrumb->getTimestamp()), + 'message' => $breadcrumb->getMessage(), + 'metadata' => [ + 'exception' => $breadcrumb->getType(), + ], + ]); + } + + $stackFrames = []; + + if (isset($log->getExtra()['detailedTrace'])) { + $detailedTrace = $log->getExtra()['detailedTrace']; + if (! is_array($detailedTrace)) { + throw new Exception('detailedTrace must be an array'); + } + foreach ($detailedTrace as $trace) { + if (! is_array($trace)) { + throw new Exception('detailedTrace must be an array of arrays'); + } + \array_push($stackFrames, [ + 'filename' => $trace['file'] ?? '', + 'lineno' => $trace['line'] ?? '', + 'function' => $trace['function'] ?? '', + ]); + } + } + + $requestBody = [ + 'notifier' => [ + 'name' => 'utopia-logger', + 'url' => 'https://github.com/utopia-php/logger', + 'tags' => $log->getTags(), + 'version' => $log->getVersion(), + ], + 'error' => [ + 'class' => $log->getType(), + 'message' => $log->getMessage(), + 'backtrace' => $stackFrames, + ], + 'breadcrumbs' => [ + 'enabled' => true, + 'trail' => $breadcrumbsArray, + ], + + 'request' => [ + 'params' => $params, + 'action' => $log->getAction(), + 'context' => empty($log->getUser()) ? null : [ + 'user_id' => $log->getUser()->getId(), + 'user_email' => $log->getUser()->getEmail(), + ], + + ], + 'server' => [ + 'project_root' => $log->getServer(), + 'environment_name' => $log->getEnvironment(), + 'hostname' => $log->getServer(), + ], + + ]; + + // init curl object + $ch = \curl_init(); + + // define options + $optArray = [ + CURLOPT_URL => 'https://api.honeybadger.io/v1/notices', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => \json_encode($requestBody), + CURLOPT_HEADEROPT => \CURLHEADER_UNIFIED, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: '.$this->apiKey, 'Accept: application/json', 'User-Agent: utopia-logger/'.Logger::LIBRARY_VERSION], + ]; + + // apply those options + \curl_setopt_array($ch, $optArray); + + // execute request and get response + $result = \curl_exec($ch); + $response = \curl_getinfo($ch, \CURLINFO_HTTP_CODE); + + if (! $result && $response >= 400) { + throw new Exception('Log could not be pushed with status code '.$response.': '.\curl_error($ch)); + } + + \curl_close($ch); + + return $response; + } + + /** + * HoneyBadger constructor. + * + * @param string $configKey + */ + public function __construct(string $configKey) + { + $this->apiKey = $configKey; + } + + public function getSupportedTypes(): array + { + return [ + Log::TYPE_INFO, + Log::TYPE_DEBUG, + Log::TYPE_VERBOSE, + Log::TYPE_WARNING, + Log::TYPE_ERROR, + ]; + } + + public function getSupportedEnvironments(): array + { + return [ + Log::ENVIRONMENT_STAGING, + Log::ENVIRONMENT_PRODUCTION, + ]; + } + + public function getSupportedBreadcrumbTypes(): array + { + return [ + Log::TYPE_INFO, + Log::TYPE_DEBUG, + Log::TYPE_VERBOSE, + Log::TYPE_WARNING, + Log::TYPE_ERROR, + ]; + } +} diff --git a/src/Logger/Logger.php b/src/Logger/Logger.php index 714ae51..458fc81 100644 --- a/src/Logger/Logger.php +++ b/src/Logger/Logger.php @@ -13,6 +13,7 @@ class Logger 'sentry', 'appSignal', 'logOwl', + 'honeyBadger', ]; /** diff --git a/tests/LoggerTest.php b/tests/LoggerTest.php old mode 100755 new mode 100644 index a3a0d0c..9261286 --- a/tests/LoggerTest.php +++ b/tests/LoggerTest.php @@ -2,6 +2,7 @@ use PHPUnit\Framework\TestCase; use Utopia\Logger\Adapter\AppSignal; +use Utopia\Logger\Adapter\HoneyBadger; use Utopia\Logger\Adapter\LogOwl; use Utopia\Logger\Adapter\Raygun; use Utopia\Logger\Adapter\Sentry; @@ -138,7 +139,7 @@ public function testAdapters(): void $log->setType(Log::TYPE_ERROR); $log->setVersion('0.11.5'); $log->setMessage('Document efgh5678 not found'); - $log->setUser(new User('efgh5678')); + $log->setUser(new User('efgh5678', 'abc@test.com', 'John Doe')); $log->addBreadcrumb(new Breadcrumb(Log::TYPE_DEBUG, 'http', 'DELETE /api/v1/database/abcd1234/efgh5678', \microtime(true) - 500)); $log->addBreadcrumb(new Breadcrumb(Log::TYPE_DEBUG, 'auth', 'Using API key', \microtime(true) - 400)); $log->addBreadcrumb(new Breadcrumb(Log::TYPE_INFO, 'auth', 'Authenticated with * Using API Key', \microtime(true) - 350)); @@ -154,6 +155,7 @@ public function testAdapters(): void $log->addExtra('isExpected', true); $log->addExtra('file', '/User/example/server/src/server/server.js'); $log->addExtra('line', '15'); + $log->addExtra('stackTrace', [['number' => 15, 'file' => 'User/example/server/src/server/server.js', 'method' => 'runtime_error']]); // Test Sentry $adapter = new Sentry(\getenv('TEST_SENTRY_KEY').';'.\getenv('TEST_SENTRY_PROJECT_ID').';'.\getenv('TEST_SENTRY_HOST')); @@ -181,5 +183,12 @@ public function testAdapters(): void $logger = new Logger($adapter); $response = $logger->addLog($log); $this->assertEquals(200, $response); + + // Test HoneyBadger + $honebadgerkey = \getenv('TEST_HONEYBADGER_KEY'); + $adapter = new HoneyBadger($honebadgerkey ? $honebadgerkey : ''); + $logger = new Logger($adapter); + $response = $logger->addLog($log); + $this->assertEquals(201, $response); } }