Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • Bar
  • BlueScreen
  • Debugger
  • Dumper
  • FireLogger
  • Helpers
  • Logger
  • OutputDebugger

Interfaces

  • IBarPanel
  • ILogger
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Tracy (http://tracy.nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Tracy;
  9: 
 10: use Tracy;
 11: 
 12: 
 13: /**
 14:  * Logger.
 15:  *
 16:  * @author     David Grudl
 17:  */
 18: class Logger implements ILogger
 19: {
 20:     /** @var string name of the directory where errors should be logged */
 21:     public $directory;
 22: 
 23:     /** @var string|array email or emails to which send error notifications */
 24:     public $email;
 25: 
 26:     /** @var mixed interval for sending email is 2 days */
 27:     public $emailSnooze = '2 days';
 28: 
 29:     /** @var callable handler for sending emails */
 30:     public $mailer;
 31: 
 32:     /** @var BlueScreen */
 33:     private $blueScreen;
 34: 
 35: 
 36:     public function __construct($directory, $email = NULL, BlueScreen $blueScreen = NULL)
 37:     {
 38:         $this->directory = $directory;
 39:         $this->email = $email;
 40:         $this->blueScreen = $blueScreen;
 41:         $this->mailer = array($this, 'defaultMailer');
 42:     }
 43: 
 44: 
 45:     /**
 46:      * Logs message or exception to file and sends email notification.
 47:      * @param  string|\Exception
 48:      * @param  int   one of constant ILogger::INFO, WARNING, ERROR (sends email), EXCEPTION (sends email), CRITICAL (sends email)
 49:      * @return string logged error filename
 50:      */
 51:     public function log($message, $priority = self::INFO)
 52:     {
 53:         if (!$this->directory) {
 54:             throw new \LogicException('Directory is not specified.');
 55:         } elseif (!is_dir($this->directory)) {
 56:             throw new \RuntimeException("Directory '$this->directory' is not found or is not directory.");
 57:         }
 58: 
 59:         $exceptionFile = $message instanceof \Exception ? $this->getExceptionFile($message) : NULL;
 60:         $line = $this->formatLogLine($message, $exceptionFile);
 61:         $file = $this->directory . '/' . strtolower($priority ?: self::INFO) . '.log';
 62: 
 63:         if (!@file_put_contents($file, $line . PHP_EOL, FILE_APPEND | LOCK_EX)) {
 64:             throw new \RuntimeException("Unable to write to log file '$file'. Is directory writable?");
 65:         }
 66: 
 67:         if ($message instanceof \Exception) {
 68:             $this->logException($message, $exceptionFile);
 69:         }
 70: 
 71:         if (in_array($priority, array(self::ERROR, self::EXCEPTION, self::CRITICAL), TRUE)) {
 72:             $this->sendEmail($message);
 73:         }
 74: 
 75:         return $exceptionFile;
 76:     }
 77: 
 78: 
 79:     /**
 80:      * @return string
 81:      */
 82:     protected function formatMessage($message)
 83:     {
 84:         if ($message instanceof \Exception) {
 85:             while ($message) {
 86:                 $tmp[] = ($message instanceof \ErrorException ?
 87:                     'Fatal error: ' . $message->getMessage()
 88:                     : get_class($message) . ': ' . $message->getMessage()
 89:                 ) . ' in ' . $message->getFile() . ':' . $message->getLine();
 90:                 $message = $message->getPrevious();
 91:             }
 92:             $message = implode($tmp, "\ncaused by ");
 93: 
 94:         } elseif (!is_string($message)) {
 95:             $message = Dumper::toText($message);
 96:         }
 97: 
 98:         return trim($message);
 99:     }
100: 
101: 
102:     /**
103:      * @return string
104:      */
105:     protected function formatLogLine($message, $exceptionFile = NULL)
106:     {
107:         return implode(' ', array(
108:             @date('[Y-m-d H-i-s]'),
109:             preg_replace('#\s*\r?\n\s*#', ' ', $this->formatMessage($message)),
110:             ' @  ' . Helpers::getSource(),
111:             $exceptionFile ? ' @@  ' . basename($exceptionFile) : NULL
112:         ));
113:     }
114: 
115: 
116:     /**
117:      * @return string
118:      */
119:     protected function getExceptionFile(\Exception $exception)
120:     {
121:         $dir = strtr($this->directory . '/', '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
122:         $hash = md5(preg_replace('~(Resource id #)\d+~', '$1', $exception));
123:         foreach (new \DirectoryIterator($this->directory) as $file) {
124:             if (strpos($file, $hash)) {
125:                 return $dir . $file;
126:             }
127:         }
128:         return $dir . 'exception-' . @date('Y-m-d-H-i-s') . "-$hash.html";
129:     }
130: 
131: 
132:     /**
133:      * Logs exception to the file if file doesn't exist.
134:      * @return string logged error filename
135:      */
136:     protected function logException(\Exception $exception, $file = NULL)
137:     {
138:         $file = $file ?: $this->getExceptionFile($exception);
139:         if ($handle = @fopen($file, 'x')) {
140:             ob_start(); // double buffer prevents sending HTTP headers in some PHP
141:             ob_start(function($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096);
142:             $bs = $this->blueScreen ?: new BlueScreen;
143:             $bs->render($exception);
144:             ob_end_flush();
145:             ob_end_clean();
146:             fclose($handle);
147:         }
148:         return $file;
149:     }
150: 
151: 
152:     /**
153:      * @param  string
154:      * @return void
155:      */
156:     protected function sendEmail($message)
157:     {
158:         $snooze = is_numeric($this->emailSnooze)
159:             ? $this->emailSnooze
160:             : strtotime($this->emailSnooze) - time();
161: 
162:         if ($this->email && $this->mailer
163:             && @filemtime($this->directory . '/email-sent') + $snooze < time() // @ - file may not exist
164:             && @file_put_contents($this->directory . '/email-sent', 'sent') // @ - file may not be writable
165:         ) {
166:             call_user_func($this->mailer, $message, implode(', ', (array) $this->email));
167:         }
168:     }
169: 
170: 
171:     /**
172:      * Default mailer.
173:      * @param  string
174:      * @param  string
175:      * @return void
176:      * @internal
177:      */
178:     public function defaultMailer($message, $email)
179:     {
180:         $host = preg_replace('#[^\w.-]+#', '', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n'));
181:         $parts = str_replace(
182:             array("\r\n", "\n"),
183:             array("\n", PHP_EOL),
184:             array(
185:                 'headers' => implode("\n", array(
186:                     "From: noreply@$host",
187:                     'X-Mailer: Tracy',
188:                     'Content-Type: text/plain; charset=UTF-8',
189:                     'Content-Transfer-Encoding: 8bit',
190:                 )) . "\n",
191:                 'subject' => "PHP: An error occurred on the server $host",
192:                 'body' => $this->formatMessage($message) . "\n\nsource: " . Helpers::getSource(),
193:             )
194:         );
195: 
196:         mail($email, $parts['subject'], $parts['body'], $parts['headers']);
197:     }
198: 
199: }
200: 
Nette 2.3.1 API API documentation generated by ApiGen 2.8.0