PocketMine-MP 5.15.1 git-5ef247620a7c6301a849b54e5ef1009217729fc8
MainLogger.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\utils;
25
26use pmmp\thread\Thread as NativeThread;
31use function implode;
32use function sprintf;
33use const PHP_EOL;
34
36 protected bool $logDebug;
37
38 private string $format = TextFormat::AQUA . "[%s] " . TextFormat::RESET . "%s[%s/%s]: %s" . TextFormat::RESET;
39 private bool $useFormattingCodes = false;
40 private string $mainThreadName;
41 private string $timezone;
42 private ?MainLoggerThread $logWriterThread = null;
43
47 public function __construct(?string $logFile, bool $useFormattingCodes, string $mainThreadName, \DateTimeZone $timezone, bool $logDebug = false, ?string $logArchiveDir = null){
48 parent::__construct();
49 $this->logDebug = $logDebug;
50
51 $this->useFormattingCodes = $useFormattingCodes;
52 $this->mainThreadName = $mainThreadName;
53 $this->timezone = $timezone->getName();
54
55 if($logFile !== null){
56 $this->logWriterThread = new MainLoggerThread($logFile, $logArchiveDir);
57 $this->logWriterThread->start(NativeThread::INHERIT_NONE);
58 }
59 }
60
64 public function getFormat() : string{
65 return $this->format;
66 }
67
79 public function setFormat(string $format) : void{
80 $this->format = $format;
81 }
82
83 public function emergency($message){
84 $this->send($message, \LogLevel::EMERGENCY, "EMERGENCY", TextFormat::RED);
85 }
86
87 public function alert($message){
88 $this->send($message, \LogLevel::ALERT, "ALERT", TextFormat::RED);
89 }
90
91 public function critical($message){
92 $this->send($message, \LogLevel::CRITICAL, "CRITICAL", TextFormat::RED);
93 }
94
95 public function error($message){
96 $this->send($message, \LogLevel::ERROR, "ERROR", TextFormat::DARK_RED);
97 }
98
99 public function warning($message){
100 $this->send($message, \LogLevel::WARNING, "WARNING", TextFormat::YELLOW);
101 }
102
103 public function notice($message){
104 $this->send($message, \LogLevel::NOTICE, "NOTICE", TextFormat::AQUA);
105 }
106
107 public function info($message){
108 $this->send($message, \LogLevel::INFO, "INFO", TextFormat::WHITE);
109 }
110
111 public function debug($message, bool $force = false){
112 if(!$this->logDebug && !$force){
113 return;
114 }
115 $this->send($message, \LogLevel::DEBUG, "DEBUG", TextFormat::GRAY);
116 }
117
118 public function setLogDebug(bool $logDebug) : void{
119 $this->logDebug = $logDebug;
120 }
121
128 public function logException(\Throwable $e, $trace = null){
129 $this->critical(implode("\n", Utils::printableExceptionInfo($e, $trace)));
130
131 $this->syncFlushBuffer();
132 }
133
134 public function log($level, $message){
135 switch($level){
136 case \LogLevel::EMERGENCY:
137 $this->emergency($message);
138 break;
139 case \LogLevel::ALERT:
140 $this->alert($message);
141 break;
142 case \LogLevel::CRITICAL:
143 $this->critical($message);
144 break;
145 case \LogLevel::ERROR:
146 $this->error($message);
147 break;
148 case \LogLevel::WARNING:
149 $this->warning($message);
150 break;
151 case \LogLevel::NOTICE:
152 $this->notice($message);
153 break;
154 case \LogLevel::INFO:
155 $this->info($message);
156 break;
157 case \LogLevel::DEBUG:
158 $this->debug($message);
159 break;
160 }
161 }
162
166 public function buffer(\Closure $c) : void{
167 $this->synchronized($c);
168 }
169
170 public function shutdownLogWriterThread() : void{
171 if($this->logWriterThread !== null){
172 if(NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){
173 $this->logWriterThread->shutdown();
174 }else{
175 throw new \LogicException("Only the creator thread can shutdown the logger thread");
176 }
177 }
178 }
179
180 protected function send(string $message, string $level, string $prefix, string $color) : void{
181 $time = new \DateTime('now', new \DateTimeZone($this->timezone));
182
183 $thread = NativeThread::getCurrentThread();
184 if($thread === null){
185 $threadName = $this->mainThreadName . " thread";
186 }elseif($thread instanceof Thread || $thread instanceof Worker){
187 $threadName = $thread->getThreadName() . " thread";
188 }else{
189 $threadName = (new \ReflectionClass($thread))->getShortName() . " thread";
190 }
191
192 $message = sprintf($this->format, $time->format("H:i:s.v"), $color, $threadName, $prefix, TextFormat::addBase($color, TextFormat::clean($message, false)));
193
194 if(!Terminal::isInit()){
195 Terminal::init($this->useFormattingCodes); //lazy-init colour codes because we don't know if they've been registered on this thread
196 }
197
198 $this->synchronized(function() use ($message, $level, $time) : void{
199 Terminal::writeLine($message);
200 if($this->logWriterThread !== null){
201 $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL);
202 }
203
207 foreach($this->attachments as $attachment){
208 $attachment->log($level, $message);
209 }
210 });
211 }
212
213 public function syncFlushBuffer() : void{
214 $this->logWriterThread?->syncFlushBuffer();
215 }
216
217 public function __destruct(){
218 if($this->logWriterThread !== null && !$this->logWriterThread->isJoined() && NativeThread::getCurrentThreadId() === $this->logWriterThread->getCreatorId()){
219 $this->shutdownLogWriterThread();
220 }
221 }
222}
log($level, $message)
Definition: MainLogger.php:134
setFormat(string $format)
Definition: MainLogger.php:79
__construct(?string $logFile, bool $useFormattingCodes, string $mainThreadName, \DateTimeZone $timezone, bool $logDebug=false, ?string $logArchiveDir=null)
Definition: MainLogger.php:47
logException(\Throwable $e, $trace=null)
Definition: MainLogger.php:128