@@ -31,13 +31,25 @@ class Logger implements ILogger
3131 /** @var BlueScreen */
3232 private $ blueScreen ;
3333
34+ /** @var StreamLogger[] */
35+ private $ streamLoggers ;
36+
37+ /** @var BlueScreenLogger */
38+ private $ blueScreenLogger ;
39+
40+ /** @var MailLogger */
41+ private $ mailLogger ;
42+
3443
3544 public function __construct ($ directory , $ email = null , BlueScreen $ blueScreen = null )
3645 {
3746 $ this ->directory = $ directory ;
3847 $ this ->email = $ email ;
3948 $ this ->blueScreen = $ blueScreen ;
4049 $ this ->mailer = [$ this , 'defaultMailer ' ];
50+
51+ $ this ->blueScreenLogger = $ this ->createBlueScreenLogger ();
52+ $ this ->mailLogger = $ this ->createMailLogger ();
4153 }
4254
4355
@@ -48,32 +60,49 @@ public function __construct($directory, $email = null, BlueScreen $blueScreen =
4860 * @return string logged error filename
4961 */
5062 public function log ($ message , $ priority = self ::INFO )
63+ {
64+ $ exceptionFile = $ this ->getStreamLogger ($ priority )->log ($ message , $ priority );
65+ $ this ->mailLogger ->log ($ message , $ priority );
66+ return $ exceptionFile ;
67+ }
68+
69+
70+ protected function getStreamLogger ($ priority )
5171 {
5272 if (!$ this ->directory ) {
5373 throw new \LogicException ('Logging directory is not specified. ' );
5474 } elseif (!is_dir ($ this ->directory )) {
5575 throw new \RuntimeException ("Logging directory ' $ this ->directory ' is not found or is not directory. " );
5676 }
5777
58- $ exceptionFile = $ message instanceof \Exception || $ message instanceof \Throwable
59- ? $ this ->getExceptionFile ($ message )
60- : null ;
61- $ line = $ this ->formatLogLine ($ message , $ exceptionFile );
62- $ file = $ this ->directory . '/ ' . strtolower ($ priority ?: self ::INFO ) . '.log ' ;
63-
64- if (!@file_put_contents ($ file , $ line . PHP_EOL , FILE_APPEND | LOCK_EX )) { // @ is escalated to exception
65- throw new \RuntimeException ("Unable to write to log file ' $ file'. Is directory writable? " );
78+ $ path = $ this ->directory . '/ ' . strtolower ($ priority ?: self ::INFO ) . '.log ' ;
79+ if (!isset ($ this ->streamLoggers [$ path ])) {
80+ $ this ->streamLoggers [$ path ] = new StreamLogger ($ path , $ this ->blueScreenLogger );
6681 }
6782
68- if ($ exceptionFile ) {
69- $ this ->logException ($ message , $ exceptionFile );
70- }
83+ return $ this ->streamLoggers [$ path ];
84+ }
7185
72- if (in_array ($ priority , [self ::ERROR , self ::EXCEPTION , self ::CRITICAL ], true )) {
73- $ this ->sendEmail ($ message );
74- }
7586
76- return $ exceptionFile ;
87+ protected function createBlueScreenLogger ()
88+ {
89+ $ blueScreenLogger = new BlueScreenLogger ($ this ->directory , $ this ->blueScreen );
90+ $ blueScreenLogger ->directory = &$ this ->directory ;
91+
92+ return $ blueScreenLogger ;
93+ }
94+
95+
96+ protected function createMailLogger ()
97+ {
98+ $ mailLogger = new MailLogger ($ this ->directory , $ this ->email );
99+ $ mailLogger ->directory = &$ this ->directory ;
100+ $ mailLogger ->email = &$ this ->email ;
101+ $ mailLogger ->fromEmail = &$ this ->fromEmail ;
102+ $ mailLogger ->emailSnooze = &$ this ->emailSnooze ;
103+ $ mailLogger ->mailer = &$ this ->mailer ;
104+
105+ return $ mailLogger ;
77106 }
78107
79108
@@ -83,21 +112,7 @@ public function log($message, $priority = self::INFO)
83112 */
84113 protected function formatMessage ($ message )
85114 {
86- if ($ message instanceof \Exception || $ message instanceof \Throwable) {
87- while ($ message ) {
88- $ tmp [] = ($ message instanceof \ErrorException
89- ? Helpers::errorTypeToString ($ message ->getSeverity ()) . ': ' . $ message ->getMessage ()
90- : Helpers::getClass ($ message ) . ': ' . $ message ->getMessage () . ($ message ->getCode () ? ' # ' . $ message ->getCode () : '' )
91- ) . ' in ' . $ message ->getFile () . ': ' . $ message ->getLine ();
92- $ message = $ message ->getPrevious ();
93- }
94- $ message = implode ("\ncaused by " , $ tmp );
95-
96- } elseif (!is_string ($ message )) {
97- $ message = Dumper::toText ($ message );
98- }
99-
100- return trim ($ message );
115+ return Helpers::formatMessage ($ message );
101116 }
102117
103118
@@ -117,87 +132,42 @@ protected function formatLogLine($message, $exceptionFile = null)
117132
118133
119134 /**
120- * @param \Exception|\Throwable
121- * @return string
135+ * @deprecated
122136 */
123137 public function getExceptionFile ($ exception )
124138 {
125- while ($ exception ) {
126- $ data [] = [
127- get_class ($ exception ), $ exception ->getMessage (), $ exception ->getCode (), $ exception ->getFile (), $ exception ->getLine (),
128- array_map (function ($ item ) { unset($ item ['args ' ]); return $ item ; }, $ exception ->getTrace ()),
129- ];
130- $ exception = $ exception ->getPrevious ();
131- }
132- $ hash = substr (md5 (serialize ($ data )), 0 , 10 );
133- $ dir = strtr ($ this ->directory . '/ ' , '\\/ ' , DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
134- foreach (new \DirectoryIterator ($ this ->directory ) as $ file ) {
135- if (strpos ($ file ->getBasename (), $ hash )) {
136- return $ dir . $ file ;
137- }
138- }
139- return $ dir . 'exception-- ' . @date ('Y-m-d--H-i ' ) . "-- $ hash.html " ; // @ timezone may not be set
139+ return $ this ->blueScreenLogger ->getExceptionFile ($ exception );
140140 }
141141
142142
143143 /**
144- * Logs exception to the file if file doesn't exist.
145- * @param \Exception|\Throwable
146- * @return string logged error filename
144+ * @deprecated
147145 */
148146 protected function logException ($ exception , $ file = null )
149147 {
150- $ file = $ file ?: $ this ->getExceptionFile ($ exception );
151- $ bs = $ this ->blueScreen ?: new BlueScreen ;
152- $ bs ->renderToFile ($ exception , $ file );
153- return $ file ;
148+ $ reflection = new \ReflectionMethod ($ this ->blueScreenLogger , 'logException ' );
149+ $ reflection ->setAccessible (true );
150+ return $ reflection ->invoke ($ this ->blueScreenLogger , $ exception , $ file );
154151 }
155152
156153
157154 /**
158- * @param string|\Exception|\Throwable
159- * @return void
155+ * @deprecated
160156 */
161157 protected function sendEmail ($ message )
162158 {
163- $ snooze = is_numeric ($ this ->emailSnooze )
164- ? $ this ->emailSnooze
165- : @strtotime ($ this ->emailSnooze ) - time (); // @ timezone may not be set
166-
167- if ($ this ->email && $ this ->mailer
168- && @filemtime ($ this ->directory . '/email-sent ' ) + $ snooze < time () // @ file may not exist
169- && @file_put_contents ($ this ->directory . '/email-sent ' , 'sent ' ) // @ file may not be writable
170- ) {
171- call_user_func ($ this ->mailer , $ message , implode (', ' , (array ) $ this ->email ));
172- }
159+ $ reflection = new \ReflectionMethod ($ this ->mailLogger , 'sendEmail ' );
160+ $ reflection ->setAccessible (true );
161+ return $ reflection ->invoke ($ this ->mailLogger , $ message );
173162 }
174163
175164
176165 /**
177- * Default mailer.
178- * @param string|\Exception|\Throwable
179- * @param string
180- * @return void
166+ * @deprecated
181167 * @internal
182168 */
183169 public function defaultMailer ($ message , $ email )
184170 {
185- $ host = preg_replace ('#[^\w.-]+# ' , '' , isset ($ _SERVER ['HTTP_HOST ' ]) ? $ _SERVER ['HTTP_HOST ' ] : php_uname ('n ' ));
186- $ parts = str_replace (
187- ["\r\n" , "\n" ],
188- ["\n" , PHP_EOL ],
189- [
190- 'headers ' => implode ("\n" , [
191- 'From: ' . ($ this ->fromEmail ?: "noreply@ $ host " ),
192- 'X-Mailer: Tracy ' ,
193- 'Content-Type: text/plain; charset=UTF-8 ' ,
194- 'Content-Transfer-Encoding: 8bit ' ,
195- ]) . "\n" ,
196- 'subject ' => "PHP: An error occurred on the server $ host " ,
197- 'body ' => $ this ->formatMessage ($ message ) . "\n\nsource: " . Helpers::getSource (),
198- ]
199- );
200-
201- mail ($ email , $ parts ['subject ' ], $ parts ['body ' ], $ parts ['headers ' ]);
171+ return $ this ->mailLogger ->defaultMailer ($ message , $ email );
202172 }
203173}
0 commit comments