123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <?php
- /*
- * Part of Shuzanne - An extensible sequel to an open-source imageboard.
- *
- * @package Shuzanne
- * @author MisleadingName, Shuzanne Contributors
- * @license MPL v2.0
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
- namespace app;
- class Logger
- {
- private const LOG_FILE = "rajesh.log";
- private const DEFAULT_MAX_SIZE_KB = 5000; // 5MB default max size
- private static ?string $logPath = null;
- private static LogLevel $minLevel = LogLevel::DBUG;
- private static int $maxSizeKB = self::DEFAULT_MAX_SIZE_KB;
- /**
- * Initialize the logger
- */
- public static function Initialize(): void
- {
- self::$logPath = APP_ROOT . "/logs/" . self::LOG_FILE;
- register_shutdown_function(function () {
- $error = error_get_last();
- if ($error && in_array($error["type"], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
- self::Fatal("PHP Fatal Error: {$error["message"]} in {$error["file"]} on line {$error["line"]}");
- }
- });
- // Register hook for plugin access
- // Hooks::Register("Shuzanne.LoggerWrite", function ($data) {
- // self::Write($data["level"], $data["message"], $data["context"] ?? []);
- // return $data;
- // });
- self::Info("Logger initialized. Log file: " . self::$logPath);
- }
- /**
- * Set minimum log level
- */
- public static function SetMinLevel(LogLevel $level): void
- {
- self::$minLevel = $level;
- }
- /**
- * Set maximum log file size in kilobytes before rotation
- */
- public static function SetMaxLogSizeKB(int $sizeKB): void
- {
- self::$maxSizeKB = max(1, $sizeKB); // Ensure at least 1KB
- self::CheckRotation();
- }
- /**
- * Write a message to the log file
- */
- public static function Write(LogLevel $level, string $message, array $context = [], string $file = "Unknown", int $line = 0): void
- {
- if ($level->value < self::$minLevel->value) {
- return;
- }
- if (self::$logPath === null) {
- self::Initialize();
- }
- self::CheckRotation();
- foreach ($context as $key => $value) {
- if (is_array($value) || is_object($value)) {
- $value = json_encode($value);
- }
- $message = str_replace("{{$key}}", $value, $message);
- }
- $timestamp = date("Y-m-d H:i:s");
- $levelName = $level->name;
- $file = basename($file);
- $formattedMessage = "[$timestamp] <$file:$line> [$levelName] $message" . PHP_EOL;
- file_put_contents(self::$logPath, $formattedMessage, FILE_APPEND);
- }
- /**
- * Check if log rotation is needed and rotate if necessary
- */
- private static function CheckRotation(): void
- {
- if (!file_exists(self::$logPath)) {
- return;
- }
- $sizeKB = filesize(self::$logPath) / 1024;
- if ($sizeKB >= self::$maxSizeKB) {
- self::RotateLog();
- }
- }
- /**
- * Rotate the log file
- */
- public static function RotateLog(): bool
- {
- if (!file_exists(self::$logPath)) {
- return false;
- }
- $timestamp = date("Y-m-d_H-i-s");
- $rotatedFileName = "old_logs_{$timestamp}.log.gz";
- $rotatedFilePath = dirname(self::$logPath) . DIRECTORY_SEPARATOR . $rotatedFileName;
- $logContent = file_get_contents(self::$logPath);
- $compressedContent = gzencode($logContent, 9);
- if (file_put_contents($rotatedFilePath, $compressedContent) === false) {
- self::Error("Failed to create rotated log file: {$rotatedFilePath}");
- return false;
- }
- if (file_put_contents(self::$logPath, "") === false) {
- self::Error("Failed to clear log file after rotation");
- return false;
- }
- self::Info("Old log rotated to {$rotatedFileName}");
- return true;
- }
- /**
- * Debug level message
- */
- public static function Debug(string $message, array $context = []): void
- {
- $key = array_search(__FUNCTION__, array_column(debug_backtrace(), "function"));
- $file = debug_backtrace()[$key]["file"];
- $line = debug_backtrace()[$key]["line"];
- self::Write(LogLevel::DBUG, $message, $context, $file, $line);
- }
- /**
- * Info level message
- */
- public static function Info(string $message, array $context = []): void
- {
- $key = array_search(__FUNCTION__, array_column(debug_backtrace(), "function"));
- $file = debug_backtrace()[$key]["file"];
- $line = debug_backtrace()[$key]["line"];
- self::Write(LogLevel::INFO, $message, $context, $file, $line);
- }
- /**
- * Warning level message
- */
- public static function Warn(string $message, array $context = []): void
- {
- $key = array_search(__FUNCTION__, array_column(debug_backtrace(), "function"));
- $file = debug_backtrace()[$key]["file"];
- $line = debug_backtrace()[$key]["line"];
- self::Write(LogLevel::WARN, $message, $context, $file, $line);
- }
- /**
- * Error level message
- */
- public static function Error(string $message, array $context = []): void
- {
- $key = array_search(__FUNCTION__, array_column(debug_backtrace(), "function"));
- $file = debug_backtrace()[$key]["file"];
- $line = debug_backtrace()[$key]["line"];
- self::Write(LogLevel::EROR, $message, $context, $file, $line);
- }
- /**
- * Fatal level message
- */
- public static function Fatal(string $message, array $context = []): void
- {
- $key = array_search(__FUNCTION__, array_column(debug_backtrace(), "function"));
- $file = debug_backtrace()[$key]["file"];
- $line = debug_backtrace()[$key]["line"];
- self::Write(LogLevel::FTAL, $message, $context, $file, $line);
- }
- /**
- * Get the log file path
- */
- public static function GetLogPath(): string
- {
- if (self::$logPath === null) {
- self::Initialize();
- }
- return self::$logPath;
- }
- /**
- * Clear the log file
- */
- public static function Clear(): bool
- {
- if (self::$logPath === null) {
- self::Initialize();
- }
- return file_put_contents(self::$logPath, "") !== false;
- }
- }
- enum LogLevel: int
- {
- case DBUG = 0;
- case INFO = 1;
- case WARN = 2;
- case EROR = 3;
- case FTAL = 4;
- public static function tryFromName(string $name): ?LogLevel
- {
- return array_find(self::cases(), fn($case) => $case->name === $name);
- }
- }
|