日志对象
class Logger { private $FileName, $When, $Size, $BackupCount; private $SuffixFormat = [ 'H' => 'Y-m-d_H', 'D' => 'Y-m-d', 'W' => 'Y-m-d', 'M' => 'Y-m' ]; /** * 获取日志类对象 * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建 * @return object */ public static function getLogger($fileName) { return new Logger($fileName); } /** * 获取按时间分割的日志类对象 * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建 * @param string $when 分割的时间单位 H 每小时, D 每天, W 每周, M 每月 * @param integer $backupCount 文件备份数量,默认全部,超出将会删除旧的文件 * @return object */ public static function getTimedRotatingLogger($fileName, $when = 'D', $backupCount = 0) { $logger = new Logger($fileName); $logger->setTimedRotating($when, abs(intval($backupCount))); return $logger; } /** * 获取按文件大小分割的日志类对象 * @param string $fileName 日志文件名,可以带路径,不存在的目录将被创建 * @param integer $size 分割的文件大小,单位(kb) * @param integer $backupCount 文件备份数量,默认全部,超出将会删除旧的文件 * @return object */ public static function getSizedRotatingLogger($fileName, $size = 1024, $backupCount = 0) { $logger = new Logger($fileName); $logger->setSizedRotating(abs(intval($size)), abs(intval($backupCount))); return $logger; } private function setTimedRotating($when, $backupCount) { $this->When = $when; $this->BackupCount = $backupCount; } private function setSizedRotating($size, $backupCount) { $this->Size = $size; $this->BackupCount = $backupCount; } /** * 初始化配置 * @param string $fileName 日志文件名 */ public function __construct($fileName) { $this->FileName = $fileName; } /** * 写入信息日志 * @param String $msg 日志消息 * @return Boolean */ public function info($msg) { return $this->write('INFO', $msg); } /** * 写入警告日志 * @param String $msg 日志消息 * @return Boolean */ public function warn($msg) { return $this->write('WARN', $msg); } /** * 写入警告日志 * @param String $msg 日志消息 * @return Boolean */ public function debug($msg) { return $this->write('DEBUG', $msg); } /** * 写入错误日志 * @param String $msg 日志消息 * @return Boolean */ public function error($msg) { return $this->write('ERROR', $msg); } /** * 写入日志 * @param String $type 日志类型 * @param String $msg 日志消息 * @return Boolean */ private function write($type, $msg) { $fileName = $this->FileName; // 设置日志文件名 $this->When && $fileName = $this->getTimedFileName(); $this->Size && $fileName = $this->getSizedFileName(); // 清理备份日志 $this->BackupCount && $this->clearLogFile(); // 创建日志目录 $isCreate = $this->createLogPath(); echo $msg."\n"; // 日志内容 $msg = sprintf('[%s] %-5s %s : %s' . PHP_EOL, date('Y-m-d H:i:s'), $type, get_current_user(), $msg); // 写入日志文件 if ($isCreate) { return file_put_contents($fileName, $msg, FILE_APPEND); } return false; } /** * 清理超出备份数量的旧日志文件 * @return boolean 清理结果 */ private function clearLogFile() { $files = $this->getAsortFileByTime(); $fileCnt = count($files); if ($fileCnt <= $this->BackupCount) { return true; } $cnt = 0; $result = true; foreach ($files as $file) { $result &= unlink($file['name']); if (++$cnt == $fileCnt - $this->BackupCount) { break; } } return $result; } /** * 获取根据修改时间升序排序的文件 * @return array */ private function getAsortFileByTime() { $name = explode('.', basename($this->FileName))[0]; $fold = dirname($this->FileName); $result = glob("$fold/$name*"); $files = []; foreach ($result as $i => $file) { $files[$i]['name'] = $file; $files[$i]['time'] = filemtime($file); } uasort($files, function ($f1, $f2) { return $f1['time'] - $f2['time']; }); return $files; } /** * 获取按时间分割的文件名 * @return string */ private function getTimedFileName() { $name = basename($this->FileName); $pos = strrpos($name, '.'); !isset($this->SuffixFormat[$this->When]) && $this->When = 'D'; $suffix = date($this->SuffixFormat[$this->When]); $files = $this->getAsortFileByTime(); $lastFile = end($files); $newFileName = dirname($this->FileName) . '/' . ($pos ? substr($name, 0, $pos) . $suffix . substr($name, $pos) : $name . $suffix); return $this->When == 'W' && $lastFile && time() - $lastFile['time'] > 7 * 24 * 3600 || $this->When != 'W' ? $newFileName : $lastFile['name']; } /** * 获取按文件大小分割的文件名 * @return string */ private function getSizedFileName() { $files = $this->getAsortFileByTime(); $lastFile = end($files); $fileName = $this->FileName; if ($lastFile && filesize($lastFile['name']) > 1024 * $this->Size) { $this->When = 'S'; $this->SuffixFormat['S'] = 'Y-m-d_H-i-s'; $fileName = $this->getTimedFileName(); } else if ($lastFile) { $fileName = $lastFile['name']; } return $fileName; } /** * 创建日志目录 * @return Boolean */ private function createLogPath() { $path = dirname($this->FileName); if (!is_dir($path)) { return mkdir($path, 0777, true); } return true; } }
获取日志对象
$fileName = 'logging/test.log'; $logger = Logger::getLogger($fileName); // 普通日志 $sizedLogger = Logger::getSizedRotatingLogger($fileName, 5, 3); // 按文件大小分割的日志,超过5KB分割,保留最新的三个日志文件 $timedLogger = Logger::getTimedRotatingLogger($fileName, 'H'); // 按时间分割的日志,按小时分割,保留所有日志
普通日志测试
// 普通日志测试 for ($i = 0;$i < 10;$i++) { $logger->info('test info'); $logger->warn('test warn'); $logger->error('test error'); $logger->debug('test debug'); }
按文件大小分割的日志测试
// 按文件大小分割的日志测试 for ($i = 0;$i < 600;$i++) { $sizedLogger->info('test info'); $i % 100 == 0 && sleep(1); }
按时间分割的日志测试
// 按时间分割的日志测试 for ($i = 0;$i < 100;$i++) { $timedLogger->info('test info'); }