Logs.Class.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. namespace Mall\Framework\Core;
  3. class Logs
  4. {
  5. const LEVEL_TRACE = 'trace';
  6. const LEVEL_WARNING = 'warning';
  7. const LEVEL_ERROR = 'error';
  8. const LEVEL_INFO = 'info';
  9. const LEVEL_PROFILE = 'profile';
  10. const MAX_LOGS = 10000;
  11. public $rotateByCopy = true;
  12. public $maxLogFiles = 5;
  13. public $maxFileSize = 100; // in MB
  14. //系统日志标识
  15. private $logSystem = 'swoole-jobs';
  16. private $logPath = '';
  17. //单个类型log
  18. private $logs = [];
  19. private $logCount = 0;
  20. //默认log文件存储名
  21. private $logSaveFileApp = 'application.log';
  22. private static $instance=null;
  23. public function __construct($logPath, $logSaveFileApp='', $logSystem = '')
  24. {
  25. if (empty($logPath)) {
  26. die('config logPath must be set!' . PHP_EOL);
  27. }
  28. if (!is_dir($logPath)) {
  29. mkdir($logPath, '0777', true);
  30. }
  31. $this->logPath = $logPath;
  32. if ($logSaveFileApp) {
  33. $this->logSaveFileApp = $logSaveFileApp;
  34. }
  35. $logSystem && $this->logSystem = $logSystem;
  36. }
  37. static public function getInstance($logPath='', $logSaveFileApp='', $logSystem = '')
  38. {
  39. $key = md5('logs');
  40. if (isset(self::$instance[$key]) && self::$instance[$key] !== null) {
  41. return self::$instance[$key];
  42. }
  43. self::$instance[$key] = new self($logPath, $logSaveFileApp, $logSystem);
  44. return self::$instance[$key];
  45. }
  46. /**
  47. * 格式化日志信息.
  48. *
  49. * @param mixed $message
  50. * @param mixed $level
  51. * @param mixed $category
  52. * @param mixed $time
  53. */
  54. public function formatLogMessage($message, $level, $category, $time)
  55. {
  56. return @date('Y/m/d H:i:s', $time) . "$this->logSystem [$level] [$category] \n $message \n";
  57. }
  58. /**
  59. * 日志分类处理.
  60. *
  61. * @param mixed $message
  62. * @param mixed $level
  63. * @param mixed $category
  64. * @param mixed $flush
  65. */
  66. public function log($message, $level = 'info', $category = '', $flush = true)
  67. {
  68. if( defined('QUEUE_RUNLOG') && !LOG_ERROR ){
  69. return;
  70. }
  71. if (empty($category)) {
  72. $category=$this->logSaveFileApp;
  73. }
  74. $this->logs[$category][] = [$message, $level, $category, microtime(true)];
  75. $this->logCount++;
  76. if ($this->logCount >= self::MAX_LOGS || true == $flush) {
  77. $this->flush($category);
  78. }
  79. }
  80. /**
  81. * 日志分类处理.
  82. */
  83. public function processLogs()
  84. {
  85. $logsAll=[];
  86. foreach ((array) $this->logs as $key => $logs) {
  87. $logsAll[$key] = '';
  88. foreach ((array) $logs as $log) {
  89. $logsAll[$key] .= $this->formatLogMessage($log[0], $log[1], $log[2], $log[3]);
  90. }
  91. }
  92. return $logsAll;
  93. }
  94. /**
  95. * 写日志到文件.
  96. */
  97. public function flush()
  98. {
  99. if ($this->logCount <= 0) {
  100. return false;
  101. }
  102. $logsAll = $this->processLogs();
  103. $this->write($logsAll);
  104. $this->logs = [];
  105. $this->logCount = 0;
  106. }
  107. /**
  108. * [write 根据日志类型写到不同的日志文件].
  109. *
  110. * @param $logsAll
  111. *
  112. * @throws \Exception
  113. */
  114. public function write($logsAll)
  115. {
  116. if (empty($logsAll)) {
  117. return;
  118. }
  119. //$this->logPath = ROOT_PATH . 'src/runtime/';
  120. if (!is_dir($this->logPath)) {
  121. self::mkdir($this->logPath, [], true);
  122. }
  123. foreach ($logsAll as $key => $value) {
  124. if (empty($key)) {
  125. continue;
  126. }
  127. $fileName = $this->logPath . '/' . $key;
  128. if (($fp = @fopen($fileName, 'a')) === false) {
  129. throw new \Exception("Unable to append to log file: {$fileName}");
  130. }
  131. @flock($fp, LOCK_EX);
  132. if (@filesize($fileName) > $this->maxFileSize * 1024 * 1024) {
  133. $this->rotateFiles($fileName);
  134. }
  135. @fwrite($fp, $value);
  136. @flock($fp, LOCK_UN);
  137. @fclose($fp);
  138. }
  139. }
  140. /**
  141. * Rotates log files.
  142. *
  143. * @param mixed $file
  144. */
  145. protected function rotateFiles($file)
  146. {
  147. for ($i = $this->maxLogFiles; $i >= 0; --$i) {
  148. // $i == 0 is the original log file
  149. $rotateFile = $file . ($i === 0 ? '' : '.' . $i);
  150. //var_dump($rotateFile);
  151. if (is_file($rotateFile)) {
  152. // suppress errors because it's possible multiple processes enter into this section
  153. if ($i === $this->maxLogFiles) {
  154. @unlink($rotateFile);
  155. } else {
  156. if ($this->rotateByCopy) {
  157. @copy($rotateFile, $file . '.' . ($i + 1));
  158. if ($fp = @fopen($rotateFile, 'a')) {
  159. @ftruncate($fp, 0);
  160. @fclose($fp);
  161. }
  162. } else {
  163. @rename($rotateFile, $file . '.' . ($i + 1));
  164. }
  165. }
  166. }
  167. }
  168. }
  169. /**
  170. * Shared environment safe version of mkdir. Supports recursive creation.
  171. * For avoidance of umask side-effects chmod is used.
  172. *
  173. * @param string $dst path to be created
  174. * @param array $options newDirMode element used, must contain access bitmask
  175. * @param bool $recursive whether to create directory structure recursive if parent dirs do not exist
  176. *
  177. * @return bool result of mkdir
  178. *
  179. * @see mkdir
  180. */
  181. private static function mkdir($dst, array $options, $recursive)
  182. {
  183. $prevDir = dirname($dst);
  184. if ($recursive && !is_dir($dst) && !is_dir($prevDir)) {
  185. self::mkdir(dirname($dst), $options, true);
  186. }
  187. $mode = isset($options['newDirMode']) ? $options['newDirMode'] : 0777;
  188. $res = mkdir($dst, $mode, $recursive);
  189. @chmod($dst, $mode);
  190. return $res;
  191. }
  192. }