Log.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace think;
  12. use think\exception\ClassNotFoundException;
  13. /**
  14. * Class Log
  15. * @package think
  16. *
  17. * @method void log($msg) static 记录一般日志
  18. * @method void error($msg) static 记录错误日志
  19. * @method void info($msg) static 记录一般信息日志
  20. * @method void sql($msg) static 记录 SQL 查询日志
  21. * @method void notice($msg) static 记录提示日志
  22. * @method void alert($msg) static 记录报警日志
  23. */
  24. class Log
  25. {
  26. const LOG = 'log';
  27. const ERROR = 'error';
  28. const INFO = 'info';
  29. const SQL = 'sql';
  30. const NOTICE = 'notice';
  31. const ALERT = 'alert';
  32. const DEBUG = 'debug';
  33. private static $log_time;
  34. protected static $index = 0;
  35. /**
  36. * @var array 日志信息
  37. */
  38. protected static $log = [];
  39. /**
  40. * @var array 配置参数
  41. */
  42. protected static $config = [];
  43. /**
  44. * @var array 日志类型
  45. */
  46. protected static $type = ['log', 'error', 'info', 'sql', 'notice', 'alert', 'debug'];
  47. /**
  48. * @var log\driver\File|log\driver\Test|log\driver\Socket 日志写入驱动
  49. */
  50. protected static $driver;
  51. /**
  52. * @var string 当前日志授权 key
  53. */
  54. protected static $key;
  55. /**
  56. * 日志初始化
  57. * @access public
  58. * @param array $config 配置参数
  59. * @return void
  60. */
  61. public static function init($config = [])
  62. {
  63. $type = isset($config['type']) ? $config['type'] : 'File';
  64. $class = false !== strpos($type, '\\') ? $type : '\\think\\log\\driver\\' . ucwords($type);
  65. self::$config = $config;
  66. unset($config['type']);
  67. if (class_exists($class)) {
  68. self::$driver = new $class($config);
  69. } else {
  70. throw new ClassNotFoundException('class not exists:' . $class, $class);
  71. }
  72. // 记录初始化信息
  73. App::$debug && Log::record('[ LOG ] INIT ' . $type, 'info');
  74. }
  75. /**
  76. * 获取日志信息
  77. * @access public
  78. * @param string $type 信息类型
  79. * @return array|string
  80. */
  81. public static function getLog($type = '')
  82. {
  83. return $type ? self::$log[$type] : self::$log;
  84. }
  85. /**
  86. * 记录调试信息
  87. * @access public
  88. * @param mixed $msg 调试信息
  89. * @param string $type 信息类型
  90. * @return void
  91. */
  92. public static function record($msg, $type = 'log')
  93. {
  94. self::$log[$type][] = self::getMsg($msg, $type);
  95. // 命令行下面日志写入改进
  96. IS_CLI && self::save();
  97. if (IS_CLI) {
  98. if (is_string($msg)) {
  99. echo $msg."\n";
  100. }else{
  101. echo json_encode($msg, JSON_UNESCAPED_UNICODE)."\n";
  102. }
  103. }
  104. }
  105. /**
  106. * 获取格式化msg
  107. * @param $msg
  108. * @param string $type
  109. * @return array
  110. */
  111. public static function getMsg($msg, $type = 'log')
  112. {
  113. if (!is_string($msg)) {
  114. $msg = json_encode($msg, JSON_UNESCAPED_UNICODE);
  115. }
  116. if (!self::$log_time) {
  117. self::$log_time = THINK_START_TIME;
  118. }
  119. $current_time = microtime(true);
  120. $msg .= " [ FromPreLog:" . number_format($current_time - self::$log_time, 6) . " ]";
  121. self::$log_time = $current_time;
  122. return ['type' => $type, 'msg' => $msg, 'index' => self::$index++];
  123. }
  124. /**
  125. * 获取格式化的待存数据
  126. * @param $log
  127. * @return array
  128. */
  129. public static function getSaveLogs($log)
  130. {
  131. $logs = [];
  132. foreach ($log as $item) {
  133. $logs = array_merge($logs, $item);
  134. }
  135. usort($logs, function ($v1, $v2) {
  136. if ($v1['index'] > $v2['index']) {
  137. return 1;
  138. }
  139. return 0;
  140. });
  141. return $logs;
  142. }
  143. /**
  144. * 清空日志信息
  145. * @access public
  146. * @return void
  147. */
  148. public static function clear()
  149. {
  150. self::$log = [];
  151. }
  152. /**
  153. * 设置当前日志记录的授权 key
  154. * @access public
  155. * @param string $key 授权 key
  156. * @return void
  157. */
  158. public static function key($key)
  159. {
  160. self::$key = $key;
  161. }
  162. /**
  163. * 检查日志写入权限
  164. * @access public
  165. * @param array $config 当前日志配置参数
  166. * @return bool
  167. */
  168. public static function check($config)
  169. {
  170. return !self::$key || empty($config['allow_key']) || in_array(self::$key, $config['allow_key']);
  171. }
  172. /**
  173. * 保存调试信息
  174. * @access public
  175. * @return bool
  176. */
  177. public static function save()
  178. {
  179. // 没有需要保存的记录则直接返回
  180. if (empty(self::$log)) {
  181. return true;
  182. }
  183. is_null(self::$driver) && self::init(Config::get('log'));
  184. // 检测日志写入权限
  185. if (!self::check(self::$config)) {
  186. return false;
  187. }
  188. if (empty(self::$config['level'])) {
  189. // 获取全部日志
  190. $log = self::$log;
  191. if (!App::$debug && isset($log['debug'])) {
  192. unset($log['debug']);
  193. }
  194. } else {
  195. // 记录允许级别
  196. $log = [];
  197. foreach (self::$config['level'] as $level) {
  198. if (isset(self::$log[$level])) {
  199. $log[$level] = self::$log[$level];
  200. }
  201. }
  202. }
  203. $logs = self::getSaveLogs($log);
  204. if ($result = self::$driver->save($logs)) {
  205. self::$log = [];
  206. }
  207. Hook::listen('log_write_done', $log);
  208. return $result;
  209. }
  210. /**
  211. * 实时写入日志信息 并支持行为
  212. * @access public
  213. * @param mixed $msg 调试信息
  214. * @param string $type 信息类型
  215. * @param bool $force 是否强制写入
  216. * @return bool
  217. */
  218. public static function write($msg, $type = 'log', $force = false)
  219. {
  220. $log = self::$log;
  221. // 如果不是强制写入,而且信息类型不在可记录的类别中则直接返回 false 不做记录
  222. if (true !== $force && !empty(self::$config['level']) && !in_array($type, self::$config['level'])) {
  223. return false;
  224. }
  225. // 封装日志信息
  226. $log[$type][] = self::getMsg($msg, $type);
  227. // 监听 log_write
  228. Hook::listen('log_write', $log);
  229. is_null(self::$driver) && self::init(Config::get('log'));
  230. $logs = self::getSaveLogs($log);
  231. // 写入日志
  232. if ($result = self::$driver->save($logs)) {
  233. self::$log = [];
  234. }
  235. return $result;
  236. }
  237. /**
  238. * 静态方法调用
  239. * @access public
  240. * @param string $method 调用方法
  241. * @param mixed $args 参数
  242. * @return void
  243. */
  244. public static function __callStatic($method, $args)
  245. {
  246. if (in_array($method, self::$type)) {
  247. array_push($args, $method);
  248. call_user_func_array('\\think\\Log::record', $args);
  249. }
  250. }
  251. }