PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/susuka/log/Log.php

https://bitbucket.org/tierai/susuka
PHP | 109 lines | 84 code | 12 blank | 13 comment | 17 complexity | 824254c1b95d82d7ac4d38c4baba213b MD5 | raw file
  1. <?php
  2. namespace susuka\log;
  3. if(!defined('SU_LOG_PATH')) define('SU_LOG_PATH', SU_APP_PATH.'/log');
  4. /**
  5. *
  6. * @todo I'm not sure about this yet... logging should be simple and efficient
  7. *
  8. * The general idea is something like:
  9. * if(SOME_CONSTANT) doTheLogging
  10. *
  11. * Where dotheLogging could be:
  12. * - \suGlobalClass::w(...) <-- This is what we use
  13. * - \suGlobalLogW(...) <-- Clean, but we cant use class magic (more code in autoload)
  14. * - \suGetLogInstance()->w(...) <-- Each log is an instance, more overhead when logging is enabled but ignored by logger (due to threshold)
  15. * and so on...
  16. */
  17. class Log {
  18. protected static $levelMap = array(
  19. SU_LOG_DEBUG => 'DEBUG',
  20. SU_LOG_NOTICE => 'NOTICE',
  21. SU_LOG_WARNING => 'WARNING',
  22. SU_LOG_ERROR => 'ERROR',
  23. );
  24. private static $instances = array();
  25. private $file;
  26. public static function d($format) {
  27. self::_write(SU_LOG_DEBUG, func_get_args());
  28. }
  29. public static function n($format) {
  30. self::_write(SU_LOG_NOTICE, func_get_args());
  31. }
  32. public static function w($format) {
  33. self::_write(SU_LOG_WARNING, func_get_args());
  34. }
  35. public static function e($format) {
  36. self::_write(SU_LOG_ERROR, func_get_args());
  37. }
  38. public static function format($level, $format) {
  39. self::_write($level, func_get_args(), 1);
  40. }
  41. public function __construct($file = null, $threshold = null) {
  42. if($file === null) {
  43. $file = defined('SU_LOGFILE') ? SU_LOGFILE : SU_LOG_PATH.'/app.log';
  44. }
  45. $this->file = $file;
  46. $this->threshold = $threshold === null ? SU_LOG : $threshold;
  47. }
  48. public function write($level, $message) {
  49. $cat = isset(self::$levelMap[$level]) ? self::$levelMap[$level] : 'UNKNOWN';
  50. $cat = str_pad($cat, 10, ' ', STR_PAD_LEFT);
  51. $src = SU_LOG >= SU_LOG_DEBUG ? $this->getSource() : 'UNKNOWN';
  52. $addr = $_SERVER['REMOTE_ADDR'];
  53. $msg = sprintf('%s %s %s %s: %s'.PHP_EOL, date(DATE_ATOM), $cat, $addr, $src, $message);
  54. file_put_contents($this->file, $msg, FILE_APPEND | LOCK_EX);
  55. }
  56. protected function getSource() {
  57. $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  58. for($i = 0; $i < count($bt); $i++) {
  59. $b = $bt[$i];
  60. if(!isset($b['class']) || $b['class'] !== __CLASS__) {
  61. if(isset($b['class']) && isset($b['function']))
  62. return $b['class'].'::'.$b['function'];
  63. else if(isset($b['file']) && isset($b['line']))
  64. return basename($b['file']).':'.$b['line'];
  65. return str_replace("\n", " ", print_r($b, true));
  66. }
  67. }
  68. return 'UNKNOWN';
  69. }
  70. protected static function _write($level, $args, $offset = 0, $instance = null) {
  71. if($level <= SU_LOG) {
  72. if($instance === null) {
  73. $class = get_called_class();
  74. if(!isset(self::$instances[$class])) {
  75. self::$instances[$class] = new $class;
  76. }
  77. $instance = self::$instances[$class];
  78. }
  79. if($level <= $instance->threshold) {
  80. $args = array_slice($args, $offset);
  81. $format = array_shift($args);
  82. foreach($args as &$arg) {
  83. if(is_array($arg)) {
  84. $arg = print_r($arg, true);
  85. $arg = substr($arg, 6); // Remove Array
  86. $arg = str_replace(' ', '', $arg);
  87. } else if(is_bool($arg)) {
  88. $arg = $arg ? 'true' : 'false';
  89. }
  90. $arg = str_replace(PHP_EOL, ' ', $arg);
  91. }
  92. $message = vsprintf($format, $args);
  93. $instance->write($level, $message);
  94. }
  95. }
  96. }
  97. }