<?php标签:function,记录,file,threshold,path,日志,PHP,public From: https://blog.51cto.com/u_13940603/5886222
/**
* @notes: Logging
* @auther: Bin Shi
* @dateTime: 2020/05/13 17:44
*/
class Logging {
/**
* 进程唯一ID
*
* @var string
*/
private $uniqid = null;
/**
* 日志根路径
*
* @var string
*/
private $path = '';
/**
* 日志缓冲区
*
* @var array
*/
private $logs = array();
/**
* 日志缓冲数量阈值
*
* @var int
*/
private $threshold = 100;
/**
* 日志缓冲时间间隔(单位:秒)
*
* @var int
*/
private $interval = 600;
/**
* 把日志缓冲区里的日志写入文件的时间(Unix 时间戳)
*
* @var int
*/
private $dumpTime = 0;
/**
* 自动清理多久以前的日志文件(单位:秒) 30天自动清理
*
* @var int
*/
private $cleanCycle = 2592000;
private static $instance;
/**
* 单例模式
*
* @return self
*/
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
public function __construct() {
$this->uniqid = uniqid();
$this->path = rtrim('/root/project/', '/');
if (!is_dir($this->path)) {
@mkdir($this->path, 0777, true);
}
}
public function __destruct() {
$this->dump();
}
/**
* 获取日志缓冲数量阈值
*
* @return int 日志缓冲数量阈值
*/
public function getThreshold() {
return $this->threshold;
}
/**
* 设置日志缓冲数量阈值
*
* @param int $threshold
*/
public function setThreshold($threshold) {
$this->threshold = $threshold;
}
/**
* 获取自动清理多久以前的日志文件(单位:秒)
*
* @return int 自动清理多久以前的日志文件(单位:秒)
*/
public function getCleanCycle() {
return $this->cleanCycle;
}
/**
* 设置自动清理多久以前的日志文件(单位:秒)
*
* @param int $cleanCycle
*/
public function setCleanCycle($cleanCycle) {
$this->cleanCycle = $cleanCycle;
}
/**
* 写入日志
*
* @param mixed $message 日志消息
* @param string $module 日志模块目录,默认为 default
* @param string $level 日志级别,包括:
* - debug:调试日志
* - info: 信息日志(默认)
* - notice: 通知日志
* - warning: 警告日志
* - error: 错误日志
* - emergency: 紧急日志
*/
public function log($message, $module = 'default', $level = 'info') {
if (!is_string($message)) {
$message = print_r($message, true);
}
list($msec, $sec) = explode(" ", microtime());
$str = date("Y-m-d H:i:s", $sec) . '.' . sprintf('%04d', round($msec * 10000)) . ' | ' . $this->uniqid . ' | ' . $level . ' | ' . $message . PHP_EOL;
$file = $this->path . '/' . $module . '/' . date("Y-m-d") . '.log';
$this->logs[] = array('str' => $str, 'file' => $file);
if (count($this->logs) >= $this->threshold || $this->dumpTime < time() - $this->interval) {
$this->dump();
}
}
/**
* 把日志缓冲区里的日志写入文件
*
* 备注:一般不需要手动调用,系统会在日志数量达到日志缓冲阈值时自动执行,也会在此对象被销毁时自动执行。
*/
public function dump() {
$logs = array_splice($this->logs, 0, count($this->logs));
$threshold = $this->threshold;
list($msec, $sec) = explode(" ", microtime());
$datas = array();
$paths = array();
// 把写入同一个日志文件的数据拼接起来,方便后续一次写入,减少IO操作
while (count($logs)) {
$log = array_shift($logs);
$str = $log['str'];
$file = $log['file'];
$path = dirname($file);
if (!file_exists($path)) {
@mkdir($path, 0777, true);
}
if (!isset($datas[$file])) {
$datas[$file] = array();
}
$datas[$file][] = $str;
$paths[$path] = $path;
}
// 输出日志到文件
$prefix = date("Y-m-d H:i:s", $sec) . '.' . sprintf('%04d', round($msec * 10000)) . ' | ' . $this->uniqid;
foreach ($datas as $file => $strs) {
$str = $prefix . ' | 日志写入文件 | ' . $threshold . ' | ' . sprintf('%0' . strlen($threshold) . 'd', count($strs)) . ' | ' . $file . PHP_EOL . implode('', $strs);
// 在写入时获得一个独占锁,,防止多进程同时写入造成内容丢失。
file_put_contents($file, $str, FILE_APPEND | LOCK_EX);
}
// 自动清理以前的日志文件
foreach ($paths as $path) {
foreach (glob($path . '/*.*') as $fn) {
if (is_file($fn) && @filemtime($fn) < $sec - $this->cleanCycle) {
@unlink($fn);
}
}
}
$this->dumpTime = $sec;
}
}