[ Index ] |
|
Code source de PRADO 3.0.6 |
1 <?php 2 /** 3 * TLogRouter, TLogRoute, TFileLogRoute, TEmailLogRoute class file 4 * 5 * @author Qiang Xue <qiang.xue@gmail.com> 6 * @link http://www.pradosoft.com/ 7 * @copyright Copyright © 2005 PradoSoft 8 * @license http://www.pradosoft.com/license/ 9 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 10 * @package System.Util 11 */ 12 13 /** 14 * TLogRouter class. 15 * 16 * TLogRouter manages routes that record log messages in different media different ways. 17 * For example, a file log route {@link TFileLogRoute} records log messages 18 * in log files. An email log route {@link TEmailLogRoute} sends log messages 19 * to email addresses. 20 * 21 * Log routes may be configured in application or page folder configuration files 22 * or an external configuration file specified by {@link setConfigFile ConfigFile}. 23 * The format is as follows, 24 * <code> 25 * <route class="TFileLogRoute" Categories="System.Web.UI" Levels="Warning" /> 26 * <route class="TEmailLogRoute" Categories="Application" Levels="Fatal" Emails="admin@pradosoft.com" /> 27 * </code> 28 * You can specify multiple routes with different filtering conditions and different 29 * targets, even if the routes are of the same type. 30 * 31 * @author Qiang Xue <qiang.xue@gmail.com> 32 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 33 * @package System.Util 34 * @since 3.0 35 */ 36 class TLogRouter extends TModule 37 { 38 /** 39 * File extension of external configuration file 40 */ 41 const CONFIG_FILE_EXT='.xml'; 42 /** 43 * @var array list of routes available 44 */ 45 private $_routes=array(); 46 /** 47 * @var string external configuration file 48 */ 49 private $_configFile=null; 50 51 /** 52 * Initializes this module. 53 * This method is required by the IModule interface. 54 * @param TXmlElement configuration for this module, can be null 55 * @throws TConfigurationException if {@link getConfigFile ConfigFile} is invalid. 56 */ 57 public function init($config) 58 { 59 if($this->_configFile!==null) 60 { 61 if(is_file($this->_configFile)) 62 { 63 $dom=new TXmlDocument; 64 $dom->loadFromFile($this->_configFile); 65 $this->loadConfig($dom); 66 } 67 else 68 throw new TConfigurationException('logrouter_configfile_invalid',$this->_configFile); 69 } 70 $this->loadConfig($config); 71 $this->getApplication()->attachEventHandler('OnEndRequest',array($this,'collectLogs')); 72 } 73 74 /** 75 * Loads configuration from an XML element 76 * @param TXmlElement configuration node 77 * @throws TConfigurationException if log route class or type is not specified 78 */ 79 private function loadConfig($xml) 80 { 81 foreach($xml->getElementsByTagName('route') as $routeConfig) 82 { 83 $properties=$routeConfig->getAttributes(); 84 if(($class=$properties->remove('class'))===null) 85 throw new TConfigurationException('logrouter_routeclass_required'); 86 $route=Prado::createComponent($class); 87 if(!($route instanceof TLogRoute)) 88 throw new TConfigurationException('logrouter_routetype_invalid'); 89 foreach($properties as $name=>$value) 90 $route->setSubproperty($name,$value); 91 $this->_routes[]=$route; 92 $route->init($routeConfig); 93 } 94 } 95 96 /** 97 * @return string external configuration file. Defaults to null. 98 */ 99 public function getConfigFile() 100 { 101 return $this->_configFile; 102 } 103 104 /** 105 * @param string external configuration file in namespace format. The file 106 * must be suffixed with '.xml'. 107 * @throws TInvalidDataValueException if the file is invalid. 108 */ 109 public function setConfigFile($value) 110 { 111 if(($this->_configFile=Prado::getPathOfNamespace($value,self::LOG_FILE_EXT))===null) 112 throw new TConfigurationException('logrouter_configfile_invalid',$value); 113 } 114 115 /** 116 * Collects log messages from a logger. 117 * This method is an event handler to application's EndRequest event. 118 * @param mixed event parameter 119 */ 120 public function collectLogs($param) 121 { 122 $logger=Prado::getLogger(); 123 foreach($this->_routes as $route) 124 $route->collectLogs($logger); 125 } 126 } 127 128 /** 129 * TLogRoute class. 130 * 131 * TLogRoute is the base class for all log route classes. 132 * A log route object retrieves log messages from a logger and sends it 133 * somewhere, such as files, emails. 134 * The messages being retrieved may be filtered first before being sent 135 * to the destination. The filters include log level filter and log category filter. 136 * 137 * To specify level filter, set {@link setLevels Levels} property, 138 * which takes a string of comma-separated desired level names (e.g. 'Error, Debug'). 139 * To specify category filter, set {@link setCategories Categories} property, 140 * which takes a string of comma-separated desired category names (e.g. 'System.Web, System.IO'). 141 * 142 * Level filter and category filter are combinational, i.e., only messages 143 * satisfying both filter conditions will they be returned. 144 * 145 * @author Qiang Xue <qiang.xue@gmail.com> 146 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 147 * @package System.Util 148 * @since 3.0 149 */ 150 abstract class TLogRoute extends TApplicationComponent 151 { 152 /** 153 * @var array lookup table for level names 154 */ 155 protected static $_levelNames=array( 156 TLogger::DEBUG=>'Debug', 157 TLogger::INFO=>'Info', 158 TLogger::NOTICE=>'Notice', 159 TLogger::WARNING=>'Warning', 160 TLogger::ERROR=>'Error', 161 TLogger::ALERT=>'Alert', 162 TLogger::FATAL=>'Fatal' 163 ); 164 /** 165 * @var array lookup table for level values 166 */ 167 protected static $_levelValues=array( 168 'debug'=>TLogger::DEBUG, 169 'info'=>TLogger::INFO, 170 'notice'=>TLogger::NOTICE, 171 'warning'=>TLogger::WARNING, 172 'error'=>TLogger::ERROR, 173 'alert'=>TLogger::ALERT, 174 'fatal'=>TLogger::FATAL 175 ); 176 /** 177 * @var integer log level filter (bits) 178 */ 179 private $_levels=null; 180 /** 181 * @var array log category filter 182 */ 183 private $_categories=null; 184 185 /** 186 * Initializes the route. 187 * @param TXmlElement configurations specified in {@link TLogRouter}. 188 */ 189 public function init($config) 190 { 191 } 192 193 /** 194 * @return integer log level filter 195 */ 196 public function getLevels() 197 { 198 return $this->_levels; 199 } 200 201 /** 202 * @param integer|string integer log level filter (in bits). If the value is 203 * a string, it is assumed to be comma-separated level names. Valid level names 204 * include 'Debug', 'Info', 'Notice', 'Warning', 'Error', 'Alert' and 'Fatal'. 205 */ 206 public function setLevels($levels) 207 { 208 if(is_integer($levels)) 209 $this->_levels=$levels; 210 else 211 { 212 $this->_levels=null; 213 $levels=strtolower($levels); 214 foreach(explode(',',$levels) as $level) 215 { 216 $level=trim($level); 217 if(isset(self::$_levelValues[$level])) 218 $this->_levels|=self::$_levelValues[$level]; 219 } 220 } 221 } 222 223 /** 224 * @return array list of categories to be looked for 225 */ 226 public function getCategories() 227 { 228 return $this->_categories; 229 } 230 231 /** 232 * @param array|string list of categories to be looked for. If the value is a string, 233 * it is assumed to be comma-separated category names. 234 */ 235 public function setCategories($categories) 236 { 237 if(is_array($categories)) 238 $this->_categories=$categories; 239 else 240 { 241 $this->_categories=null; 242 foreach(explode(',',$categories) as $category) 243 { 244 if(($category=trim($category))!=='') 245 $this->_categories[]=$category; 246 } 247 } 248 } 249 250 /** 251 * @param integer level value 252 * @return string level name 253 */ 254 protected function getLevelName($level) 255 { 256 return isset(self::$_levelNames[$level])?self::$_levelNames[$level]:'Unknown'; 257 } 258 259 /** 260 * @param string level name 261 * @return integer level value 262 */ 263 protected function getLevelValue($level) 264 { 265 return isset(self::$_levelValues[$level])?self::$_levelValues[$level]:0; 266 } 267 268 /** 269 * Formats a log message given different fields. 270 * @param string message content 271 * @param integer message level 272 * @param string message category 273 * @param integer timestamp 274 * @return string formatted message 275 */ 276 protected function formatLogMessage($message,$level,$category,$time) 277 { 278 return @date('M d H:i:s',$time).' ['.$this->getLevelName($level).'] ['.$category.'] '.$message."\n"; 279 } 280 281 /** 282 * Retrieves log messages from logger to log route specific destination. 283 * @param TLogger logger instance 284 */ 285 public function collectLogs(TLogger $logger) 286 { 287 $logs=$logger->getLogs($this->getLevels(),$this->getCategories()); 288 if(!empty($logs)) 289 $this->processLogs($logs); 290 } 291 292 /** 293 * Processes log messages and sends them to specific destination. 294 * Derived child classes must implement this method. 295 * @param array list of messages. Each array elements represents one message 296 * with the following structure: 297 * array( 298 * [0] => message 299 * [1] => level 300 * [2] => category 301 * [3] => timestamp); 302 */ 303 abstract protected function processLogs($logs); 304 } 305 306 /** 307 * TFileLogRoute class. 308 * 309 * TFileLogRoute records log messages in files. 310 * The log files are stored under {@link setLogPath LogPath} and the file name 311 * is specified by {@link setLogFile LogFile}. If the size of the log file is 312 * greater than {@link setMaxFileSize MaxFileSize} (in kilo-bytes), a rotation 313 * is performed, which renames the current log file by suffixing the file name 314 * with '.1'. All existing log files are moved backwards one place, i.e., '.2' 315 * to '.3', '.1' to '.2'. The property {@link setMaxLogFiles MaxLogFiles} 316 * specifies how many files to be kept. 317 * 318 * @author Qiang Xue <qiang.xue@gmail.com> 319 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 320 * @package System.Util 321 * @since 3.0 322 */ 323 class TFileLogRoute extends TLogRoute 324 { 325 /** 326 * @var integer maximum log file size 327 */ 328 private $_maxFileSize=512; // in KB 329 /** 330 * @var integer number of log files used for rotation 331 */ 332 private $_maxLogFiles=2; 333 /** 334 * @var string directory storing log files 335 */ 336 private $_logPath=null; 337 /** 338 * @var string log file name 339 */ 340 private $_logFile='prado.log'; 341 342 /** 343 * @return string directory storing log files. Defaults to application runtime path. 344 */ 345 public function getLogPath() 346 { 347 if($this->_logPath===null) 348 $this->_logPath=$this->getApplication()->getRuntimePath(); 349 return $this->_logPath; 350 } 351 352 /** 353 * @param string directory (in namespace format) storing log files. 354 * @throws TConfigurationException if log path is invalid 355 */ 356 public function setLogPath($value) 357 { 358 if(($this->_logPath=Prado::getPathOfNamespace($value))===null || !is_dir($this->_logPath) || !is_writable($this->_logPath)) 359 throw new TConfigurationException('filelogroute_logpath_invalid',$value); 360 } 361 362 /** 363 * @return string log file name. Defaults to 'prado.log'. 364 */ 365 public function getLogFile() 366 { 367 return $this->_logFile; 368 } 369 370 /** 371 * @param string log file name 372 */ 373 public function setLogFile($value) 374 { 375 $this->_logFile=$value; 376 } 377 378 /** 379 * @return integer maximum log file size in kilo-bytes (KB). Defaults to 1024 (1MB). 380 */ 381 public function getMaxFileSize() 382 { 383 return $this->_maxFileSize; 384 } 385 386 /** 387 * @param integer maximum log file size in kilo-bytes (KB). 388 * @throws TInvalidDataValueException if the value is smaller than 1. 389 */ 390 public function setMaxFileSize($value) 391 { 392 $this->_maxFileSize=TPropertyValue::ensureInteger($value); 393 if($this->_maxFileSize<=0) 394 throw new TInvalidDataValueException('filelogroute_maxfilesize_invalid'); 395 } 396 397 /** 398 * @return integer number of files used for rotation. Defaults to 2. 399 */ 400 public function getMaxLogFiles() 401 { 402 return $this->_maxLogFiles; 403 } 404 405 /** 406 * @param integer number of files used for rotation. 407 */ 408 public function setMaxLogFiles($value) 409 { 410 $this->_maxLogFiles=TPropertyValue::ensureInteger($value); 411 if($this->_maxLogFiles<1) 412 throw new TInvalidDataValueException('filelogroute_maxlogfiles_invalid'); 413 } 414 415 /** 416 * Saves log messages in files. 417 * @param array list of log messages 418 */ 419 protected function processLogs($logs) 420 { 421 $logFile=$this->getLogPath().'/'.$this->getLogFile(); 422 if(@filesize($logFile)>$this->_maxFileSize*1024) 423 $this->rotateFiles(); 424 foreach($logs as $log) 425 error_log($this->formatLogMessage($log[0],$log[1],$log[2],$log[3]),3,$logFile); 426 } 427 428 /** 429 * Rotates log files. 430 */ 431 protected function rotateFiles() 432 { 433 $file=$this->getLogPath().'/'.$this->getLogFile(); 434 for($i=$this->_maxLogFiles;$i>0;--$i) 435 { 436 $rotateFile=$file.'.'.$i; 437 if(is_file($rotateFile)) 438 { 439 if($i===$this->_maxLogFiles) 440 unlink($rotateFile); 441 else 442 rename($rotateFile,$file.'.'.($i+1)); 443 } 444 } 445 if(is_file($file)) 446 rename($file,$file.'.1'); 447 } 448 } 449 450 /** 451 * TEmailLogRoute class. 452 * 453 * TEmailLogRoute sends selected log messages to email addresses. 454 * The target email addresses may be specified via {@link setEmails Emails} property. 455 * Optionally, you may set the email {@link setSubject Subject} and the 456 * {@link setSentFrom SentFrom} address. 457 * 458 * @author Qiang Xue <qiang.xue@gmail.com> 459 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 460 * @package System.Util 461 * @since 3.0 462 */ 463 class TEmailLogRoute extends TLogRoute 464 { 465 /** 466 * Regex pattern for email address. 467 */ 468 const EMAIL_PATTERN='/^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$/'; 469 /** 470 * Default email subject. 471 */ 472 const DEFAULT_SUBJECT='Prado Application Log'; 473 /** 474 * @var array list of destination email addresses. 475 */ 476 private $_emails=array(); 477 /** 478 * @var string email subject 479 */ 480 private $_subject=''; 481 /** 482 * @var string email sent from address 483 */ 484 private $_from=''; 485 486 /** 487 * Initializes the route. 488 * @param TXmlElement configurations specified in {@link TLogRouter}. 489 * @throws TConfigurationException if {@link getSentFrom SentFrom} is empty and 490 * 'sendmail_from' in php.ini is also empty. 491 */ 492 public function init($config) 493 { 494 if($this->_from==='') 495 $this->_from=ini_get('sendmail_from'); 496 if($this->_from==='') 497 throw new TConfigurationException('emaillogroute_sentfrom_required'); 498 } 499 500 /** 501 * Sends log messages to specified email addresses. 502 * @param array list of log messages 503 */ 504 protected function processLogs($logs) 505 { 506 $message=''; 507 foreach($logs as $log) 508 $message.=$this->formatLogMessage($log[0],$log[1],$log[2],$log[3]); 509 $message=wordwrap($message,70); 510 foreach($this->_emails as $email) 511 mail($email,$this->getSubject(),$message,"From:{$this->_from}\r\n"); 512 513 } 514 515 /** 516 * @return array list of destination email addresses 517 */ 518 public function getEmails() 519 { 520 return $this->_emails; 521 } 522 523 /** 524 * @return array|string list of destination email addresses. If the value is 525 * a string, it is assumed to be comma-separated email addresses. 526 */ 527 public function setEmails($emails) 528 { 529 if(is_array($emails)) 530 $this->_emails=$emails; 531 else 532 { 533 $this->_emails=array(); 534 foreach(explode(',',$emails) as $email) 535 { 536 $email=trim($email); 537 if(preg_match(self::EMAIL_PATTERN,$email)) 538 $this->_emails[]=$email; 539 } 540 } 541 } 542 543 /** 544 * @return string email subject. Defaults to TEmailLogRoute::DEFAULT_SUBJECT 545 */ 546 public function getSubject() 547 { 548 if($this->_subject===null) 549 $this->_subject=self::DEFAULT_SUBJECT; 550 return $this->_subject; 551 } 552 553 /** 554 * @param string email subject. 555 */ 556 public function setSubject($value) 557 { 558 $this->_subject=$value; 559 } 560 561 /** 562 * @return string send from address of the email 563 */ 564 public function getSentFrom() 565 { 566 return $this->_from; 567 } 568 569 /** 570 * @param string send from address of the email 571 */ 572 public function setSentFrom($value) 573 { 574 $this->_from=$value; 575 } 576 } 577 578 /** 579 * TBrowserLogRoute class. 580 * 581 * TBrowserLogRoute prints selected log messages in the response. 582 * 583 * @author Xiang Wei Zhuo <weizhuo[at]gmail[dot]com> 584 * @version $Id: TLogRouter.php 1397 2006-09-07 07:55:53Z wei $ 585 * @package System.Util 586 * @since 3.0 587 */ 588 class TBrowserLogRoute extends TLogRoute 589 { 590 public function processLogs($logs) 591 { 592 if(empty($logs) || $this->getApplication()->getMode()==='Performance') return; 593 $first = $logs[0][3]; 594 $even = true; 595 $response = $this->getApplication()->getResponse(); 596 $response->write($this->renderHeader()); 597 for($i=0,$n=count($logs);$i<$n;++$i) 598 { 599 if ($i<$n-1) 600 { 601 $timing['delta'] = $logs[$i+1][3] - $logs[$i][3]; 602 $timing['total'] = $logs[$i+1][3] - $first; 603 } 604 else 605 { 606 $timing['delta'] = '?'; 607 $timing['total'] = $logs[$i][3] - $first; 608 } 609 $timing['even'] = !($even = !$even); 610 $response->write($this->renderMessage($logs[$i],$timing)); 611 } 612 $response->write($this->renderFooter()); 613 } 614 615 protected function renderHeader() 616 { 617 $string = <<<EOD 618 <table cellspacing="0" cellpadding="2" border="0" width="100%"> 619 <tr> 620 <th style="background-color: black; color:white;" colspan="11"> 621 Application Log 622 </th> 623 </tr><tr style="background-color: #ccc;"> 624 <th> </th> 625 <th>Category</th><th>Message</th><th>Time Spent (s)</th><th>Cumulated Time Spent (s)</th> 626 </tr> 627 EOD; 628 return $string; 629 } 630 631 protected function renderMessage($log, $info) 632 { 633 $bgcolor = $info['even'] ? "#fff" : "#eee"; 634 $total = sprintf('%0.6f', $info['total']); 635 $delta = sprintf('%0.6f', $info['delta']); 636 $color = $this->getColorLevel($log[1]); 637 $msg = preg_replace('/\(line[^\)]+\)$/','',$log[0]); //remove line number info 638 $msg = THttpUtility::htmlEncode($msg); 639 $string = <<<EOD 640 <tr style="background-color: {$bgcolor};"> 641 <td style="border:1px solid silver;background-color: $color;"> </td> 642 <td>{$log[2]}</td> 643 <td>{$msg}</td> 644 <td style="text-align:center">{$delta}</td> 645 <td style="text-align:center">{$total}</td> 646 </tr> 647 EOD; 648 return $string; 649 } 650 651 protected function getColorLevel($level) 652 { 653 switch($level) 654 { 655 case TLogger::DEBUG: return 'green'; 656 case TLogger::INFO: return 'black'; 657 case TLogger::NOTICE: return '#3333FF'; 658 case TLogger::WARNING: return '#33FFFF'; 659 case TLogger::ERROR: return '#ff9933'; 660 case TLogger::ALERT: return '#ff00ff'; 661 case TLogger::FATAL: return 'red'; 662 } 663 return ''; 664 } 665 666 protected function renderFooter() 667 { 668 $string = "<tr><td colspan=\"11\" style=\"text-align:center; border-top: 1px solid #ccc; padding:0.2em;\">"; 669 foreach(self::$_levelValues as $name => $level) 670 { 671 $string .= "<span style=\"color:white;background-color:".$this->getColorLevel($level); 672 $string .= ";margin: 0.5em;\">".strtoupper($name)."</span>"; 673 } 674 $string .= "</td></tr></table>"; 675 return $string; 676 } 677 } 678 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 21:07:04 2007 | par Balluche grâce à PHPXref 0.7 |