Benjamin Renard
6fdc5447f1
* Code cleaning and fix some small errors using Phpstan * Configure pre-commit to run Phpstan before each commit * Some little improvments and logging, mail, smarty & URL libs * Add Sentry integration * Add Webstat JS code inclusion * Install Smarty dependency using composer Breaking changes: * Rename Event class as HookEvent to avoid conflict with PECL event * URL with refresh GET parameter now automatically trigger redirection without it after page loading to avoid to keep it in URL
213 lines
5.8 KiB
PHP
213 lines
5.8 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Configuration :
|
|
*
|
|
* // Log PHP errors in Sentry: list of errors types to logs
|
|
* // Note: must also match with $log_php_errors_levels.
|
|
* // See: https://www.php.net/manual/fr/errorfunc.constants.php
|
|
* $sentry_php_error_types = array(
|
|
* E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
|
|
* E_RECOVERABLE_ERROR,E_DEPRECATED,
|
|
* );
|
|
*/
|
|
|
|
// Init Sentry (if its DSN is configured)
|
|
if (isset($sentry_dsn) && $sentry_dsn) {
|
|
\Sentry\init([
|
|
'dsn' => $sentry_dsn,
|
|
'traces_sample_rate' => (
|
|
isset($sentry_traces_sample_rate) ?
|
|
$sentry_traces_sample_rate : 0.2
|
|
),
|
|
]);
|
|
|
|
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
|
global $auth_user;
|
|
$scope->setUser([
|
|
'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null,
|
|
'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null,
|
|
'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null,
|
|
'ip_address' => $_SERVER['REMOTE_ADDR'],
|
|
]);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log an exception or a message in Sentry
|
|
* @param string|Exception $msg
|
|
* @return void
|
|
*/
|
|
function log_in_sentry($msg) {
|
|
global $sentry_dsn;
|
|
if (!isset($sentry_dsn) || !$sentry_dsn) {
|
|
logging('TRACE', 'Sentry DSN not configured, do not log this error');
|
|
return;
|
|
}
|
|
if (is_string($msg)) {
|
|
logging('DEBUG', 'Error logged in Sentry');
|
|
\Sentry\captureMessage($msg);
|
|
}
|
|
elseif ($msg instanceof Exception) {
|
|
logging('DEBUG', 'Exception logged in Sentry');
|
|
\Sentry\captureException($msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log a PHP error in Sentry
|
|
* @param int $errno The error number
|
|
* @param string $msg The error message
|
|
* @return void
|
|
*/
|
|
function log_php_error_in_sentry($errno, $msg) {
|
|
global $sentry_php_error_types;
|
|
if (
|
|
isset($sentry_php_error_types)
|
|
&& is_array($sentry_php_error_types)
|
|
&& in_array($errno, $sentry_php_error_types)
|
|
)
|
|
log_in_sentry($msg);
|
|
}
|
|
|
|
/*
|
|
* Performance monitoring
|
|
*/
|
|
|
|
class SentryTransaction {
|
|
|
|
/**
|
|
* The Sentry transaction object
|
|
* @var \Sentry\Tracing\Transaction
|
|
*/
|
|
private $transaction;
|
|
|
|
/**
|
|
* The Sentry transaction context object
|
|
* @var \Sentry\Tracing\TransactionContext
|
|
*/
|
|
private $context;
|
|
|
|
/**
|
|
* Constructor: start a Sentry transaction
|
|
* @param string|null $op The operation name
|
|
* @param string|null $name The transaction name
|
|
* @return void
|
|
*/
|
|
public function __construct($op=null, $name=null) {
|
|
// Setup context for the full transaction
|
|
$this->context = new \Sentry\Tracing\TransactionContext();
|
|
$this->context->setName(
|
|
$name?$name:
|
|
(php_sapi_name()=='cli'?'CLI execution':'HTTP request')
|
|
);
|
|
$this->context->setOp(
|
|
$op?$op:
|
|
(php_sapi_name()=='cli'?'cli.command':'http.request')
|
|
);
|
|
|
|
// Start the transaction
|
|
$this->transaction = \Sentry\startTransaction($this->context);
|
|
|
|
// Set the current transaction as the current span so we can retrieve it later
|
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this->transaction);
|
|
}
|
|
|
|
/**
|
|
* Destructor: Stop the current Sentry transaction
|
|
* @return void
|
|
*/
|
|
public function __destruct() {
|
|
SentrySpan :: finishAll();
|
|
$this->transaction->finish();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal Sentry Span object implementation
|
|
* This internal implementation principally permit to keep trace of new span parent
|
|
* and list of started spans.
|
|
*/
|
|
class SentrySpan {
|
|
|
|
/**
|
|
* Keep trace of started Sentry spans
|
|
* @var array<int,mixed>
|
|
*/
|
|
private static $_started_spans = array();
|
|
|
|
/**
|
|
* The unique ID of the Sentry span
|
|
* Note: internal ID used as key in self::$_started_spans
|
|
* @var int|null
|
|
*/
|
|
private $id = null;
|
|
|
|
/**
|
|
* The parent of the Sentry span
|
|
* @var mixed
|
|
*/
|
|
private $parent = null;
|
|
|
|
/**
|
|
* The context of the Sentry span
|
|
* @var null|\Sentry\Tracing\SpanContext
|
|
*/
|
|
private $context = null;
|
|
|
|
/**
|
|
* The Sentry span object
|
|
* @var mixed
|
|
*/
|
|
private $span = null;
|
|
|
|
/**
|
|
* Sentry span constructor
|
|
* @param string|null $op The operation name
|
|
* @param string|null $name The span name
|
|
* @return void
|
|
*/
|
|
public function __construct($op, $name) {
|
|
$this -> parent = \Sentry\SentrySdk::getCurrentHub()->getSpan();
|
|
// Check if we have a parent span (this is the case if we started a transaction earlier)
|
|
if (is_null($this -> parent)) return;
|
|
|
|
while (is_null($this -> id)) {
|
|
$this -> id = rand();
|
|
if (isset(self :: $_started_spans[$this -> id]))
|
|
$this -> id = null;
|
|
}
|
|
$this -> context = new \Sentry\Tracing\SpanContext();
|
|
$this -> context->setOp($op);
|
|
$this -> context->setDescription($name);
|
|
$this -> span = $this->parent->startChild($this -> context);
|
|
|
|
// Set the current span to the span we just started
|
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> span);
|
|
|
|
self :: $_started_spans[$this -> id] = $this;
|
|
}
|
|
|
|
/**
|
|
* Finish the span (if started)
|
|
* @return void
|
|
*/
|
|
public function finish() {
|
|
if (!$this -> span) return;
|
|
$this -> span -> finish();
|
|
unset(self::$_started_spans[$this -> id]);
|
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> parent);
|
|
}
|
|
|
|
/**
|
|
* Finish all started spans
|
|
* @see SentryTransaction::__destruct()
|
|
* @return void
|
|
*/
|
|
public static function finishAll() {
|
|
foreach (array_reverse(self :: $_started_spans) as $id => $span)
|
|
$span -> finish();
|
|
}
|
|
}
|
|
|
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|