118 lines
3.4 KiB
PHP
118 lines
3.4 KiB
PHP
|
|
<?php
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
class TaskCertLogger
|
||
|
|
{
|
||
|
|
private static ?string $logFile = null;
|
||
|
|
|
||
|
|
public static function debug(string $message, array $context = []): void
|
||
|
|
{
|
||
|
|
self::write('DEBUG', $message, $context);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function info(string $message, array $context = []): void
|
||
|
|
{
|
||
|
|
self::write('INFO', $message, $context);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function warning(string $message, array $context = []): void
|
||
|
|
{
|
||
|
|
self::write('WARNING', $message, $context);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function error(string $message, array $context = []): void
|
||
|
|
{
|
||
|
|
self::write('ERROR', $message, $context);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function write(string $level, string $message, array $context = []): void
|
||
|
|
{
|
||
|
|
$line = self::formatLine($level, $message, $context);
|
||
|
|
$logFile = self::resolveLogFile();
|
||
|
|
$logDir = dirname($logFile);
|
||
|
|
|
||
|
|
if (!is_dir($logDir)) {
|
||
|
|
@mkdir($logDir, 0775, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (@file_put_contents($logFile, $line, FILE_APPEND | LOCK_EX) === false) {
|
||
|
|
error_log(trim($line));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function resolveLogFile(): string
|
||
|
|
{
|
||
|
|
if (self::$logFile !== null) {
|
||
|
|
return self::$logFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
$configured = trim((string) (getenv('TASK_CERT_LOG_FILE') ?: ($_ENV['TASK_CERT_LOG_FILE'] ?? '')));
|
||
|
|
if ($configured === '') {
|
||
|
|
self::$logFile = dirname(__DIR__) . '/logs/task_cert.log';
|
||
|
|
return self::$logFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($configured[0] === '/') {
|
||
|
|
self::$logFile = $configured;
|
||
|
|
return self::$logFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
self::$logFile = dirname(__DIR__) . '/' . ltrim($configured, '/');
|
||
|
|
return self::$logFile;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function formatLine(string $level, string $message, array $context): string
|
||
|
|
{
|
||
|
|
$timestamp = date('Y-m-d H:i:s');
|
||
|
|
$normalizedContext = self::normalizeContext($context);
|
||
|
|
|
||
|
|
if ($normalizedContext !== []) {
|
||
|
|
$contextJson = json_encode($normalizedContext, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
|
|
if ($contextJson !== false) {
|
||
|
|
return sprintf("[%s] task_cert.%s %s | %s\n", $timestamp, strtoupper($level), $message, $contextJson);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return sprintf("[%s] task_cert.%s %s\n", $timestamp, strtoupper($level), $message);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function normalizeContext(array $context): array
|
||
|
|
{
|
||
|
|
$normalized = [];
|
||
|
|
foreach ($context as $key => $value) {
|
||
|
|
$stringKey = (string) $key;
|
||
|
|
|
||
|
|
if (is_scalar($value) || $value === null) {
|
||
|
|
$normalized[$stringKey] = $value;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($value instanceof Throwable) {
|
||
|
|
$normalized[$stringKey] = [
|
||
|
|
'class' => get_class($value),
|
||
|
|
'message' => $value->getMessage(),
|
||
|
|
'file' => $value->getFile(),
|
||
|
|
'line' => $value->getLine(),
|
||
|
|
];
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_array($value)) {
|
||
|
|
$normalized[$stringKey] = $value;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is_object($value)) {
|
||
|
|
$normalized[$stringKey] = [
|
||
|
|
'class' => get_class($value),
|
||
|
|
];
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$normalized[$stringKey] = gettype($value);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $normalized;
|
||
|
|
}
|
||
|
|
}
|