@@ -33,6 +33,15 @@ class Logger implements ILogger
3333 /** @var BlueScreen|null */
3434 private $ blueScreen ;
3535
36+ /** @var StreamLogger[] */
37+ private $ streamLoggers ;
38+
39+ /** @var BlueScreenLogger */
40+ private $ blueScreenLogger ;
41+
42+ /** @var MailLogger */
43+ private $ mailLogger ;
44+
3645
3746 /**
3847 * @param string|array|null $email
@@ -43,6 +52,9 @@ public function __construct(?string $directory, $email = null, BlueScreen $blueS
4352 $ this ->email = $ email ;
4453 $ this ->blueScreen = $ blueScreen ;
4554 $ this ->mailer = [$ this , 'defaultMailer ' ];
55+
56+ $ this ->blueScreenLogger = $ this ->createBlueScreenLogger ();
57+ $ this ->mailLogger = $ this ->createMailLogger ();
4658 }
4759
4860
@@ -53,32 +65,49 @@ public function __construct(?string $directory, $email = null, BlueScreen $blueS
5365 * @return string|null logged error filename
5466 */
5567 public function log ($ message , string $ priority = self ::INFO ): ?string
68+ {
69+ $ exceptionFile = $ this ->getStreamLogger ($ priority )->log ($ message , $ priority );
70+ $ this ->mailLogger ->log ($ message , $ priority );
71+ return $ exceptionFile ;
72+ }
73+
74+
75+ protected function getStreamLogger ($ priority )
5676 {
5777 if (!$ this ->directory ) {
5878 throw new \LogicException ('Logging directory is not specified. ' );
5979 } elseif (!is_dir ($ this ->directory )) {
6080 throw new \RuntimeException ("Logging directory ' $ this ->directory ' is not found or is not directory. " );
6181 }
6282
63- $ exceptionFile = $ message instanceof \Throwable
64- ? $ this ->getExceptionFile ($ message )
65- : null ;
66- $ line = static ::formatLogLine ($ message , $ exceptionFile );
67- $ file = $ this ->directory . '/ ' . strtolower ($ priority ?: self ::INFO ) . '.log ' ;
68-
69- if (!@file_put_contents ($ file , $ line . PHP_EOL , FILE_APPEND | LOCK_EX )) { // @ is escalated to exception
70- throw new \RuntimeException ("Unable to write to log file ' $ file'. Is directory writable? " );
83+ $ path = $ this ->directory . '/ ' . strtolower ($ priority ?: self ::INFO ) . '.log ' ;
84+ if (!isset ($ this ->streamLoggers [$ path ])) {
85+ $ this ->streamLoggers [$ path ] = new StreamLogger ($ path , $ this ->blueScreenLogger );
7186 }
7287
73- if ($ exceptionFile ) {
74- $ this ->logException ($ message , $ exceptionFile );
75- }
88+ return $ this ->streamLoggers [$ path ];
89+ }
7690
77- if (in_array ($ priority , [self ::ERROR , self ::EXCEPTION , self ::CRITICAL ], true )) {
78- $ this ->sendEmail ($ message );
79- }
8091
81- return $ exceptionFile ;
92+ protected function createBlueScreenLogger ()
93+ {
94+ $ blueScreenLogger = new BlueScreenLogger ($ this ->directory , $ this ->blueScreen );
95+ $ blueScreenLogger ->directory = &$ this ->directory ;
96+
97+ return $ blueScreenLogger ;
98+ }
99+
100+
101+ protected function createMailLogger ()
102+ {
103+ $ mailLogger = new MailLogger ($ this ->directory , $ this ->email );
104+ $ mailLogger ->directory = &$ this ->directory ;
105+ $ mailLogger ->email = &$ this ->email ;
106+ $ mailLogger ->fromEmail = &$ this ->fromEmail ;
107+ $ mailLogger ->emailSnooze = &$ this ->emailSnooze ;
108+ $ mailLogger ->mailer = &$ this ->mailer ;
109+
110+ return $ mailLogger ;
82111 }
83112
84113
@@ -119,82 +148,43 @@ public static function formatLogLine($message, string $exceptionFile = null): st
119148 }
120149
121150
151+ /**
152+ * @deprecated
153+ */
122154 public function getExceptionFile (\Throwable $ exception ): string
123155 {
124- while ($ exception ) {
125- $ data [] = [
126- get_class ($ exception ), $ exception ->getMessage (), $ exception ->getCode (), $ exception ->getFile (), $ exception ->getLine (),
127- array_map (function ($ item ) { unset($ item ['args ' ]); return $ item ; }, $ exception ->getTrace ()),
128- ];
129- $ exception = $ exception ->getPrevious ();
130- }
131- $ hash = substr (md5 (serialize ($ data )), 0 , 10 );
132- $ dir = strtr ($ this ->directory . '/ ' , '\\/ ' , DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
133- foreach (new \DirectoryIterator ($ this ->directory ) as $ file ) {
134- if (strpos ($ file ->getBasename (), $ hash )) {
135- return $ dir . $ file ;
136- }
137- }
138- return $ dir . 'exception-- ' . @date ('Y-m-d--H-i ' ) . "-- $ hash.html " ; // @ timezone may not be set
156+ return $ this ->blueScreenLogger ->getExceptionFile ($ exception );
139157 }
140158
141159
142160 /**
143- * Logs exception to the file if file doesn't exist.
144- * @return string logged error filename
161+ * @deprecated
145162 */
146- protected function logException (\Throwable $ exception , string $ file = null ): string
163+ protected function logException (\Throwable $ exception , ? string $ file = null ): string
147164 {
148- $ file = $ file ?: $ this ->getExceptionFile ($ exception );
149- $ bs = $ this ->blueScreen ?: new BlueScreen ;
150- $ bs ->renderToFile ($ exception , $ file );
151- return $ file ;
165+ $ reflection = new \ReflectionMethod ($ this ->blueScreenLogger , 'logException ' );
166+ $ reflection ->setAccessible (true );
167+ return $ reflection ->invoke ($ this ->blueScreenLogger , $ exception , $ file );
152168 }
153169
154170
155171 /**
156- * @param mixed $message
172+ * @deprecated
157173 */
158174 protected function sendEmail ($ message ): void
159175 {
160- $ snooze = is_numeric ($ this ->emailSnooze )
161- ? $ this ->emailSnooze
162- : @strtotime ($ this ->emailSnooze ) - time (); // @ timezone may not be set
163-
164- if (
165- $ this ->email
166- && $ this ->mailer
167- && @filemtime ($ this ->directory . '/email-sent ' ) + $ snooze < time () // @ file may not exist
168- && @file_put_contents ($ this ->directory . '/email-sent ' , 'sent ' ) // @ file may not be writable
169- ) {
170- ($ this ->mailer )($ message , implode (', ' , (array ) $ this ->email ));
171- }
176+ $ reflection = new \ReflectionMethod ($ this ->mailLogger , 'sendEmail ' );
177+ $ reflection ->setAccessible (true );
178+ $ reflection ->invoke ($ this ->mailLogger , $ message );
172179 }
173180
174181
175182 /**
176- * Default mailer.
177- * @param mixed $message
183+ * @deprecated
178184 * @internal
179185 */
180186 public function defaultMailer ($ message , string $ email ): void
181187 {
182- $ host = preg_replace ('#[^\w.-]+# ' , '' , $ _SERVER ['HTTP_HOST ' ] ?? php_uname ('n ' ));
183- $ parts = str_replace (
184- ["\r\n" , "\n" ],
185- ["\n" , PHP_EOL ],
186- [
187- 'headers ' => implode ("\n" , [
188- 'From: ' . ($ this ->fromEmail ?: "noreply@ $ host " ),
189- 'X-Mailer: Tracy ' ,
190- 'Content-Type: text/plain; charset=UTF-8 ' ,
191- 'Content-Transfer-Encoding: 8bit ' ,
192- ]) . "\n" ,
193- 'subject ' => "PHP: An error occurred on the server $ host " ,
194- 'body ' => static ::formatMessage ($ message ) . "\n\nsource: " . Helpers::getSource (),
195- ]
196- );
197-
198- mail ($ email , $ parts ['subject ' ], $ parts ['body ' ], $ parts ['headers ' ]);
188+ $ this ->mailLogger ->defaultMailer ($ message , $ email );
199189 }
200190}
0 commit comments