Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,286 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
use DateTime;
use Throwable;
use Xentral\Components\Http\Request;
use Xentral\Components\Logger\LoggerInterface;
use Xentral\Components\Util\StringUtil;
final class ContextHelper
{
/** @var Request $request */
private $request;
/**
* @param Request $request
*/
public function __construct(
Request $request
) {
$this->request = $request;
}
/**
* @param array $contextArray
*
* @return ContextInterface
*/
public function createContext(array $contextArray): ContextInterface
{
//time context
$time = new DateTime('now');
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
//calling code line
$invocation = $this->findInvocation($backtrace);
//origin of the call
$instigation = $this->createOrigin($backtrace);
//possible exception
$exceptionEntry = null;
if (array_key_exists('exception', $contextArray)) {
$exceptionEntry = $contextArray['exception'];
unset($contextArray['exception']);
}
$exception = null;
if (is_subclass_of($exceptionEntry, Throwable::class)) {
$exception = $exceptionEntry;
}
//possible dump
if (count($contextArray) === 0) {
$dump = null;
} else {
$dump = $contextArray;
}
return new LoggerContext(
$time,
$invocation,
$instigation,
$exception,
$dump
);
}
/**
* @param string $message
* @param array $context
*
* @return string
*/
public function interpolateMessage(string $message, array &$context): string
{
$keys = array_keys($context);
$interpolated = $message;
foreach ($keys as $key) {
if ($key === 'exception') {
continue;
}
if (!preg_match('/^\w+$/', (string)$key)) {
continue;
}
if (preg_match(sprintf('/\{%s\}/', $key), $interpolated)) {
$pattern = sprintf('{%s}', $key);
try {
$interpolated = str_replace($pattern, (string)$context[$key], $interpolated);
} catch (Throwable $e) {
continue;
}
unset($context[$key]);
}
}
return $interpolated;
}
/**
* @param array $backtrace
*
* @return Invocation
*/
public function findInvocation(array $backtrace): Invocation
{
$lastLine = 0;
$lastFile = '';
foreach ($backtrace as $trace) {
if (isset($trace['class'])) {
$class = $trace['class'];
if (
$class !== self::class
&& !in_array(LoggerInterface::class, class_implements($class), true)
) {
return new Invocation(
$trace['class'],
$trace['function'],
$lastLine,
$lastFile
);
}
if (array_key_exists('line', $trace)) {
$lastLine = $trace['line'];
$lastFile = $trace['file'];
}
}
}
return new Invocation('unknown', 'unknown', 0, 'unknown');
}
/**
* @param array $backtrace
*
* @return OriginInterface
*/
public function createOrigin(array $backtrace): OriginInterface
{
try {
$instigation = $this->tryCreateFrontendOrigin();
if ($instigation !== null) {
return $instigation;
}
$instigation = $this->tryCreateSchedulerJobOrigin($backtrace);
if ($instigation !== null) {
return $instigation;
}
$instigation = $this->tryCreateRestApiOrigin();
if ($instigation !== null) {
return $instigation;
}
$instigation = $this->tryCreateLegacyApiOrigin();
if ($instigation !== null) {
return $instigation;
}
$instigation = $this->tryCreateCliOrigin();
if ($instigation !== null) {
return $instigation;
}
} catch (Throwable $e) {
}
return new Origin(OriginInterface::TYPE_UNKNOWN, 'unknown');
}
/**
* @return OriginInterface|null
*/
private function tryCreateFrontendOrigin(): ?OriginInterface
{
$module = $this->request->get->get('module', null);
if ($this->request === null || $module === null || $module === 'api') {
return null;
}
$action = $this->request->get->get('action', null);
$cmd = $this->request->get->get('cmd', null);
$payload = [strtoupper($this->request->getMethod())];
if ($module !== null) {
$payload[] = sprintf('module=%s', $module);
}
if ($action !== null) {
$payload[] = sprintf('action=%s', $action);
}
if ($cmd !== null) {
$payload[] = sprintf('cmd=%s', $cmd);
}
return new Origin(OriginInterface::TYPE_FRONTEND, implode(' ', $payload));
}
/**
* @return OriginInterface|null
*/
private function tryCreateLegacyApiOrigin(): ?OriginInterface
{
if ($this->request->get->get('module', '') === 'api') {
return new Origin(
OriginInterface::TYPE_LEGACY_API,
sprintf(
'%s action=%s',
$this->request->getMethod(),
$this->request->get->get('action', '')
)
);
}
return null;
}
/**
* @return OriginInterface|null
*/
private function tryCreateRestApiOrigin(): ?OriginInterface
{
$url = $this->request->getFullUrl();
$match = preg_match('/api\/(v\d.?\/[^?]+)\??/', $url, $matches);
if ($match && count($matches) > 1) {
return new Origin(
OriginInterface::TYPE_REST_API,
sprintf(
'%s endpoint=%s',
$this->request->getMethod(),
$matches[1]
)
);
}
$path = $this->request->get->get('path', '');
if (preg_match('/(v\d.?\/[^?]+)/', $path)
&& preg_match('/api\/index.php\?/', $url)
) {
return new Origin(
OriginInterface::TYPE_REST_API,
sprintf(
'%s path=%s',
$this->request->getMethod(),
$path
)
);
}
return null;
}
/**
* @param array $backtrace
*
* @return OriginInterface|null
*/
private function tryCreateSchedulerJobOrigin(array $backtrace): ?OriginInterface
{
if (count($backtrace) === 0) {
return null;
}
$trace = $backtrace[count($backtrace) - 1];
$file = $trace['file'] ?? '';
if (!StringUtil::endsWith($file, '/cronjobs/command.php')) {
return null;
}
$jobFile = $trace['args'][0] ?? '';
$payload = $jobFile;
$matchresult = [];
preg_match('/^.+\/cronjobs\/(.+)$/', $jobFile, $matchresult);
if (count($matchresult) > 1) {
$payload = sprintf('job=%s', $matchresult[1]);
}
return new Origin(OriginInterface::TYPE_SCHEDULER_JOB, $payload);
}
/**
* @return OriginInterface|null
*/
private function tryCreateCliOrigin(): ?OriginInterface
{
if ($this->request->server->getInt('argc', 0) < 1) {
return null;
}
$file = $this->request->server->get('argv', [''])[0];
$payload = sprintf('script=%s', $file);
return new Origin(OriginInterface::TYPE_CLI, $payload);
}
}
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
use DateTimeInterface;
use Throwable;
interface ContextInterface
{
public function getTime(): DateTimeInterface;
public function getClass(): ?string;
public function getFunction(): ?string;
public function getLine(): int;
public function hasOrigin(): bool;
public function getOriginType(): ?string;
public function getOriginDetail(): ?string;
public function hasException(): bool;
public function getException(): ?Throwable;
public function hasDump(): bool;
public function getDump(): array;
}
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
final class Invocation
{
/** @var string $class */
private $class;
/** @var string $function */
private $function;
/** @var int $line */
private $line;
/** @var string $file */
private $file;
/**
* @param string $file
* @param string $function
* @param int $line
* @param string $class
*/
public function __construct(string $class, string $function, int $line, string $file)
{
$this->class = $class;
$this->function = $function;
$this->line = $line;
$this->file = $file;
}
/**
* @return string
*/
public function getClass(): string
{
return $this->class;
}
/**
* @return string
*/
public function getFunction(): string
{
return $this->function;
}
/**
* @return int
*/
public function getLine(): int
{
return $this->line;
}
/**
* @return string
*/
public function getFile(): string
{
return $this->file;
}
}
@@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
use DateTimeInterface;
use Exception;
use Throwable;
final class LoggerContext implements ContextInterface
{
/** @var DateTimeInterface $dateTime */
private $dateTime;
/** @var Invocation $invocation */
private $invocation;
/** @var OriginInterface $origin */
private $origin;
/** @var Exception $exception */
private $exception;
/** @var array $dump */
private $dump;
/**
* @param DateTimeInterface $dateTime
* @param Invocation|null $invocation
* @param OriginInterface|null $origin
* @param Throwable|null $exception
* @param array|null $dump
*/
public function __construct(
DateTimeInterface $dateTime,
Invocation $invocation = null,
OriginInterface $origin = null,
Throwable $exception = null,
array $dump = null
) {
$this->dateTime = $dateTime;
$this->invocation = $invocation;
$this->origin = $origin;
$this->exception = $exception;
$this->dump = $dump;
}
/**
* @return DateTimeInterface
*/
public function getTime(): DateTimeInterface
{
return $this->dateTime;
}
/**
* @return string|null
*/
public function getClass(): ?string
{
if ($this->invocation === null) {
return null;
}
return $this->invocation->getClass();
}
/**
* @return string|null
*/
public function getFunction(): ?string
{
if ($this->invocation === null) {
return null;
}
return $this->invocation->getFunction();
}
/**
* @return int
*/
public function getLine(): int
{
if ($this->invocation === null) {
return 0;
}
return $this->invocation->getLine();
}
/**
* @return bool
*/
public function hasOrigin(): bool
{
return $this->origin !== null;
}
/**
* @return bool
*/
public function hasException(): bool
{
return $this->exception !== null;
}
/**
* @return Exception|null
*/
public function getException(): ?Throwable
{
return $this->exception;
}
/**
* @return bool
*/
public function hasDump(): bool
{
return is_array($this->dump) && count($this->dump) > 0;
}
/**
* @return array
*/
public function getDump(): array
{
if (!is_array($this->dump)) {
return [];
}
return $this->dump;
}
/**
* @return string|null
*/
public function getOriginType(): ?string
{
if ($this->origin === null) {
return null;
}
return $this->origin->getType();
}
/**
* @return string|null
*/
public function getOriginDetail(): ?string
{
if ($this->origin === null) {
return null;
}
return $this->origin->getDetail();
}
}
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
final class Origin implements OriginInterface
{
/** @var string $type */
private $type;
/** @var string $payload */
private $payload;
/**
* @param string $type
* @param string $payload
*/
public function __construct(string $type, string $payload)
{
$this->type = $type;
$this->payload = $payload;
}
/**
* @inheritDoc
*/
public function getType(): string
{
return $this->type;
}
/**
* @inheritDoc
*/
public function getDetail(): string
{
return $this->payload;
}
}
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Xentral\Components\Logger\Context;
interface OriginInterface
{
/** @var string FRONTEND */
public const TYPE_FRONTEND = 'frontend_request';
/** @var string LEGACY_API */
public const TYPE_LEGACY_API = 'legacy_api';
/** @var string TYPE_REST_API */
public const TYPE_REST_API = 'rest_api';
/** @var string TYPE_CALDAV */
public const TYPE_CALDAV = 'caldav_request';
/** @var string TYPE_WEBDAV */
public const TYPE_WEBDAV = 'webdav_request';
/** @var string TYPE_DEVICE */
public const TYPE_DEVICE = 'device_request';
/** @var string TYPE_SCHEDULER_JOB */
public const TYPE_SCHEDULER_JOB = 'scheduler_job';
/** @var string TYPE_CLI */
public const TYPE_CLI = 'cli_command';
/** @var string TYPE_UNKNOWN */
public const TYPE_UNKNOWN = 'unknown';
/**
* Gets the origin type.
*
* @return string
*/
public function getType(): string;
/**
* Gets the origin payload.
*
* e.g. web request GET params, cronjob name, REST-API endpoint etc...
*
* @return string
*/
public function getDetail(): string;
}