Overview

Namespaces

  • Thelia
    • Action
    • Config
    • Controller
    • Core
      • Bundle
      • DependencyInjection
        • Compiler
        • Loader
      • Event
      • EventListener
      • Template
        • BaseParam
    • Exception
    • Log
      • Destination
    • Model
      • map
      • om
    • Routing
      • Matcher
    • Tools
    • Tpex
      • BaseParam
      • Element
        • Loop
        • TestLoop
      • Event
      • Exception
      • Filter
      • Tokenizer

Classes

  • AbstractTlogDestination
  • Tlog
  • TlogDestinationConfig

Interfaces

  • TlogInterface
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: /*************************************************************************************/
  3: /*                                                                                   */
  4: /*      Thelia                                                                       */
  5: /*                                                                                   */
  6: /*      Copyright (c) OpenStudio                                                     */
  7: /*  email : info@thelia.net                                                      */
  8: /*      web : http://www.thelia.net                                                  */
  9: /*                                                                                   */
 10: /*      This program is free software; you can redistribute it and/or modify         */
 11: /*      it under the terms of the GNU General Public License as published by         */
 12: /*      the Free Software Foundation; either version 3 of the License                */
 13: /*                                                                                   */
 14: /*      This program is distributed in the hope that it will be useful,              */
 15: /*      but WITHOUT ANY WARRANTY; without even the implied warranty of               */
 16: /*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                */
 17: /*      GNU General Public License for more details.                                 */
 18: /*                                                                                   */
 19: /*      You should have received a copy of the GNU General Public License            */
 20: /*      along with this program. If not, see <http://www.gnu.org/licenses/>.     */
 21: /*                                                                                   */
 22: /*************************************************************************************/
 23: namespace Thelia\Log;
 24: 
 25: use Thelia\Model\ConfigQuery;
 26: use Psr\Log\LoggerInterface;
 27: 
 28: /**
 29:  *
 30:  * Thelia Logger
 31:  *
 32:  * Allow to define different level and output.
 33:  *
 34:  * @author Franck Allimant <franck@cqfdev.fr>
 35:  * @author Manuel Raynaud <mraynaud@openstudio.fr>
 36:  */
 37: class Tlog Implements LoggerInterface
 38: {
 39:     // Nom des variables de configuration
 40:     const VAR_LEVEL         = "tlog_level";
 41:     const VAR_DESTINATIONS  = "tlog_destinations";
 42:     const VAR_PREFIXE       = "tlog_prefix";
 43:     const VAR_FILES         = "tlog_files";
 44:     const VAR_IP                = "tlog_ip";
 45:     const VAR_SHOW_REDIRECT     = "tlog_show_redirect";
 46: 
 47:     // all level of trace
 48:     const DEBUG                 = 100;
 49:     const INFO                  = 200;
 50:     const NOTICE                = 300;
 51:     const WARNING               = 400;
 52:     const ERROR                 = 500;
 53:     const CRITICAL              = 600;
 54:     const ALERT                 = 700;
 55:     const EMERGENCY             = 800;
 56:     const MUET                  = PHP_INT_MAX;
 57:     
 58:     protected $levels = array(
 59:         100 => "DEBUG",
 60:         200 => "INFO",
 61:         300 => "NOTICE",
 62:         400 => "WARNING",
 63:         500 => "ERROR",
 64:         600 => "CRITICAL",
 65:         700 => "ALERT",
 66:         800 => "EMERGENCY"
 67:     );
 68: 
 69:     // default values
 70:     const DEFAULT_LEVEL         = self::DEBUG;
 71:     const DEFAUT_DESTINATIONS   = "Thelia\Log\Destination\TlogDestinationFile";
 72:     const DEFAUT_PREFIXE    = "#NUM: #NIVEAU [#FICHIER:#FONCTION()] {#LIGNE} #DATE #HEURE: ";
 73:     const DEFAUT_FILES      = "*";
 74:     const DEFAUT_IP         = "";
 75:     const DEFAUT_SHOW_REDIRECT  = 0;
 76: 
 77:     /**
 78:      *
 79:      * @var \Thelia\Log\Tlog
 80:      */
 81:     private static $instance = false;
 82: 
 83:     /**
 84:      *
 85:      * @var array containing class of destination handler
 86:      */
 87:     protected $destinations = array();
 88: 
 89:     protected $mode_back_office = false;
 90:     protected $level = self::MUET;
 91:     protected $prefixe = "";
 92:     protected $files = array();
 93:     protected $all_files = false;
 94:     protected $show_redirect = false;
 95: 
 96:     private $linecount = 0;
 97: 
 98:     protected static $done = false;
 99: 
100:     // directories where are the Destinations Files
101:     public $dir_destinations = array();
102: 
103:     /**
104:      * 
105:      */
106:     private function __construct(){}
107: 
108:     /**
109:      * 
110:      * @return \Thelia\Log\Tlog
111:      */
112:     public static function getInstance() {
113:         if (self::$instance == false) {
114:             self::$instance = new Tlog();
115: 
116:             // On doit placer les initialisations à ce level pour pouvoir
117:             // utiliser la classe Tlog dans les classes de base (Cnx, BaseObj, etc.)
118:             // Les placer dans le constructeur provoquerait une boucle
119:             self::$instance->init();
120:         }
121: 
122:         return self::$instance;
123:     }
124: 
125:     /**
126:      * initialize default configuration
127:      */
128:     protected function init()
129:     {
130: 
131:         $this->setLevel(ConfigQuery::read(self::VAR_LEVEL, self::DEFAULT_LEVEL));
132: 
133:         $this->dir_destinations = array(
134:                 __DIR__.'/Destination'
135:                 //, __DIR__.'/../client/tlog/destinations'
136:         );
137: 
138:         $this->setPrefix(ConfigQuery::read(self::VAR_PREFIXE, self::DEFAUT_PREFIXE));
139:         $this->setFiles(ConfigQuery::read(self::VAR_FILES, self::DEFAUT_FILES));
140:         $this->setIp(ConfigQuery::read(self::VAR_IP, self::DEFAUT_IP));
141:         $this->setDestinations(ConfigQuery::read(self::VAR_DESTINATIONS, self::DEFAUT_DESTINATIONS));
142:         $this->setShowRedirect(ConfigQuery::read(self::VAR_SHOW_REDIRECT, self::DEFAUT_SHOW_REDIRECT));
143: 
144:         // Au cas ou il y aurait un exit() quelque part dans le code.
145:         register_shutdown_function(array($this, 'writeOnExit'));
146:     }
147: 
148:     // Configuration
149:     // -------------
150: 
151:     /**
152:      * 
153:      * @param string $destinations
154:      */
155:     public function setDestinations($destinations)
156:     {
157:         if (! empty($destinations)) {
158: 
159:             $this->destinations = array();
160: 
161:             $classes_destinations = explode(';', $destinations);
162:             $this->loadDestinations($this->destinations, $classes_destinations);
163:         }
164:     }
165:     
166:     /**
167:      * 
168:      * change the debug level. Use Tlog constant : \Thelia\Log\Tlog::DEBUG set level to Debug
169:      * 
170:      * @param int $level
171:      */
172:     public function setLevel($level)
173:     {
174:             $this->level = $level;
175:     }
176: 
177:     public function setPrefix($prefixe)
178:     {
179:             $this->prefixe = $prefixe;
180:     }
181: 
182:     public function setFiles($files)
183:     {
184:             $this->files = explode(";", $files);
185: 
186:             $this->all_files = in_array('*', $this->files);
187:     }
188: 
189:     public function setIp($ips)
190:     {
191:             // isset($_SERVER['REMOTE_ADDR']) if we are in cli mode
192:             if (! empty($ips) && isset($_SERVER['REMOTE_ADDR']) && ! in_array($_SERVER['REMOTE_ADDR'], explode(";", $ips))) $this->level = self::MUET;
193:     }
194: 
195:     public function setShowRedirect($bool)
196:     {
197:             $this->show_redirect = $bool;
198:     }
199: 
200:     // Configuration d'une destination
201:     public function setConfig($destination, $param, $valeur)
202:     {
203:             if (isset($this->destinations[$destination])) {
204:                     $this->destinations[$destination]->setConfig($param, $valeur);
205:             }
206:     }
207: 
208:     // Configuration d'une destination
209:     public function getConfig($destination, $param)
210:     {
211:             if (isset($this->destinations[$destination])) {
212:                     return $this->destinations[$destination]->getConfig($param);
213:             }
214: 
215:             return false;
216:     }
217: 
218:     // Methodes d'accès aux traces
219:     // ---------------------------
220: 
221:     /**
222:      * Detailed debug information.
223:      *
224:      * @param string $message
225:      * @param array $context
226:      * @return null
227:      */
228:     public function debug($message, array $context = array())
229:     {
230:         $this->log(self::DEBUG, $message, $context);
231:     }
232:     
233:     /**
234:      * 
235:      * Alias of debug method. With this method you can put all parameter you want
236:      * 
237:      * ex : Tlog::getInstance()->addDebug($arg1, $arg2, $arg3);
238:      * 
239:      */
240:     public function addDebug()
241:     {
242:         $args = func_get_args();
243:         
244:         foreach ($args as $arg) {
245:             $this->log(self::DEBUG, $arg);
246:         }
247:     }
248: 
249:     /**
250:      * Interesting events.
251:      *
252:      * Example: User logs in, SQL logs.
253:      *
254:      * @param string $message
255:      * @param array $context
256:      * @return null
257:      */
258:     public function info($message, array $context = array())
259:     {
260:         $this->log(self::INFO, $message, $context);
261:     }
262:     
263:     /**
264:      * 
265:      * Alias of info method. With this method you can put all parameter you want
266:      * 
267:      * ex : Tlog::getInstance()->addInfo($arg1, $arg2, $arg3);
268:      * 
269:      */
270:     public function addInfo()
271:     {
272:         $args = func_get_args();
273:         
274:         foreach ($args as $arg) {
275:             $this->log(self::INFO, $arg);
276:         }
277:     }
278:     
279:     /**
280:      * Normal but significant events.
281:      *
282:      * @param string $message
283:      * @param array $context
284:      * @return null
285:      */
286:     public function notice($message, array $context = array())
287:     {
288:         $this->log(self::NOTICE, $message, $context);
289:     }
290:     
291:     /**
292:      * 
293:      * Alias of notice method. With this method you can put all parameter you want
294:      * 
295:      * ex : Tlog::getInstance()->addNotice($arg1, $arg2, $arg3);
296:      * 
297:      */
298:     public function addNotice()
299:     {
300:         $args = func_get_args();
301:         
302:         foreach ($args as $arg) {
303:             $this->log(self::NOTICE, $arg);
304:         }
305:     }
306: 
307:     /**
308:      * Exceptional occurrences that are not errors.
309:      *
310:      * Example: Use of deprecated APIs, poor use of an API, undesirable things
311:      * that are not necessarily wrong.
312:      *
313:      * @param string $message
314:      * @param array $context
315:      * @return null
316:      */
317:     public function warning($message, array $context = array())
318:     {
319:         $this->log(self::WARNING, $message, $context);
320:     }
321:     
322:     /**
323:      * 
324:      * Alias of warning method. With this method you can put all parameter you want
325:      * 
326:      * ex : Tlog::getInstance()->addWarning($arg1, $arg2, $arg3);
327:      * 
328:      */
329:     public function addWarning()
330:     {
331:         $args = func_get_args();
332:         
333:         foreach ($args as $arg) {
334:             $this->log(self::WARNING, $arg);
335:         }
336:     }
337: 
338:     /**
339:      * Runtime errors that do not require immediate action but should typically
340:      * be logged and monitored.
341:      *
342:      * @param string $message
343:      * @param array $context
344:      * @return null
345:      */
346:     public function error($message, array $context = array())
347:     {
348:         $this->log(self::ERROR, $message, $context);
349:     }
350:     
351:     /**
352:      * 
353:      * Alias of error method. With this method you can put all parameter you want
354:      * 
355:      * ex : Tlog::getInstance()->addError($arg1, $arg2, $arg3);
356:      * 
357:      */
358:     public function addError()
359:     {
360:         $args = func_get_args();
361:         
362:         foreach ($args as $arg) {
363:             $this->log(self::ERROR, $arg);
364:         }
365:     }
366:     
367:     /**
368:      * 
369:      * @see error()
370:      */
371:     public function err($message, array $context = array())
372:     {
373:         $this->error($message, $context);
374:     }
375:     
376:     /**
377:      * Critical conditions.
378:      *
379:      * Example: Application component unavailable, unexpected exception.
380:      *
381:      * @param string $message
382:      * @param array $context
383:      * @return null
384:      */
385:     public function critical($message, array $context = array())
386:     {
387:         $this->log(self::CRITICAL, $message, $context);
388:     }
389:     
390:     /**
391:      * 
392:      * Alias of critical method. With this method you can put all parameter you want
393:      * 
394:      * ex : Tlog::getInstance()->addCritical($arg1, $arg2, $arg3);
395:      * 
396:      */
397:     public function addCritical()
398:     {
399:         $args = func_get_args();
400:         
401:         foreach ($args as $arg) {
402:             $this->log(self::CRITICAL, $arg);
403:         }
404:     }
405:     
406:     /**
407:      * 
408:      * @see critical()
409:      */
410:     public function crit($message, array $context = array())
411:     {
412:         $this->critical($message, $context);
413:     }
414:     
415:     /**
416:      * Action must be taken immediately.
417:      *
418:      * Example: Entire website down, database unavailable, etc. This should
419:      * trigger the SMS alerts and wake you up.
420:      *
421:      * @param string $message
422:      * @param array $context
423:      * @return null
424:      */
425:     public function alert($message, array $context = array())
426:     {
427:         $this->log(self::ALERT, $message, $context);
428:     }
429:     
430:     /**
431:      * 
432:      * Alias of alert method. With this method you can put all parameter you want
433:      * 
434:      * ex : Tlog::getInstance()->addAlert($arg1, $arg2, $arg3);
435:      * 
436:      */
437:     public function addAlert()
438:     {
439:         $args = func_get_args();
440:         
441:         foreach ($args as $arg) {
442:             $this->log(self::ALERT, $arg);
443:         }
444:     }
445:     
446:     /**
447:      * System is unusable.
448:      *
449:      * @param string $message
450:      * @param array $context
451:      * @return null
452:      */
453:     public function emergency($message, array $context = array())
454:     {
455:         $this->log(self::EMERGENCY, $message, $context);
456:     }
457:     
458:     /**
459:      * 
460:      * Alias of emergency method. With this method you can put all parameter you want
461:      * 
462:      * ex : Tlog::getInstance()->addEmergency($arg1, $arg2, $arg3);
463:      * 
464:      */
465:     public function addEmergency()
466:     {
467:         $args = func_get_args();
468:         
469:         foreach ($args as $arg) {
470:             $this->log(self::EMERGENCY, $arg);
471:         }
472:     }
473:     
474:     /**
475:      * Logs with an arbitrary level.
476:      *
477:      * @param mixed $level
478:      * @param string $message
479:      * @param array $context
480:      * @return null
481:      */
482:     public function log($level, $message, array $context = array()) {
483:         if($this->level > $level || array_key_exists($level, $this->levels) === false)
484:             return;
485:         
486:         $this->out($this->levels[$level], $message, $context);
487:     }
488: 
489:     
490: 
491:     // Mode back office
492:     public static function SetBackOfficeMode($booleen)
493:     {
494:             foreach (Tlog::getInstance()->destinations as $dest) {
495:                     $dest->SetBackOfficeMode($booleen);
496:             }
497:     }
498: 
499:     /**
500:      * 
501:      * final end method. Write log for each destination handler
502:      * 
503:      * @param string $res
504:      * @return void
505:      */
506:     public function write(&$res)
507:     {
508:             self::$done = true;
509: 
510:             // Muet ? On ne fait rien
511:             if ($this->level == self::MUET) return;
512: 
513:             foreach ($this->destinations as $dest) {
514:                     $dest->write($res);
515:             }
516:     }
517: 
518:     /**
519:      * @see write()
520:      */
521:     public function writeOnExit()
522:     {
523:         // Si les infos de debug n'ont pas été ecrites, le faire maintenant
524:         if (self::$done === false) {
525: 
526:                 $res = "";
527: 
528:                 $this->write($res);
529: 
530:                 echo $res;
531:         }
532:     }
533: 
534:     public function showRedirect($url)
535:     {
536:         if ($this->level != self::MUET && $this->show_redirect) {
537:                 echo "
538: <html>
539: <head><title>Redirection...</title></head>
540: <body>
541: <a href=\"$url\">Redirection vers $url</a>
542: </body>
543: </html>
544:         ";
545: 
546:                 return true;
547:         } else {
548:                 return false;
549:         }
550:     }
551: 
552:     /**
553:      * 
554:      * check if level is activated and control if current file is activated
555:      * 
556:      * @param int $level
557:      * @return boolean
558:      */
559:     public function isActivated($level)
560:     {
561:         if ($this->level <= $level) {
562: 
563:             $origin = $this->findOrigin();
564: 
565:             $file = basename($origin['file']);
566: 
567:             if ($this->isActivedFile($file)) {
568:                     return true;
569:             }
570:         }
571: 
572:         return false;
573:     }
574:     
575:     /**
576:      * 
577:      * check if $file is in authorized files
578:      * 
579:      * @param string $file
580:      * @return boolean
581:      */
582:     public function isActivedFile($file)
583:     {
584:         return ($this->all_files || in_array($file, $this->files)) && ! in_array("!$file", $this->files);
585:     }
586: 
587:     /* -- Methodes privees ---------------------------------------- */
588: 
589:     
590:     private function findOrigin()
591:     {
592:         $origine = array();
593: 
594:         if (function_exists('debug_backtrace')) {
595: 
596:             $trace = debug_backtrace();
597:             $prevHop = null;
598:             // make a downsearch to identify the caller
599:             $hop = array_pop($trace);
600: 
601:             while ($hop !== null) {
602:                 if (isset($hop['class'])) {
603:                     // we are sometimes in functions = no class available: avoid php warning here
604:                     $className = $hop['class'];
605: 
606:                     if (! empty($className) and ($className == ltrim(__CLASS__,'\\') or strtolower(get_parent_class($className)) == ltrim(__CLASS__,'\\'))) {
607:                             $origine['line'] = $hop['line'];
608:                             $origine['file'] = $hop['file'];
609:                             break;
610:                     }
611:                 }
612:                 $prevHop = $hop;
613:                 $hop = array_pop($trace);
614:             }
615: 
616:             $origine['class'] = isset($prevHop['class']) ? $prevHop['class'] : 'main';
617: 
618:             if(isset($prevHop['function']) and
619:                 $prevHop['function'] !== 'include' and
620:                 $prevHop['function'] !== 'include_once' and
621:                 $prevHop['function'] !== 'require' and
622:                 $prevHop['function'] !== 'require_once') {
623: 
624:                 $origine['function'] = $prevHop['function'];
625:             } else {
626:                 $origine['function'] = 'main';
627:             }
628:         }
629: 
630:         return $origine;
631:     }
632:     
633:     protected function interpolate($message, array $context = array())
634:     {
635:         // build a replacement array with braces around the context keys
636:         $replace = array();
637:         foreach ($context as $key => $val) {
638:             $replace['{' . $key . '}'] = $val;
639:         }
640: 
641:         // interpolate replacement values into the message and return
642:         return strtr($message, $replace);
643:     }
644: 
645:     private function out($level, $message, array $context = array())
646:     {
647:         $text = '';
648:         
649:         /*if (is_array($message)) {
650:             foreach ($message as $arg) {
651:                 $text .= is_scalar($arg) ? $arg : print_r($arg, true);
652:             }
653:         } else */ if (is_scalar($message) === false) {
654:             $text = print_r($message, true);
655:         } else {
656:             $text = $message;
657:         }
658:          
659:         $text = $this->interpolate($text, $context);
660: 
661:         $origine = $this->findOrigin();
662: 
663:         $file = basename($origine['file']);
664: 
665:         if ($this->isActivedFile($file)) {
666: 
667:             $function = $origine['function'];
668:             $line = $origine['line'];
669: 
670:             $prefixe = str_replace(
671:                 array("#NUM", "#NIVEAU", "#FICHIER", "#FONCTION", "#LIGNE", "#DATE", "#HEURE"),
672:                 array(1+$this->linecount, $level, $file, $function, $line, date("Y-m-d"), date("G:i:s")),
673:                 $this->prefixe
674:             );
675: 
676:             $trace = $prefixe . $text;
677: 
678:             foreach ($this->destinations as $dest) {
679:                 $dest->add($trace);
680:             }
681: 
682:             $this->linecount++;
683:         }
684:     }
685: 
686:     /**
687:      *
688:      * @param type  $destinations
689:      * @param array $actives      array containing classes instanceof AbstractTlogDestination
690:      */
691:     protected function loadDestinations(&$destinations, array $actives = NULL)
692:     {
693:         foreach ($actives as $active) {
694:             if (class_exists($active)) {
695:                 $class = new $active();
696: 
697:                 if (!$class instanceof AbstractTlogDestination) {
698:                     throw new \UnexpectedValueException($active." must extends Thelia\Tlog\AbstractTlogDestination");
699:                 }
700: 
701:                 $destinations[$active] = $class;
702:             }
703:         }
704:     }
705: }
706: 
thelia API documentation generated by ApiGen 2.8.0