PageRenderTime 28ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/functions/logger.class.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 1075 lines | 761 code | 133 blank | 181 comment | 95 complexity | 9b0873520e5aa145df4a21dc9da85e4a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * TestLink Open Source Project - http://testlink.sourceforge.net/
  4. * This script is distributed under the GNU General Public License 2 or later.
  5. *
  6. * Log Functions
  7. *
  8. * A great way to debug is through logging. It's even easier if you can leave
  9. * the log messages through your code and turn them on and off with a single command.
  10. * To facilitate this we will create a number of logging functions.
  11. *
  12. * @package TestLink
  13. * @author Andreas Morsing
  14. * @copyright 2005-2009, TestLink community
  15. * @version CVS: $Id: logger.class.php,v 1.49 2010/08/23 21:43:24 franciscom Exp $
  16. * @link http://www.teamst.org
  17. * @since 1.8
  18. *
  19. * @internal Revisions:
  20. *
  21. * 20100823 - franciscom - BUGID 3656 - reopened crash when using table prefix
  22. * 20100808 - franciscom - BUGID 3656 - crash on some DBMS due to Transactions instead of transactions
  23. * 20091005 - amitkhullar - improved function getEventsFor() - BUG 2862
  24. * 20090603 - franciscom - adding table prefix management
  25. * 20080517 - franciscom - exclude mktime() logs
  26. * 20080316 - franciscom - added getEnableLoggingStatus() methods
  27. * refactored access to enable logging status info.
  28. * refactored enable/disable logging
  29. * Added code to configure individual loggers using new config $g_loggerCfg
  30. * 20080315 - franciscom - discovered bug on tlTransaction->writeToDB thanks to POSTGRES
  31. * watchPHPErrors() - added new error to suppress
  32. * 20080216 - franciscom - limit length of entryPoint
  33. *
  34. **/
  35. /**
  36. * @package TestLink
  37. */
  38. class tlLogger extends tlObject
  39. {
  40. /**
  41. * Log levels
  42. * There are 5 logging levels available. Log messages will only be displayed
  43. * if they are at a level less verbose than that currently set. So, we can turn
  44. * on logging with the following command:
  45. *
  46. */
  47. const ERROR = 1;
  48. const WARNING = 2;
  49. const INFO = 4;
  50. const DEBUG = 8;
  51. const AUDIT = 16;
  52. static $logLevels = null;
  53. static $revertedLogLevels = null;
  54. /** @var boolean to enable/disable loggin for all loggers */
  55. protected $doLogging = true;
  56. // must be changed is db field len changes
  57. const ENTRYPOINT_MAX_LEN = 45;
  58. //the one and only logger of TesTLink
  59. private static $s_instance;
  60. //all transactions, at the moment there is only one transaction supported,
  61. //could be extended if we need more
  62. protected $transactions = null;
  63. //the logger which are controlled
  64. protected $loggers = null;
  65. //log only event which pass the filter,
  66. /** @TODO SCHLUNDUS: should use $g_log_level */
  67. protected $logLevelFilter = null;
  68. protected $eventManager;
  69. public function __construct(&$db)
  70. {
  71. parent::__construct();
  72. $this->loggers['db'] = new tlDBLogger($db);
  73. $this->loggers['file'] = new tlFileLogger();
  74. $this->setLogLevelFilter(self::ERROR | self::WARNING | self::AUDIT);
  75. $this->eventManager = tlEventManager::create($db);
  76. }
  77. public function __destruct()
  78. {
  79. parent::__destruct();
  80. }
  81. public function getAuditEventsFor($objectIDs = null,$objectTypes = null,$activityCodes = null,
  82. $limit = -1,$startTime = null,$endTime = null, $users = null)
  83. {
  84. return $this->eventManager->getEventsFor(tlLogger::AUDIT,$objectIDs,$objectTypes,$activityCodes,
  85. $limit,$startTime,$endTime,$users);
  86. }
  87. public function getEventsFor($logLevels = null,$objectIDs = null,$objectTypes = null,
  88. $activityCodes = null,$limit = -1,$startTime = null,
  89. $endTime = null, $users = null)
  90. {
  91. return $this->eventManager->getEventsFor($logLevels,$objectIDs,$objectTypes,$activityCodes,
  92. $limit,$startTime,$endTime,$users);
  93. }
  94. public function deleteEventsFor($logLevels = null,$startTime = null)
  95. {
  96. return $this->eventManager->deleteEventsFor($logLevels,$startTime);
  97. }
  98. /**
  99. * set the log level filter, only events which matches the filter can pass
  100. * can be combination of any of the tlLogger::LogLevels
  101. */
  102. public function setLogLevelFilter($filter)
  103. {
  104. $this->logLevelFilter = $filter;
  105. foreach($this->loggers as $key => $loggerObj)
  106. {
  107. $this->loggers[$key]->setLogLevelFilter($filter);
  108. }
  109. return tl::OK;
  110. }
  111. /**
  112. * disable logging
  113. *
  114. * @param TBD $logger (optional) default null = all loggers
  115. * string representing a list of keys to access loggers map.
  116. *
  117. */
  118. public function disableLogging($logger = null)
  119. {
  120. if(is_null($logger))
  121. {
  122. $this->doLogging = false;
  123. }
  124. else
  125. {
  126. $loggerSet = explode(",",$logger);
  127. foreach($loggerSet as $idx => $loggerKey)
  128. {
  129. $this->loggers[$loggerKey]->disableLogging();
  130. }
  131. }
  132. }
  133. /**
  134. * enable logging
  135. *
  136. * @param TBD $logger (optional) default null = all loggers
  137. * string representing a list of keys to access loggers map.
  138. *
  139. */
  140. public function enableLogging($logger = null)
  141. {
  142. if(is_null($logger))
  143. {
  144. $this->doLogging = false;
  145. }
  146. else
  147. {
  148. $loggerSet = explode(",",$logger);
  149. foreach($loggerSet as $idx => $loggerKey)
  150. {
  151. $this->loggers[$loggerKey]->enableLogging();
  152. }
  153. }
  154. }
  155. public function getEnableLoggingStatus($logger = null)
  156. {
  157. $status=is_null($logger) ? $this->doLogging : $this->loggers[$logger]->getEnableLoggingStatus();
  158. return $status;
  159. // if(is_null($logger))
  160. // return $this->doLogging;
  161. // else
  162. // return $this->loggers[$logger]->getEnableLoggingStatus();
  163. }
  164. /**
  165. * returns the transaction with the specified name, null else
  166. */
  167. public function getTransaction($name = "DEFAULT")
  168. {
  169. if (isset($this->transactions[$name]))
  170. {
  171. return $this->transactions[$name];
  172. }
  173. return null;
  174. }
  175. /**
  176. * create the logger for TestLink
  177. * @param resource &$db reference to database handler
  178. */
  179. static public function create(&$db)
  180. {
  181. if (!isset(self::$s_instance))
  182. {
  183. //create the logging instance
  184. self::$logLevels = array (self::DEBUG => 'DEBUG', self::INFO => 'INFO',
  185. self::WARNING => 'WARNING', self::ERROR => 'ERROR',
  186. self::AUDIT => 'AUDIT');
  187. self::$revertedLogLevels = array_flip(self::$logLevels);
  188. $c = __CLASS__;
  189. self::$s_instance = new $c($db);
  190. }
  191. return self::$s_instance;
  192. }
  193. /**
  194. * starts a transaction
  195. *
  196. * @internal
  197. * rev: 20080216 - franciscom - entrypoint len limiting
  198. */
  199. public function startTransaction($name = "DEFAULT",$entryPoint = null,$userID = null)
  200. {
  201. //if we have already a transaction with this name, return
  202. if (isset($transactions[$name]))
  203. return tl::ERROR;
  204. if (is_null($entryPoint))
  205. $entryPoint = $_SERVER['SCRIPT_NAME'];
  206. if(strlen($entryPoint) > self::ENTRYPOINT_MAX_LEN)
  207. {
  208. // Important information is at end of string
  209. $entryPoint = substr($entryPoint,-self::ENTRYPOINT_MAX_LEN);
  210. // After limiting we can get thinks like:
  211. // l18/head_20080216/lib/project/projectEdit.php
  212. // in these cases is better (IMHO) write:
  213. // /head_20080216/lib/project/projectEdit.php
  214. //
  215. // search first /
  216. $mypos = strpos($entryPoint,"/");
  217. if(($mypos !== FALSE) && $mypos)
  218. $entryPoint = substr($entryPoint,$mypos);
  219. }
  220. if (is_null($userID))
  221. $userID = isset($_SESSION['currentUser']) ? $_SESSION['currentUser']->dbID : 0;
  222. $sessionID = $userID ? session_id() : null;
  223. $t = new tlTransaction($this->db);
  224. $this->transactions[$name] = &$t;
  225. $t->initialize($this->loggers,$entryPoint,$name,$userID,$sessionID);
  226. return $this->transactions[$name];
  227. }
  228. /**
  229. * ends a transaction
  230. */
  231. public function endTransaction($name = "DEFAULT")
  232. {
  233. if (!isset($this->transactions[$name]))
  234. {
  235. return tl::ERROR;
  236. }
  237. $this->transactions[$name]->close();
  238. unset($this->transactions[$name]);
  239. }
  240. }
  241. /**
  242. * transaction class
  243. * @package TestLink
  244. *
  245. */
  246. class tlTransaction extends tlDBObject
  247. {
  248. //the attached loggers
  249. protected $loggers = null;
  250. public $name = null;
  251. public $entryPoint = null;
  252. public $startTime = null;
  253. public $endTime = null;
  254. public $duration = null;
  255. public $userID = null;
  256. public $sessionID = null;
  257. protected $events = null;
  258. public function __construct(&$db)
  259. {
  260. parent::__construct($db);
  261. }
  262. public function initialize(&$logger,$entryPoint,$name,$userID,$sessionID)
  263. {
  264. $this->loggers = $logger;
  265. $this->name = $name;
  266. $this->entryPoint = $entryPoint;
  267. $this->startTime = time();
  268. $this->userID = $userID;
  269. $this->sessionID = $sessionID;
  270. $this->writeTransaction($this);
  271. tlTimingStart($name);
  272. }
  273. public function __destruct()
  274. {
  275. if (!is_null($this->name))
  276. $this->close();
  277. parent::__destruct();
  278. }
  279. public function _clean($options = self::TLOBJ_O_SEARCH_BY_ID)
  280. {
  281. $this->loggers = null;
  282. $this->name = null;
  283. $this->entryPoint = null;
  284. $this->startTime = null;
  285. $this->userID = null;
  286. $this->sessionID = null;
  287. if (!($options & self::TLOBJ_O_SEARCH_BY_ID))
  288. $this->dbID = null;
  289. }
  290. /*
  291. closes the transaction
  292. */
  293. public function close()
  294. {
  295. $this->endTime = time();
  296. tlTimingStop($this->name);
  297. $this->duration = tlTimingCurrent($this->name);
  298. $result = $this->writeTransaction($this);
  299. $this->name = null;
  300. return $result;
  301. }
  302. //add an event to the transaction the last arguments are proposed for holding information about the objects
  303. public function add($logLevel,$description,$source = null,$activityCode = null,$objectID = null,$objectType = null)
  304. {
  305. $e = new tlEvent();
  306. $e->initialize($this->dbID,$this->userID,$this->sessionID,$logLevel,$description,
  307. $source,$activityCode,$objectID,$objectType);
  308. $this->writeEvent($e);
  309. $this->events[] = $e;
  310. return tl::OK;
  311. }
  312. public function readFromDB(&$db,$options = self::TLOBJ_O_SEARCH_BY_ID)
  313. {
  314. $this->_clean($options);
  315. $query = " SELECT id,entry_point,start_time,end_time,user_id,session_id " .
  316. " FROM {$this->tables['transactions']} ";
  317. $clauses = null;
  318. if ($options & self::TLOBJ_O_SEARCH_BY_ID)
  319. $clauses[] = "id = {$this->dbID}";
  320. if ($clauses)
  321. $query .= " WHERE " . implode(" AND ",$clauses);
  322. $info = $db->fetchFirstRow($query);
  323. if ($info)
  324. {
  325. $this->dbID = $info['id'];
  326. $this->entry_point = $info['entry_point'];
  327. $this->startTime = $info['start_time'];
  328. $this->endTime = $info['end_time'];
  329. $this->userID = $info['user_id'];
  330. $this->sessionID = $info['session_id'];
  331. }
  332. return $info ? tl::OK : tl::ERROR;
  333. }
  334. public function writeToDB(&$db)
  335. {
  336. if (!$this->dbID)
  337. {
  338. $entryPoint = $db->prepare_string($this->entryPoint);
  339. $startTime = $db->prepare_int(time());
  340. $endTime = $db->prepare_int(0);
  341. $userID = $db->prepare_int($this->userID);
  342. $sessionID = "NULL";
  343. if (!is_null($this->sessionID))
  344. {
  345. $sessionID = "'".$db->prepare_string($this->sessionID)."'";
  346. }
  347. $query = "INSERT INTO {$this->tables['transactions']} " .
  348. "(entry_point,start_time,end_time,user_id,session_id) " .
  349. "VALUES ('{$entryPoint}',{$startTime},{$endTime},{$userID},{$sessionID})";
  350. $result = $db->exec_query($query);
  351. if ($result)
  352. {
  353. $this->dbID = $db->insert_id($this->tables['transactions']);
  354. }
  355. }
  356. else
  357. {
  358. $endTime = $db->prepare_int(time());
  359. $query = "UPDATE {$this->tables['transactions']} SET end_time = {$endTime} WHERE id = {$this->dbID}";
  360. $result = $db->exec_query($query);
  361. }
  362. return $result ? tl::OK : tl::ERROR;
  363. }
  364. public function deleteFromDB(&$db)
  365. {
  366. return self::handleNotImplementedMethod(__FUNCTION__);
  367. }
  368. protected function writeEvent(&$e)
  369. {
  370. foreach($this->loggers as $key => $loggerObj)
  371. {
  372. $this->loggers[$key]->writeEvent($e);
  373. }
  374. return tl::OK;
  375. }
  376. protected function writeTransaction(&$t)
  377. {
  378. foreach($this->loggers as $key => $loggerObj)
  379. {
  380. $this->loggers[$key]->writeTransaction($t);
  381. }
  382. return tl::OK;
  383. }
  384. static public function getByID(&$db,$id,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  385. {
  386. return tlDBObject::createObjectFromDB($db,$id,__CLASS__,tlEvent::TLOBJ_O_SEARCH_BY_ID,$detailLevel);
  387. }
  388. static public function getByIDs(&$db,$ids,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  389. {
  390. return self::handleNotImplementedMethod(__FUNCTION__);
  391. }
  392. static public function getAll(&$db,$whereClause = null,$column = null,$orderBy = null,
  393. $detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  394. {
  395. return self::handleNotImplementedMethod(__FUNCTION__);
  396. }
  397. }
  398. /**
  399. * @package TestLink
  400. */
  401. class tlEventManager extends tlObjectWithDB
  402. {
  403. private static $s_instance;
  404. public function __construct(&$db)
  405. {
  406. parent::__construct($db);
  407. }
  408. public static function create(&$db)
  409. {
  410. if (!isset(self::$s_instance))
  411. {
  412. $c = __CLASS__;
  413. self::$s_instance = new $c($db);
  414. }
  415. return self::$s_instance;
  416. }
  417. /*
  418. function:
  419. args:
  420. returns:
  421. rev: 20080514 - franciscom - added empty() to avoid crash
  422. */
  423. public function getEventsFor($logLevels = null,$objectIDs = null,$objectTypes = null,
  424. $activityCodes = null,$limit = -1,$startTime = null,
  425. $endTime = null, $users = null)
  426. {
  427. $clauses = null;
  428. $usersFilter = null;
  429. if (!is_null($logLevels))
  430. {
  431. $logLevels = (array) $logLevels;
  432. $logLevels = implode(",",$logLevels);
  433. $clauses[] = "log_level IN ({$logLevels})";
  434. }
  435. if (!is_null($objectIDs) && !empty($objectIDs))
  436. {
  437. $objectIDs = (array) $objectIDs;
  438. $objectIDs = implode(",",$objectIDs);
  439. $clauses[] = "object_id IN ({$objectIDs})";
  440. }
  441. if (!is_null($objectTypes) && !empty($objectTypes) )
  442. {
  443. $objectTypes = (array) $objectTypes;
  444. $objectTypes = $this->db->prepare_string(implode("','",$objectTypes));
  445. $clauses[] = "object_type IN ('{$objectTypes}')";
  446. }
  447. if (!is_null($activityCodes))
  448. {
  449. $activityCodes = (array) $activityCodes;
  450. $activityCodes = "('".implode("','",$activityCodes)."')";
  451. $clauses[] = "activity IN {$activityCodes}";
  452. }
  453. if (!is_null($startTime))
  454. {
  455. $clauses[] = "fired_at >= {$startTime}";
  456. }
  457. if (!is_null($endTime))
  458. {
  459. $clauses[] = "fired_at <= {$endTime}";
  460. }
  461. if (!is_null($users))
  462. {
  463. // BUGID 3656
  464. $usersFilter = " JOIN {$this->tables['transactions']} T ON T.id = E.transaction_id AND T.user_id IN ({$users}) ";
  465. }
  466. $query = "SELECT E.id FROM {$this->tables['events']} E {$usersFilter}";
  467. if ($clauses)
  468. {
  469. $query .= " WHERE " . implode(" AND ",$clauses);
  470. }
  471. $query .= " ORDER BY transaction_id DESC,fired_at DESC";
  472. return tlEvent::createObjectsFromDBbySQL($this->db,$query,'id',"tlEvent",true,
  473. tlEvent::TLOBJ_O_GET_DETAIL_FULL,$limit);
  474. }
  475. function deleteEventsFor($logLevels = null,$startTime = null)
  476. {
  477. $clauses = null;
  478. if (!is_null($logLevels))
  479. {
  480. $logLevels = (array) $logLevels;
  481. $logLevels = implode(",",$logLevels);
  482. $clauses[] = "log_level IN ({$logLevels})";
  483. }
  484. if (!is_null($startTime))
  485. {
  486. $clauses[] = "fired_at < {$startTime}";
  487. }
  488. $query = "DELETE FROM {$this->tables['events']} ";
  489. if ($clauses)
  490. {
  491. $query .= " WHERE " . implode(" AND ",$clauses);
  492. }
  493. $this->db->exec_query($query);
  494. $query = "SELECT id FROM {$this->tables['transactions']} t " .
  495. "WHERE (SELECT COUNT(0) FROM {$this->tables['events']} e WHERE e.transaction_id = t.id) = 0";
  496. $transIDs = $this->db->fetchColumnsIntoArray($query,"id");
  497. if ($transIDs)
  498. {
  499. $transIDs = implode(",",$transIDs);
  500. $query = "DELETE FROM {$this->tables['transactions']} WHERE id IN ({$transIDs})";
  501. $this->db->exec_query($query);
  502. }
  503. }
  504. }
  505. /**
  506. * the event class
  507. * @package TestLink
  508. */
  509. class tlEvent extends tlDBObject
  510. {
  511. public $logLevel = null;
  512. public $description = null;
  513. public $source = null;
  514. public $timestamp = null;
  515. public $userID = null;
  516. public $sessionID = null;
  517. public $transactionID = null;
  518. public $activityCode = null;
  519. public $objectID = null;
  520. public $objectType = null;
  521. public $transaction = null;
  522. //detail leveles @TODO DOCUMENT DETAILS OF WHAT ?
  523. const TLOBJ_O_GET_DETAIL_TRANSACTION = 1;
  524. public function getLogLevel()
  525. {
  526. return tlLogger::$logLevels[$this->logLevel];
  527. }
  528. public function __construct($dbID = null)
  529. {
  530. parent::__construct($dbID);
  531. }
  532. public function _clean($options = self::TLOBJ_O_SEARCH_BY_ID)
  533. {
  534. $this->logLevel = null;
  535. $this->description = null;
  536. $this->source = null;
  537. $this->timestamp = null;
  538. $this->userID = null;
  539. $this->sessionID = null;
  540. $this->source = null;
  541. $this->objectID = null;
  542. $this->objectType = null;
  543. $this->transaction = null;
  544. if (!($options & self::TLOBJ_O_SEARCH_BY_ID))
  545. $this->dbID = null;
  546. }
  547. public function initialize($transactionID,$userID,$sessionID,$logLevel,$description,
  548. $source = null,$activityCode = null,$objectID = null,$objectType = null)
  549. {
  550. $this->timestamp = time();
  551. $this->transactionID = $transactionID;
  552. $this->userID = $userID;
  553. $this->sessionID = $sessionID;
  554. $this->logLevel = $logLevel;
  555. $this->description = $description;
  556. $this->source = $source;
  557. $this->activityCode = $activityCode;
  558. $this->objectID = $objectID;
  559. $this->objectType = $objectType;
  560. }
  561. public function readFromDB(&$db,$options = self::TLOBJ_O_SEARCH_BY_ID)
  562. {
  563. $this->_clean($options);
  564. $query = " SELECT id,transaction_id,log_level,source,description,fired_at,object_id,object_type,activity " .
  565. " FROM {$this->tables['events']} ";
  566. $clauses = null;
  567. if ($options & self::TLOBJ_O_SEARCH_BY_ID)
  568. $clauses[] = "id = {$this->dbID}";
  569. if ($clauses)
  570. $query .= " WHERE " . implode(" AND ",$clauses);
  571. $info = $db->fetchFirstRow($query);
  572. if ($info)
  573. {
  574. $this->dbID = $info['id'];
  575. $this->transactionID = $info['transaction_id'];
  576. $this->logLevel = $info['log_level'];
  577. $this->source = $info['source'];
  578. $this->description = $info['source'];
  579. if( ($tmp = tlMetaString::unserialize($info['description'])) )
  580. {
  581. $this->description = $tmp;
  582. }
  583. $this->timestamp = $info['fired_at'];
  584. $this->objectID = $info['object_id'];
  585. $this->objectType = $info['object_type'];
  586. $this->activityCode = $info['activity'];
  587. if ($this->transactionID && $options & self::TLOBJ_O_GET_DETAIL_TRANSACTION)
  588. {
  589. $this->transaction = tlTransaction::getByID($db,$this->transactionID,self::TLOBJ_O_GET_DETAIL_MINIMUM);
  590. if ($this->transaction)
  591. {
  592. $this->userID = $this->transaction->userID;
  593. $this->sessionID = $this->transaction->sessionID;
  594. }
  595. }
  596. }
  597. return $info ? tl::OK : tl::ERROR;
  598. }
  599. public function writeToDB(&$db)
  600. {
  601. if (!$this->dbID)
  602. {
  603. $logLevel = $db->prepare_int($this->logLevel);
  604. //this event logger supports tlMetaString and normal strings
  605. if (is_object($this->description))
  606. $description = $this->description->serialize();
  607. else
  608. $description = $this->description;
  609. $description = $db->prepare_string($description);
  610. $source = "NULL";
  611. if (!is_null($this->source))
  612. $source = "'".$db->prepare_string($this->source)."'";
  613. $objectType = "NULL";
  614. if (!is_null($this->objectType))
  615. $objectType = "'".$db->prepare_string($this->objectType)."'";
  616. $activityCode = "NULL";
  617. if (!is_null($this->activityCode))
  618. $activityCode = "'".$db->prepare_string($this->activityCode)."'";
  619. $objectID = "NULL";
  620. if (!is_null($this->objectID))
  621. $objectID = $db->prepare_int($this->objectID);
  622. $firedAt = $db->prepare_int($this->timestamp);
  623. $transactionID = $db->prepare_int($this->transactionID);
  624. $query = "INSERT INTO {$this->tables['events']} (transaction_id,log_level,description,source," .
  625. "fired_at,object_id,object_type,activity) " .
  626. "VALUES ({$transactionID},{$logLevel},'{$description}',{$source}," .
  627. "{$firedAt},{$objectID},{$objectType},{$activityCode})";
  628. $result = $db->exec_query($query);
  629. if ($result)
  630. {
  631. $this->dbID = $db->insert_id($this->tables['events']);
  632. }
  633. }
  634. }
  635. public function deleteFromDB(&$db)
  636. {
  637. return self::handleNotImplementedMethod(__FUNCTION__);
  638. }
  639. static public function getByID(&$db,$id,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  640. {
  641. return tlDBObject::createObjectFromDB($db,$id,__CLASS__,tlEvent::TLOBJ_O_SEARCH_BY_ID,$detailLevel);
  642. }
  643. static public function getByIDs(&$db,$ids,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  644. {
  645. return self::handleNotImplementedMethod(__FUNCTION__);
  646. }
  647. static public function getAll(&$db,$whereClause = null,$column = null,$orderBy = null,
  648. $detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  649. {
  650. return self::handleNotImplementedMethod(__FUNCTION__);
  651. }
  652. }
  653. /**
  654. * class for logging events to datebase event tables
  655. * @package TestLink
  656. */
  657. class tlDBLogger extends tlObjectWithDB
  658. {
  659. protected $logLevelFilter = null;
  660. protected $pendingTransaction = null;
  661. protected $doLogging = true;
  662. public function __construct(&$db)
  663. {
  664. parent::__construct($db);
  665. }
  666. public function _clean()
  667. {
  668. $this->pendingTransaction = null;
  669. }
  670. public function disableLogging()
  671. {
  672. $this->doLogging = false;
  673. }
  674. public function enableLogging()
  675. {
  676. $this->doLogging = true;
  677. }
  678. public function getEnableLoggingStatus()
  679. {
  680. return $this->doLogging;
  681. }
  682. public function writeTransaction(&$t)
  683. {
  684. if ($this->getEnableLoggingStatus() == false)
  685. return tl::OK;
  686. if (!$this->logLevelFilter)
  687. return tl::ERROR;
  688. if ($this->checkDBConnection() < tl::OK)
  689. return tl::ERROR;
  690. //if we get a closed transaction without a dbID then the transaction wasn't stored
  691. //into the db, so we can also ignore this write
  692. if ($t->endTime)
  693. {
  694. $this->pendingTransaction = null;
  695. if ($t->dbID)
  696. {
  697. $this->disableLogging();
  698. $t->writeToDb($this->db);
  699. $this->enableLogging();
  700. }
  701. return tl::OK;
  702. }
  703. else
  704. {
  705. //the db logger only writes transaction if they have at least one event which should be logged
  706. //so we store the transaction for later usage
  707. $this->pendingTransaction = $t;
  708. }
  709. return tl::OK;
  710. }
  711. public function writeEvent(&$e)
  712. {
  713. if (!$this->doLogging)
  714. return tl::OK;
  715. if (!($e->logLevel & $this->logLevelFilter))
  716. return tl::OK;
  717. if ($this->checkDBConnection() < tl::OK)
  718. return tl::ERROR;
  719. // to avoid log, writes related to log logic
  720. $this->disableLogging();
  721. //if we have a pending transaction so we could write it now
  722. if ($this->pendingTransaction)
  723. {
  724. $this->pendingTransaction->writeToDb($this->db);
  725. $e->transactionID = $this->pendingTransaction->dbID;
  726. $this->pendingTransaction = null;
  727. }
  728. $result = $e->writeToDb($this->db);
  729. $this->enableLogging();
  730. return $result;
  731. }
  732. public function setLogLevelFilter($filter)
  733. {
  734. //we should never log DEBUG to db
  735. $this->logLevelFilter = $filter & ~tlLogger::DEBUG;
  736. }
  737. public function checkDBConnection()
  738. {
  739. //check if the DB connection is still valid before writing log entries and try to reattach
  740. if (!$this->db)
  741. {
  742. global $db;
  743. if ($db)
  744. $this->db = &$db;
  745. }
  746. if (!$this->db || !$this->db->db->isConnected())
  747. return tl::ERROR;
  748. return tl::OK;
  749. }
  750. }
  751. /**
  752. * class for logging events to file
  753. * @package TestLink
  754. * @TODO watch the logfile size, display warning / shrink it,....
  755. */
  756. class tlFileLogger extends tlObject
  757. {
  758. static protected $eventFormatString = "\t[%timestamp][%errorlevel][%sessionid][%source]\n\t\t%description\n";
  759. static protected $openTransactionFormatString = "[%prefix][%transactionID][%name][%entryPoint][%startTime]\n";
  760. static protected $closedTransactionFormatString = "[%prefix][%transactionID][%name][%entryPoint][%startTime][%endTime][took %duration secs]\n";
  761. protected $logLevelFilter = null;
  762. protected $doLogging = true;
  763. public function __construct()
  764. {
  765. parent::__construct();
  766. }
  767. public function _clean()
  768. {
  769. }
  770. public function disableLogging()
  771. {
  772. $this->doLogging = false;
  773. }
  774. public function enableLogging()
  775. {
  776. $this->doLogging = true;
  777. }
  778. public function getEnableLoggingStatus()
  779. {
  780. return $this->doLogging;
  781. }
  782. //SCHLUNDUS: maybe i dont' write the transaction stuff to the file?
  783. public function writeTransaction(&$t)
  784. {
  785. if ($this->getEnableLoggingStatus() == false)
  786. return tl::OK;
  787. if (!$this->logLevelFilter)
  788. return;
  789. //build the logfile entry
  790. $subjects = array("%prefix","%transactionID","%name","%entryPoint","%startTime","%endTime","%duration");
  791. $bFinished = $t->endTime ? 1 : 0;
  792. $formatString = $bFinished ? self::$closedTransactionFormatString : self::$openTransactionFormatString;
  793. $replacements = array($bFinished ? "<<" :">>",
  794. $t->getObjectID(),
  795. $t->name,
  796. $t->entryPoint,
  797. gmdate("y/M/j H:i:s",$t->startTime),
  798. $bFinished ? gmdate("y/M/j H:i:s",$t->endTime) : null,
  799. $t->duration,
  800. );
  801. $line = str_replace($subjects,$replacements,$formatString);
  802. return $this->writeEntry(self::getLogFileName(),$line);
  803. }
  804. public function writeEvent(&$e)
  805. {
  806. if (!($e->logLevel & $this->logLevelFilter))
  807. return;
  808. //this event logger supports tlMetaString and normal strings
  809. if (is_object($e->description))
  810. $description = $e->description->localize('en_GB');
  811. else
  812. $description = $e->description;
  813. //build the logfile entry
  814. $subjects = array("%timestamp","%errorlevel","%source","%description","%sessionid");
  815. $replacements = array(gmdate("y/M/j H:i:s",$e->timestamp),
  816. tlLogger::$logLevels[$e->logLevel],
  817. $e->source,$description,
  818. $e->sessionID ? $e->sessionID : "<nosession>");
  819. $line = str_replace($subjects,$replacements,self::$eventFormatString);
  820. $this->writeEntry(self::getLogFileName(),$line);
  821. //audits are also logged to a global audits logfile
  822. if ($e->logLevel == tlLogger::AUDIT)
  823. $this->writeEntry(self::getAuditLogFileName(),$line);
  824. }
  825. protected function writeEntry($fileName,$line)
  826. {
  827. $fd = fopen($fileName,'a+');
  828. if ($fd)
  829. {
  830. fputs($fd,$line);
  831. fclose($fd);
  832. }
  833. }
  834. public function setLogLevelFilter($filter)
  835. {
  836. $this->logLevelFilter = $filter;
  837. }
  838. /**
  839. * the logfilename is dynamic and depends of the user and its session
  840. *
  841. * @return string returns the name of the logfile
  842. **/
  843. static public function getLogFileName()
  844. {
  845. global $tlCfg;
  846. $uID = isset($_SESSION['userID']) ? $_SESSION['userID'] : 0;
  847. return $tlCfg->log_path . 'userlog' . $uID . ".log";
  848. }
  849. /**
  850. * get the file which should be used audit logging
  851. *
  852. * @return string returns the name of the logfile
  853. **/
  854. static public function getAuditLogFileName()
  855. {
  856. global $tlCfg;
  857. return $tlCfg->log_path . "audits.log";
  858. }
  859. /**
  860. * You can empty the log at any time with:
  861. * resetLogFile
  862. * @author Andreas Morsing - logfilenames are dynamic
  863. */
  864. static public function resetLogFile()
  865. {
  866. @unlink($this->getLogFileName());
  867. }
  868. }
  869. /**
  870. * @TODO SCHLUNDUS: idea of a debug "to screen logger", to be defined,
  871. * @package TestLink
  872. */
  873. class tlHTMLLogger
  874. {
  875. }
  876. //create the global TestLink Logger, and open the initial default transaction
  877. global $g_loggerCfg;
  878. $g_tlLogger = tlLogger::create($db);
  879. if( !is_null($g_loggerCfg) )
  880. {
  881. foreach($g_loggerCfg as $loggerKey => $cfgValue)
  882. {
  883. $pfn=$cfgValue['enable'] ? 'enableLogging' : 'disableLogging';
  884. $g_tlLogger->$pfn($loggerKey);
  885. }
  886. }
  887. $g_tlLogger->startTransaction();
  888. set_error_handler("watchPHPErrors");
  889. /**
  890. * include php errors, warnings and notices to TestLink log
  891. *
  892. * @internal
  893. * rev: 20080504 - franciscom - added xmlrpc.inc,xmlrpcs.inc,xmlrpc_wrappers.inc in exclude set
  894. */
  895. function watchPHPErrors($errno, $errstr, $errfile, $errline)
  896. {
  897. $errors = array (
  898. E_USER_NOTICE => "E_USER_NOTICE",
  899. E_USER_WARNING => "E_USER_WARNING",
  900. E_USER_NOTICE => "E_USER_NOTICE",
  901. E_ERROR => "E_ERROR",
  902. E_WARNING => "E_WARNING",
  903. E_NOTICE => "E_NOTICE",
  904. E_STRICT => "E_STRICT"
  905. );
  906. if (isset($errors[$errno]))
  907. {
  908. // suppress some kind of errors
  909. // strftime(),strtotime(),date()
  910. if( ($errno == E_NOTICE && strpos($errstr,"unserialize()") !== false) ||
  911. ($errno == E_NOTICE && strpos($errstr,"ob_end_clean()") !== false) ||
  912. ($errno == E_STRICT && strpos($errstr,"strftime()") !== false) ||
  913. ($errno == E_STRICT && strpos($errstr,"mktime()") !== false) ||
  914. ($errno == E_STRICT && strpos($errstr,"date()") !== false) ||
  915. ($errno == E_STRICT && strpos($errstr,"strtotime()") !== false) ||
  916. ($errno == E_STRICT && strpos($errfile,"xmlrpc.inc") !== false) ||
  917. ($errno == E_STRICT && strpos($errfile,"xmlrpcs.inc") !== false) ||
  918. ($errno == E_STRICT && strpos($errfile,"xmlrpc_wrappers.inc") !== false) ||
  919. (strpos($errfile,"Smarty_Compiler.class.php") !== false) ||
  920. ($errno == E_NOTICE && strpos($errfile,"Config_File.class.php") !== false)
  921. )
  922. {
  923. return;
  924. }
  925. logWarningEvent($errors[$errno]."\n".$errstr." - in ".$errfile." - Line ".$errline,"PHP");
  926. }
  927. }
  928. /**
  929. * we need a save way to shutdown the logger, or the current transaction will not be closed
  930. */
  931. register_shutdown_function("shutdownLogger");
  932. function shutdownLogger()
  933. {
  934. global $g_tlLogger;
  935. if ($g_tlLogger)
  936. $g_tlLogger->endTransaction();
  937. }
  938. ?>