| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 | <?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]// +----------------------------------------------------------------------// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.// +----------------------------------------------------------------------// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )// +----------------------------------------------------------------------// | Author: liu21st <liu21st@gmail.com>// +----------------------------------------------------------------------namespace think\log\driver;use think\App;use think\Request;/** * 本地化调试输出到文件 */class File{    protected $config = [        'time_format' => ' c ',        'single'      => false,        'file_size'   => 2097152,        'path'        => LOG_PATH,        'apart_level' => [],        'max_files'   => 0,        'json'        => false,    ];    // 实例化并传入参数    public function __construct($config = [])    {        if (is_array($config)) {            $this->config = array_merge($this->config, $config);        }    }    /**     * 日志写入接口     * @access public     * @param  array    $log 日志信息     * @param  bool     $append 是否追加请求信息     * @return bool     */    public function save(array $log = [], $append = false)    {        $destination = $this->getMasterLogFile();        $path = dirname($destination);        !is_dir($path) && mkdir($path, 0755, true);        $info = [];        foreach ($log as $type => $val) {            foreach ($val as $msg) {                if (!is_string($msg)) {                    $msg = var_export($msg, true);                }                $info[$type][] = $this->config['json'] ? $msg : '[ ' . $type . ' ] ' . $msg;            }            if (!$this->config['json'] && (true === $this->config['apart_level'] || in_array($type, $this->config['apart_level']))) {                // 独立记录的日志级别                $filename = $this->getApartLevelFile($path, $type);                $this->write($info[$type], $filename, true, $append);                unset($info[$type]);            }        }        if ($info) {            return $this->write($info, $destination, false, $append);        }        return true;    }    /**     * 获取主日志文件名     * @access public     * @return string     */    protected function getMasterLogFile()    {        $cli = PHP_SAPI == 'cli' ? '_cli' : '';        if ($this->config['single']) {            $name        = is_string($this->config['single']) ? $this->config['single'] : 'single';            $destination = $this->config['path'] . $name . $cli . '.log';        } else {            if ($this->config['max_files']) {                $filename = date('Ymd') . $cli . '.log';                $files    = glob($this->config['path'] . '*.log');                try {                    if (count($files) > $this->config['max_files']) {                        unlink($files[0]);                    }                } catch (\Exception $e) {                }            } else {                $filename = date('Ym') . DIRECTORY_SEPARATOR . date('d') . $cli . '.log';            }            $destination = $this->config['path'] . $filename;        }        return $destination;    }    /**     * 获取独立日志文件名     * @access public     * @param  string $path 日志目录     * @param  string $type 日志类型     * @return string     */    protected function getApartLevelFile($path, $type)    {        $cli = PHP_SAPI == 'cli' ? '_cli' : '';        if ($this->config['single']) {            $name = is_string($this->config['single']) ? $this->config['single'] : 'single';        } elseif ($this->config['max_files']) {            $name = date('Ymd');        } else {            $name = date('d');        }        return $path . DIRECTORY_SEPARATOR . $name . '_' . $type . $cli . '.log';    }    /**     * 日志写入     * @access protected     * @param  array     $message 日志信息     * @param  string    $destination 日志文件     * @param  bool      $apart 是否独立文件写入     * @param  bool      $append 是否追加请求信息     * @return bool     */    protected function write($message, $destination, $apart = false, $append = false)    {        // 检测日志文件大小,超过配置大小则备份日志文件重新生成        $this->checkLogSize($destination);        // 日志信息封装        $info['timestamp'] = date($this->config['time_format']);        foreach ($message as $type => $msg) {            $msg = is_array($msg) ? implode("\r\n", $msg) : $msg;            if (PHP_SAPI == 'cli') {                $info['msg']  = $msg;                $info['type'] = $type;            } else {                $info[$type] = $msg;            }        }        if (PHP_SAPI == 'cli') {            $message = $this->parseCliLog($info);        } else {            // 添加调试日志            $this->getDebugLog($info, $append, $apart);            $message = $this->parseLog($info);        }        return error_log($message, 3, $destination);    }    /**     * 检查日志文件大小并自动生成备份文件     * @access protected     * @param  string    $destination 日志文件     * @return void     */    protected function checkLogSize($destination)    {        if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) {            try {                rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination));            } catch (\Exception $e) {            }        }    }    /**     * CLI日志解析     * @access protected     * @param  array     $info 日志信息     * @return string     */    protected function parseCliLog($info)    {        if ($this->config['json']) {            $message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n";        } else {            $now = $info['timestamp'];            unset($info['timestamp']);            $message = implode("\r\n", $info);            $message = "[{$now}]" . $message . "\r\n";        }        return $message;    }    /**     * 解析日志     * @access protected     * @param  array     $info 日志信息     * @return string     */    protected function parseLog($info)    {        $request     = Request::instance();        $requestInfo = [            'ip'     => $request->ip(),            'method' => $request->method(),            'host'   => $request->host(),            'uri'    => $request->url(),        ];        if ($this->config['json']) {            $info = $requestInfo + $info;            return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n";        }        array_unshift($info, "---------------------------------------------------------------\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}");        unset($info['timestamp']);        return implode("\r\n", $info) . "\r\n";    }    protected function getDebugLog(&$info, $append, $apart)    {        if (App::$debug && $append) {            if ($this->config['json']) {                // 获取基本信息                $runtime = round(microtime(true) - THINK_START_TIME, 10);                $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';                $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);                $info = [                    'runtime' => number_format($runtime, 6) . 's',                    'reqs'    => $reqs . 'req/s',                    'memory'  => $memory_use . 'kb',                    'file'    => count(get_included_files()),                ] + $info;            } elseif (!$apart) {                // 增加额外的调试信息                $runtime = round(microtime(true) - THINK_START_TIME, 10);                $reqs    = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';                $memory_use = number_format((memory_get_usage() - THINK_START_MEM) / 1024, 2);                $time_str   = '[运行时间:' . number_format($runtime, 6) . 's] [吞吐率:' . $reqs . 'req/s]';                $memory_str = ' [内存消耗:' . $memory_use . 'kb]';                $file_load  = ' [文件加载:' . count(get_included_files()) . ']';                array_unshift($info, $time_str . $memory_str . $file_load);            }        }    }}
 |