1: <?php
2: 3: 4: 5: 6: 7:
8:
9: namespace Wei;
10:
11: 12: 13: 14: 15: 16:
17: class Logger extends Base
18: {
19: 20: 21: 22: 23:
24: protected $namespace = '';
25:
26: 27: 28: 29: 30:
31: protected $level = 'debug';
32:
33: 34: 35: 36: 37:
38: protected $handledLevel = 'debug';
39:
40: 41: 42: 43: 44:
45: protected $levels = array(
46: 'debug' => 100,
47: 'info' => 200,
48: 'notice' => 250,
49: 'warning' => 300,
50: 'error' => 400,
51: 'critical' => 500,
52: 'alert' => 550,
53: 'emergency' => 600
54: );
55:
56: 57: 58: 59: 60:
61: protected $format = "[%datetime%] %level%: %message%\n";
62:
63: 64: 65: 66: 67:
68: protected $dateFormat = 'H:i:s';
69:
70: 71: 72: 73: 74: 75:
76: protected $file = null;
77:
78: 79: 80: 81: 82:
83: protected $dir = 'log';
84:
85: 86: 87: 88: 89:
90: protected $fileFormat = 'Ymd.\l\o\g';
91:
92: 93: 94: 95: 96: 97:
98: protected $fileSize = 134217728;
99:
100: 101: 102: 103: 104: 105:
106: protected $fileDetected = false;
107:
108: 109: 110: 111: 112:
113: protected $context = array();
114:
115: 116: 117: 118: 119:
120: private $handle;
121:
122: 123: 124: 125: 126: 127: 128: 129:
130: public function log($level, $message, array $context = array())
131: {
132: $level = isset($this->levels[$level]) ? $level : $this->level;
133:
134:
135: if (isset($this->levels[$level])) {
136: if ($this->levels[$level] < $this->levels[$this->handledLevel]) {
137: return false;
138: }
139: }
140:
141: return $this->writeLog($level, $message, $context);
142: }
143:
144: 145: 146: 147: 148: 149: 150: 151:
152: protected function writeLog($level, $message, $context)
153: {
154: if (!$this->handle) {
155: $this->handle = fopen($this->getFile(), 'a');
156: }
157: $content = $this->formatLog($level, $message, $context);
158: return (bool)fwrite($this->handle, $content);
159: }
160:
161: 162: 163: 164: 165: 166: 167: 168:
169: protected function formatLog($level, $message, array $context = array())
170: {
171: if ($message instanceof \Exception) {
172: $context += array(
173: 'code' => $message->getCode(),
174: 'file' => $message->getFile(),
175: 'line' => $message->getLine(),
176: 'trace' => $message->getTraceAsString(),
177: );
178: $message = $message->getMessage();
179: } elseif (is_array($message)) {
180: $message = print_r($message, true);
181: } else {
182: $message = (string)$message;
183: }
184:
185:
186: $content = str_replace(array(
187: '%datetime%', '%namespace%', '%level%', '%message%',
188: ), array(
189: date($this->dateFormat, microtime(true)),
190: $this->namespace,
191: strtoupper($level),
192: $message,
193: ), $this->format);
194:
195:
196: if ($this->context || $context) {
197: $content .= print_r($this->context + $context, true) . "\n";
198: }
199:
200: return $content;
201: }
202:
203: 204: 205: 206: 207: 208: 209: 210:
211: public function __invoke($level, $message, array $context = array())
212: {
213: return $this->log($level, $message, $context);
214: }
215:
216: 217: 218: 219: 220: 221: 222:
223: public function emergency($message, array $context = array())
224: {
225: return $this('emergency', $message, $context);
226: }
227:
228: 229: 230: 231: 232: 233: 234: 235: 236: 237:
238: public function alert($message, array $context = array())
239: {
240: return $this->log('alert', $message, $context);
241: }
242:
243: 244: 245: 246: 247: 248: 249: 250: 251:
252: public function critical($message, array $context = array())
253: {
254: return $this->log('critical', $message, $context);
255: }
256:
257: 258: 259: 260: 261: 262: 263: 264:
265: public function error($message, array $context = array())
266: {
267: return $this->log('error', $message, $context);
268: }
269:
270: 271: 272: 273: 274: 275: 276: 277: 278: 279:
280: public function warning($message, array $context = array())
281: {
282: return $this->log('warning', $message, $context);
283: }
284:
285: 286: 287: 288: 289: 290: 291:
292: public function notice($message, array $context = array())
293: {
294: return $this->log('notice', $message, $context);
295: }
296:
297: 298: 299: 300: 301: 302: 303: 304: 305:
306: public function info($message, array $context = array())
307: {
308: return $this->log('info', $message, $context);
309: }
310:
311: 312: 313: 314: 315: 316: 317:
318: public function debug($message, array $context = array())
319: {
320: return $this->log('debug', $message, $context);
321: }
322:
323: 324: 325: 326: 327: 328:
329: public function getFile()
330: {
331: if ($this->fileDetected) {
332: return $this->file;
333: }
334:
335: $this->handle = null;
336: $file = &$this->file;
337:
338: if (!is_dir($this->dir) && !@mkdir($this->dir, 0755, true)) {
339: $message = sprintf('Fail to create directory "%s"', $this->dir);
340: ($e = error_get_last()) && $message .= ': ' . $e['message'];
341: throw new \RuntimeException($message);
342: }
343:
344: $file = realpath($this->dir) . '/' . date($this->fileFormat);
345:
346: if ($this->fileSize) {
347: $firstFile = $file;
348:
349: $files = glob($file . '*', GLOB_NOSORT);
350:
351: if (1 < count($files)) {
352: natsort($files);
353: $file = array_pop($files);
354: }
355:
356: if (is_file($file) && $this->fileSize < filesize($file)) {
357: $ext = pathinfo($file, PATHINFO_EXTENSION);
358: if (is_numeric($ext)) {
359: $file = $firstFile . '.' . ($ext + 1);
360: } else {
361: $file = $firstFile . '.1';
362: }
363: }
364: }
365:
366: $this->fileDetected = true;
367:
368: return $file;
369: }
370:
371: 372: 373: 374: 375: 376:
377: public function setLevel($level)
378: {
379: $this->level = $level;
380: return $this;
381: }
382:
383: 384: 385: 386: 387: 388:
389: public function setHandledLevel($handledLevel)
390: {
391: $this->handledLevel = $handledLevel;
392: return $this;
393: }
394:
395: 396: 397: 398: 399: 400: 401:
402: public function setContext($name, $value = null)
403: {
404: if (is_array($name)) {
405: $this->context = $name + $this->context;
406: } else {
407: $this->context[$name] = $value;
408: }
409: return $this;
410: }
411:
412: 413: 414: 415: 416:
417: public function clean()
418: {
419:
420: $this->close();
421:
422: $dir = dirname($this->getFile());
423: if (is_dir($dir)) {
424: $files = scandir($dir);
425: foreach ($files as $file) {
426: if ('.' != $file && '..' != $file) {
427: $file = $dir . DIRECTORY_SEPARATOR . $file;
428: if (is_file($file)) {
429: unlink($file);
430: }
431: }
432: }
433: }
434: return $this;
435: }
436:
437: 438: 439:
440: protected function close()
441: {
442: if (is_resource($this->handle)) {
443: fclose($this->handle);
444: }
445: $this->handle = null;
446: }
447:
448: 449: 450:
451: public function __destruct()
452: {
453: $this->close();
454: }
455: }
456: