forked from residit/nette-logger
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
04837b7
commit e1839fa
Showing
5 changed files
with
316 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.idea | ||
vendor | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Nette Logger | ||
|
||
Tracy logger extension capable of logging messages and errors to API. | ||
|
||
*Note*: If you have debug mode enabled in your application, logger will only send `\Tracy\Debugger::log()` messages to sentry. Any exception ending with Tracy's blue screen is not going to be logged as you can see the exception details directly. | ||
|
||
You can disable debug mode by inserting the lines below in file *bootstrap.php* | ||
|
||
```php | ||
$configurator->setDebugMode(false); | ||
``` | ||
|
||
## Installation | ||
|
||
Install package via Composer: | ||
|
||
``` | ||
composer require residit/nette-logger | ||
``` | ||
|
||
## Configuration | ||
|
||
Enable and configure the extension in Nette config file: | ||
|
||
```neon | ||
extensions: | ||
# ... | ||
nette-logger: Residit\NetteLogger\DI\NetteLoggerExtension | ||
nette-logger: | ||
dsn: https://[email protected]/123 # required | ||
environment: production # optional, defaults to "local" | ||
user_fields: # optional, defaults to empty array; Nette's identity ID is being sent automatically | ||
priority_mapping: | ||
mypriority: warning | ||
``` | ||
|
||
### Priority-Severity mapping | ||
|
||
Sometimes you might need to use custom *priority* when logging the error in Nette: | ||
|
||
```php | ||
\Tracy\Debugger::log('foo', 'mypriority'); | ||
``` | ||
|
||
Sentry only allows strict set of severities. By default any message with unknown (non-standard) severity is not being logged. | ||
|
||
You can map your custom *priority* to Sentry's *severity* in config by using `priority_mapping` as shown in the example. | ||
|
||
The allowed set of Sentry severities can be checked in [Sentry's PHP repository](https://github.com/getsentry/sentry-php/blob/master/src/Severity.php). | ||
|
||
## Usage | ||
|
||
Once enabled as extension, you can continue to throw exceptions without any change. To log message please use `\Tracy\Debugger::log()` method. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,28 @@ | ||
{ | ||
"name": "residit/nette-logger", | ||
"require": {} | ||
} | ||
"name": "residit/nette-logger", | ||
"description": "Custom Nette logger library", | ||
"homepage": "https://github.com/residit/nette-logger", | ||
"license": "MIT", | ||
"keywords": ["nette", "errorlogger", "errors"], | ||
"authors": [ | ||
{ | ||
"name": "Jan Vaníček", | ||
"email": "[email protected]", | ||
"homepage": "https://janvanicek.com/", | ||
"role": "Developer" | ||
} | ||
], | ||
"type": "library", | ||
"require": { | ||
"sentry/sdk": "^2.1", | ||
"tracy/tracy": "~2.4", | ||
"nette/di": "^2.4 || ^3.0", | ||
"nette/security": "^2.4 || ^3.0", | ||
"nette/http": "^2.4 || ^3.0" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"Residit\\NetteLogger\\": "/src" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Residit\NetteLogger\DI; | ||
|
||
use Nette\DI\CompilerExtension; | ||
use Tracy\Debugger; | ||
use Tracy\ILogger; | ||
|
||
class NetteLoggerExtension extends CompilerExtension | ||
{ | ||
private const PARAM_DSN = 'dsn'; | ||
private const PARAM_ENVIRONMENT = 'environment'; | ||
private const PARAM_USER_FIELDS = 'user_fields'; | ||
private const PARAM_PRIORITIES_MAPPING = 'priority_mapping'; | ||
|
||
private $defaults = [ | ||
self::PARAM_DSN => null, | ||
self::PARAM_ENVIRONMENT => 'local', | ||
self::PARAM_USER_FIELDS => [], | ||
self::PARAM_PRIORITIES_MAPPING => [], | ||
]; | ||
|
||
private $enabled = false; | ||
|
||
public function loadConfiguration() | ||
{ | ||
$this->validateConfig($this->defaults); | ||
if (!$this->config[self::PARAM_DSN]) { | ||
Debugger::log('Unable to initialize SentryExtension, dsn config option is missing', ILogger::WARNING); | ||
return; | ||
} | ||
$this->enabled = true; | ||
|
||
$this->getContainerBuilder() | ||
->addDefinition($this->prefix('logger')) | ||
->setFactory(\Residit\NetteLogger\NetteLogger::class) | ||
->addSetup( | ||
'register', | ||
[ | ||
$this->config[self::PARAM_DSN], | ||
$this->config[self::PARAM_ENVIRONMENT], | ||
] | ||
)->addSetup( | ||
'setUserFields', | ||
[ | ||
$this->config[self::PARAM_USER_FIELDS], | ||
] | ||
)->addSetup( | ||
'setPriorityMapping', | ||
[ | ||
$this->config[self::PARAM_PRIORITIES_MAPPING], | ||
] | ||
); | ||
} | ||
|
||
public function beforeCompile() | ||
{ | ||
if (!$this->enabled) { | ||
return; | ||
} | ||
|
||
$builder = $this->getContainerBuilder(); | ||
if ($builder->hasDefinition('tracy.logger')) { | ||
$builder->getDefinition('tracy.logger')->setAutowired(false); | ||
} | ||
if ($builder->hasDefinition('security.user')) { | ||
$builder->getDefinition($this->prefix('logger')) | ||
->addSetup('setUser', [$builder->getDefinition('security.user')]); | ||
} | ||
if ($builder->hasDefinition('session.session')) { | ||
$builder->getDefinition($this->prefix('logger')) | ||
->addSetup('setSession', [$builder->getDefinition('session.session')]); | ||
} | ||
} | ||
|
||
public function afterCompile(\Nette\PhpGenerator\ClassType $class) | ||
{ | ||
if (!$this->enabled) { | ||
return; | ||
} | ||
|
||
$class->getMethod('initialize') | ||
->addBody('Tracy\Debugger::setLogger($this->getService(?));', [ $this->prefix('logger') ]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Residit\NetteLogger; | ||
|
||
use Nette\Http\Session; | ||
use Nette\Security\IIdentity; | ||
use Nette\Security\User; | ||
use Sentry\ClientBuilder; | ||
use Sentry\Integration\RequestIntegration; | ||
use Sentry\Severity; | ||
use Sentry\State\Hub; | ||
use Tracy\Debugger; | ||
use Tracy\ILogger; | ||
use Tracy\Logger; | ||
use function Sentry\captureException; | ||
use function Sentry\captureMessage; | ||
use function Sentry\configureScope; | ||
|
||
class NetteLogger extends Logger | ||
{ | ||
/** @var IIdentity */ | ||
private $identity; | ||
|
||
/** @var Session */ | ||
private $session; | ||
|
||
/** @var array */ | ||
private $userFields = []; | ||
|
||
/** @var array */ | ||
private $priorityMapping = []; | ||
|
||
public function register(string $dsn, string $environment) | ||
{ | ||
$options = new \Sentry\Options([ | ||
'dsn' => $dsn, | ||
'environment' => $environment, | ||
'default_integrations' => false, | ||
]); | ||
|
||
$options->setIntegrations([ | ||
new RequestIntegration($options), | ||
]); | ||
|
||
$builder = new ClientBuilder($options); | ||
$client = $builder->getClient(); | ||
Hub::setCurrent(new Hub($client)); | ||
|
||
$this->email = & Debugger::$email; | ||
$this->directory = Debugger::$logDirectory; | ||
} | ||
|
||
public function setUser(User $user) | ||
{ | ||
$this->identity = $user->getIdentity(); | ||
} | ||
|
||
public function setUserFields(array $userFields) | ||
{ | ||
$this->userFields = $userFields; | ||
} | ||
|
||
public function setPriorityMapping(array $priorityMapping) | ||
{ | ||
$this->priorityMapping = $priorityMapping; | ||
} | ||
|
||
public function setSession(Session $session) | ||
{ | ||
$this->session = $session; | ||
} | ||
|
||
public function log($value, $priority = ILogger::INFO) | ||
{ | ||
$response = parent::log($value, $priority); | ||
$severity = $this->tracyPriorityToSentrySeverity($priority); | ||
|
||
// if it's non-default severity, let's try configurable mapping | ||
if (!$severity) { | ||
$mappedSeverity = $this->priorityMapping[$priority] ?? null; | ||
if ($mappedSeverity) { | ||
$severity = new Severity((string) $mappedSeverity); | ||
} | ||
} | ||
// if we still don't have severity, don't log anything | ||
if (!$severity) { | ||
return $response; | ||
} | ||
|
||
configureScope(function (\Sentry\State\Scope $scope) use ($severity) { | ||
if (!$severity) { | ||
return; | ||
} | ||
$scope->setLevel($severity); | ||
if ($this->identity) { | ||
$userFields = [ | ||
'id' => $this->identity->getId(), | ||
]; | ||
foreach ($this->userFields as $name) { | ||
$userFields[$name] = $this->identity->{$name} ?? null; | ||
} | ||
$scope->setUser($userFields); | ||
} | ||
if ($this->session) { | ||
$data = []; | ||
foreach ($this->session->getIterator() as $section) { | ||
foreach ($this->session->getSection($section)->getIterator() as $key => $val) { | ||
$data[$section][$key] = $val; | ||
} | ||
} | ||
$scope->setExtra('session', $data); | ||
} | ||
}); | ||
|
||
if ($value instanceof \Throwable) { | ||
captureException($value); | ||
} else { | ||
captureMessage($value); | ||
} | ||
|
||
return $response; | ||
} | ||
|
||
private function tracyPriorityToSentrySeverity(string $priority): ?Severity | ||
{ | ||
switch ($priority) { | ||
case ILogger::DEBUG: | ||
return Severity::debug(); | ||
case ILogger::INFO: | ||
return Severity::info(); | ||
case ILogger::WARNING: | ||
return Severity::warning(); | ||
case ILogger::ERROR: | ||
case ILogger::EXCEPTION: | ||
return Severity::error(); | ||
case ILogger::CRITICAL: | ||
return Severity::fatal(); | ||
default: | ||
return null; | ||
} | ||
} | ||
} |