当前位置: 首页 > news >正文

PHP日志系统从入门到精通

PHP日志系统从入门到精通

日志是排查问题的第一手段。好的日志系统能让你快速定位线上问题。PHP内置的error_log函数可以写日志,但生产环境需要更完善的日志方案。

从最简单的error_log开始。它可以直接写文件、发送邮件或写入系统日志。

```php
// PHP内置日志
error_log("用户登录成功");

// 写日志到指定文件
error_log("数据库连接失败", 3, '/var/log/app.log');

// 发送邮件
// error_log("严重错误", 1, "admin@example.com");

// 写入系统日志
error_log("应用启动", 4);
?>
```

用Monolog库可以实现结构化的日志记录,支持多种处理器和格式:

```php
require 'vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\MemoryUsageProcessor;

// 创建日志通道
$log = new Logger('app');

// 文件处理器(每天轮转,保留30天)
$rotating = new RotatingFileHandler('/var/log/app.log', 30, Logger::WARNING);
$formatter = new LineFormatter(
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
'Y-m-d H:i:s'
);
$rotating->setFormatter($formatter);
$log->pushHandler($rotating);

// 调试日志处理器
$debugHandler = new StreamHandler('/var/log/app_debug.log', Logger::DEBUG);
$debugFormatter = new LineFormatter(null, null, true, true);
$debugHandler->setFormatter($debugFormatter);
$log->pushHandler($debugHandler);

// 处理器
$log->pushProcessor(new IntrospectionProcessor());
$log->pushProcessor(new WebProcessor());
$log->pushProcessor(new MemoryUsageProcessor());

// 记录日志
$log->debug('调试信息', ['query' => 'SELECT * FROM users']);
$log->info('用户登录', ['user_id' => 123, 'ip' => '192.168.1.1']);
$log->warning('磁盘空间不足', ['free_space' => '500MB']);
$log->error('数据库连接失败', ['error' => 'Connection refused']);
$log->critical('服务不可用');
?>
```

结构化的日志记录格式便于分析和查询:

```php
class StructuredLogger
{
private string $logDir;
private string $channel;
private array $processors = [];

public function __construct(string $channel, string $logDir = '/var/log/app')
{
$this->channel = $channel;
$this->logDir = rtrim($logDir, '/');
if (!is_dir($this->logDir)) mkdir($this->logDir, 0755, true);
}

public function debug(string $message, array $context = []): void
{
$this->log('debug', $message, $context);
}

public function info(string $message, array $context = []): void
{
$this->log('info', $message, $context);
}

public function warning(string $message, array $context = []): void
{
$this->log('warning', $message, $context);
}

public function error(string $message, array $context = []): void
{
$this->log('error', $message, $context);
}

public function critical(string $message, array $context = []): void
{
$this->log('critical', $message, $context);
$this->sendAlert($message, $context);
}

private function log(string $level, string $message, array $context): void
{
$entry = [
'timestamp' => date('Y-m-d\TH:i:s.vP'),
'channel' => $this->channel,
'level' => $level,
'message' => $message,
'context' => $context,
'extra' => [
'pid' => getmypid(),
'memory' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB',
'uri' => $_SERVER['REQUEST_URI'] ?? 'cli',
'method' => $_SERVER['REQUEST_METHOD'] ?? 'CLI',
'ip' => $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
],
];

$logLine = json_encode($entry, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$logFile = $this->logDir . '/' . $this->channel . '-' . date('Y-m-d') . '.log';
file_put_contents($logFile, $logLine . "\n", FILE_APPEND | LOCK_EX);
}

private function sendAlert(string $message, array $context): void
{
$subject = '[CRITICAL] ' . $this->channel . ': ' . substr($message, 0, 100);
$body = json_encode(['message' => $message, 'context' => $context], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
error_log($body, 1, 'admin@example.com', "Subject: $subject\n");
}
}

$log = new StructuredLogger('payment');
$log->info('支付成功', ['order_id' => 'ORD-001', 'amount' => 99.99]);
$log->error('支付失败', ['order_id' => 'ORD-002', 'error' => '余额不足']);
?>
```

日志级别的使用场景:

```php
class LogLevelGuide
{
public static function getExamples(): array
{
return [
'debug' => [
'desc' => '详细的调试信息',
'examples' => [
'SQL查询语句和参数',
'API请求和响应内容',
'变量值的变化过程',
],
],
'info' => [
'desc' => '正常运行的记录',
'examples' => [
'用户登录/注册',
'订单创建/支付',
'定时任务执行',
],
],
'notice' => [
'desc' => '正常但值得注意的事件',
'examples' => [
'使用了已废弃的API',
'配置使用了默认值',
'达到了某个阈值',
],
],
'warning' => [
'desc' => '潜在的问题',
'examples' => [
'数据库查询速度超过1秒',
'磁盘使用率超过80%',
'重试操作成功',
],
],
'error' => [
'desc' => '运行时错误',
'examples' => [
'数据库连接失败',
'第三方API返回错误',
'数据验证失败',
],
],
'critical' => [
'desc' => '严重错误需要立即处理',
'examples' => [
'主数据库不可用',
'磁盘空间耗尽',
'安全漏洞被利用',
],
],
];
}
}

$guide = LogLevelGuide::getExamples();
foreach ($guide as $level => $info) {
echo str_pad($level, 10) . ": {$info['desc']}\n";
foreach ($info['examples'] as $ex) {
echo " - $ex\n";
}
echo "\n";
}
?>
```

日志的集中管理在大项目中很重要。可以用ELK(Elasticsearch、Logstash、Kibana)或Loki来集中收集和分析日志。PHP应用只需要把日志以JSON格式写到文件,由Filebeat或Fluentd收集后发送到日志中心。

好的日志系统能让线上问题定位变得很容易。关键是要在正确的地方用正确的级别记录日志,信息太少不行,信息太多同样不行。

http://www.cnnetsun.cn/news/2720363.html

相关文章:

  • 从Fluent面板到理论公式:一文讲透ANSYS Help文档的四种正确打开方式
  • 别再只做九点标定了!Halcon+C#实战:手眼标定完整流程与旋转中心补偿避坑指南
  • 【万字文档+源码】基于springBoot+vue摄影师分享交流社区系统-项目分享学习
  • 手把手教你理解GW星座:从3GPP NTN标准到手机直连卫星的实战展望
  • SAP EWM两步拣配实战:从波次释放到发货完成的完整流程演示与库存变化追踪
  • 企业级Windows Syslog服务器终极指南:Visual Syslog Server完整部署与优化方案
  • 从一次跨国服务时间戳Bug说起:深入理解Linux的CST、UTC、GMT和RTC到底怎么玩
  • 在AutoDL上租张4090,5小时跑通So-vits-svc4.1模型训练(含社区镜像选择与日志解读)
  • 转行AI训练师,你竟然能找到这些高薪工作!(附岗位地图)
  • 实验室萌新必看:手把手教你读懂pET-28a(+)质粒图谱,从元件到实操一次搞定
  • MATLAB实现的车-路-网协同充电负荷模拟工具:支持动态路径规划与区域级24小时负荷热力图生成
  • 从无效社交到价值网络:工程师的个人品牌与系统性连接策略
  • 【RT-DETR实战】111、TensorRT推理引擎构建与性能测试:从踩坑到起飞
  • HoloNet框架:深度神经网络在QCD相结构研究中的应用
  • UWB二维定位MATLAB实战包:含Chan/TDOA/WLS/泰勒/EKF/UKF六种算法及实测数据
  • 量子线性求解器在流体动力学中的应用与实现
  • 语音合成逼真度提升不是调参——而是重构声学先验:基于10万小时真实语料的发音动力学建模
  • Unity安卓端第三人称移动控制模板:左摇杆走位+右拖拽调视角
  • AI先替代了谁|横店群演等不到通告了
  • 独家披露:Sora 2艺术复现未公开API调用层协议与motion token embedding映射表(限时开放24小时下载)
  • 零 Token 消耗!Agnes 多模态 Agent 全栈实战指南
  • 如何高效使用冒险岛资源解析工具:5个实用技巧全面指南
  • PyTorch项目安装报错libcupti.so.12找不到?一个软链接搞定CUDA环境依赖
  • 别再死记公式了!用Simulink仿真带你直观理解Buck电路的DCM与CCM模式切换
  • GEO优化技术实现全流程拆解:中小企业如何让AI大模型准确收录你的信息
  • 深度实战:高效掌握GroundingDINO零样本目标检测的核心功能与进阶技巧
  • 2026年6月6款设计AI采购建议
  • 从Taker到Maker:我的Crypto做市策略如何靠一个‘Bug’意外盈利?
  • 告别呆板烟雾!在Niagara里用SubUV和随机旋转/缩放打造更自然的飘散效果
  • Nerfstudio训练速度慢?渲染效果差?可能是你忽略了这5个关键参数(附性能对比实测)