Docker 查看容器日志
Docker 查看容器日志
容器出问题怎么排查?先看日志,这些命令要会。
1. 查看容器日志
基本命令
# 查看全部日志
docker logs 容器名
# 查看容器ID
docker logs 容器ID
2. 常用参数
看最后几行
# 最后10行
docker logs --tail 10 容器名
# 最后20行
docker logs --tail 20 容器名
实时跟踪日志(最常用)
docker logs -f 容器名
带时间戳
docker logs -t 容器名
组合使用
# 实时跟踪 + 时间戳 + 最后10行
docker logs -f -t --tail 10 容器名
3. 按时间查看
# 最近10分钟的日志
docker logs --since 10m 容器名
# 最近1小时的日志
docker logs --since 1h 容器名
# 指定时间开始
docker logs --since "2024-01-01T00:00:00" 容器名
4. 多容器日志
docker-compose 查看日志
# 查看所有服务日志
docker-compose logs
# 实时跟踪
docker-compose logs -f
# 查看指定服务
docker-compose logs nginx
# 看最后50行
docker-compose logs --tail 50 nginx
5. 日志持久化
json-file 日志驱动(默认)
- 日志存在 /var/lib/docker/containers/
- 单个容器日志文件
配置日志大小限制
# docker-compose.yml
services:
app:
image: nginx
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
6. 常见排查场景
1)容器启动失败
docker logs 容器名
看最后几行报错信息。
2)接口报错
docker logs -f --tail 100 容器名
实时看请求日志。
3)查某个时间点的错误
docker logs --since "2024-01-01T10:00:00" 容器名 | grep "error"
7. 日志清理
清理单个容器日志
# 找到日志文件
sudo find /var/lib/docker/containers/ -name "*.log"
# 清空日志
sudo sh -c "echo > /var/lib/docker/containers/容器ID/容器ID-json.log"
重启容器自动清理
docker restart 容器名
总结
Docker 查看容器日志要点:
- docker logs 查看日志
- -f 实时跟踪最常用
- --tail 看最后几行
- -t 带时间戳
- --since 按时间查
- docker-compose logs 多容器
- 配置日志大小防止占满磁盘
- 排查问题先看日志
容器运维,看日志是第一步。
Linux 查看系统日志
Linux 查看系统日志
排查问题先看日志,这些命令要记住。
1. 系统日志位置
/var/log/messages # 系统主日志
/var/log/syslog # Debian/Ubuntu 系统日志
/var/log/boot.log # 启动日志
/var/log/cron # 定时任务日志
/var/log/secure # 安全日志(登录、sudo等)
/var/log/nginx/ # Nginx 日志
/var/log/httpd/ # Apache 日志
/var/log/mysql/ # MySQL 日志
2. 基本查看命令
cat:查看全部
cat /var/log/messages
tail:看末尾几行(最常用)
# 看最后10行
tail /var/log/messages
# 看最后20行
tail -n 20 /var/log/messages
# 实时跟踪日志(最常用)
tail -f /var/log/messages
head:看开头几行
head -n 10 /var/log/messages
3. 搜索日志
grep:搜索关键词
# 搜索错误信息
grep "error" /var/log/messages
# 不区分大小写
grep -i "error" /var/log/messages
# 显示行号
grep -n "error" /var/log/messages
# 反向匹配(不包含error)
grep -v "debug" /var/log/messages
结合管道
# 实时日志里搜索错误
tail -f /var/log/messages | grep "error"
# 搜索最近的nginx错误
tail -n 1000 /var/log/nginx/error.log | grep "500"
4. journalctl 查看 systemd 日志
# 查看全部日志
journalctl
# 看最后100行
journalctl -n 100
# 实时跟踪
journalctl -f
# 按服务查看
journalctl -u nginx
# 按时间查看
journalctl --since "1 hour ago"
journalctl --since "2024-01-01" --until "2024-01-02"
5. 常用排查场景
1)服务器登录失败
grep "Failed password" /var/log/secure
2)服务起不来
systemctl status nginx
journalctl -u nginx -n 50
3)磁盘满了
df -h
du -sh /var/log/*
4)定时任务没执行
cat /var/log/cron
6. 日志清理
手动删除大日志
# 查看日志大小
du -sh /var/log/*
# 清空日志(不删除文件)
> /var/log/messages
# 删除旧日志
rm /var/log/messages.1
logrotate 自动切割
- Linux 自带日志切割工具
- 配置文件在 /etc/logrotate.conf
- 一般不用管,自动轮转
总结
Linux 查看日志要点:
- 日志都在 /var/log/ 目录
- tail -f 实时看日志最常用
- grep 搜索关键词
- journalctl 查 systemd 服务日志
- 排查问题先看错误日志
- 日志太大要及时清理
- 系统自动轮转不用手动管
运维排查,看日志是第一步。
Nginx 日志分析技巧
Nginx 日志分析技巧
Nginx 日志是排查问题的重要工具,学会分析日志很重要。
1. 日志位置
默认日志路径:
# 访问日志
/var/log/nginx/access.log
# 错误日志
/var/log/nginx/error.log
2. 日志格式
默认日志格式:
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
3. 常用分析命令
1)查看访问量最多的IP:
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head 10
2)查看访问最多的页面:
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head 10
3)查看状态码分布:
awk '{print $9}' access.log | sort | uniq -c | sort -nr
4)查看404错误:
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -nr
4. 排查常用
1)查看哪个IP访问频繁:
grep "127.0.0.1" access.log
2)查看某个时间段日志:
grep "08/Oct/2026:07" access.log
3)查看错误日志:
tail -f error.log
5. 日志切割
用 logrotate 自动切割:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
notifempty
create 0640 nginx adm
postrotate
systemctl reload nginx
endscript
}
6. 常用场景
- 被攻击了:查访问量最多的IP
- 页面报错:查404/500
- 流量突增:查访问最多的页面
- 爬虫多:查 User-Agent
总结
Nginx 日志分析要点:
- 访问日志查访问情况
- 错误日志排查问题
- awk 统计数据
- 日志自动切割
- 定期分析日志
做运维,看日志是基本功。
PHP 错误处理最佳实践
PHP 错误处理最佳实践
错误处理是 PHP 开发最容易忽略但最重要的环节,写好了排查问题事半功倍,写不好线上出问题抓瞎。
1. 错误级别
PHP 有不同的错误级别:
- E_ERROR:致命错误,脚本停止
- E_WARNING:警告,脚本继续
- E_NOTICE:注意,一般是不规范写法
- E_PARSE:语法解析错误
// 开发环境显示所有错误
error_reporting(E_ALL);
ini_set('display_errors', 1);
// 生产环境不显示错误,只记日志
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php/error.log');
2. 错误 vs 异常
PHP 里错误和异常是两回事:
- 错误:语法错误、内存不足这种,用 try/catch 抓不住
- 异常:业务层面的错误,比如数据库连接失败
PHP 7+ 大部分错误会抛 Error 异常,也可以抓了。
3. try/catch 用法
try {
// 可能出错的代码
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
} catch (PDOException $e) {
// 捕获异常
echo "数据库连接失败:" . $e->getMessage();
// 记日志
error_log("DB Error: " . $e->getMessage());
}
4. 自定义错误处理
// 设置自定义错误处理器
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// 把错误转成异常抛出
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
// 设置异常处理器
set_exception_handler(function($e) {
// 所有未捕获的异常都到这里
error_log("Uncaught: " . $e->getMessage());
echo "系统繁忙,请稍后再试";
});
// 注册关闭函数,抓致命错误
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE])) {
error_log("Fatal: " . $error['message']);
}
});
5. 开发 vs 生产环境
开发环境:
- 打开 display_errors,错误直接显示在页面
- 打开所有错误级别
- 详细的报错信息方便调试
生产环境:
- 关闭 display_errors,不要把错误暴露给用户
- 错误全部写到日志文件
- 页面显示友好的"系统错误"提示
6. 常用错误处理技巧
// 1. 用 @ 抑制错误不好,应该判断
// 不好:
$file = @file_get_contents('config.php');
// 好:
$file = file_exists('config.php') ? file_get_contents('config.php') : null;
// 2. 不要把数据库错误信息直接返回给前端
// 不好:
echo $e->getMessage();
// 好:
error_log($e->getMessage());
echo json(['code' => 500, 'msg' => '系统错误']);
// 3. 日志要分级
error_log('信息:用户登录', 3, '/var/log/info.log');
error_log('警告:登录失败次数过多', 3, '/var/log/warn.log');
error_log('错误:数据库连接失败', 3, '/var/log/error.log');
7. 总结
PHP 错误处理核心:
- 开发环境显示错误,生产环境只记日志
- try/catch 捕获业务异常
- set_exception_handler 兜底
- 不要把错误细节暴露给用户
- 日志分级,方便排查
搞懂这些,线上出问题排查效率翻倍。
MySQL binlog日志详解,三种格式和恢复数据方法
前言
做运维或者DBA的同学肯定都遇到过这种情况:不小心执行了一个DROP TABLE语句,或者DELETE忘加WHERE条件,把数据删了。这时候怎么办?别急,MySQL的binlog日志可以帮你把数据找回来。
很多新手同学不知道binlog是什么,也不知道怎么用它来恢复数据。这篇文章就把binlog的知识点从头到尾讲清楚,包括binlog的三种格式、怎么开启、怎么查看、怎么用它恢复数据,看完之后你就彻底搞懂了。
一、binlog是什么
binlog的全称是二进制日志(Binary Log)。它记录了MySQL数据库里所有的写操作(INSERT、UPDATE、DELETE、CREATE TABLE这些),但是不记录SELECT查询。
binlog有什么用
- 数据恢复:不小心删了数据,可以用binlog恢复
- 主从复制:主库把binlog传给从库,从库重放binlog,实现主从同步
- 数据审计:可以通过binlog追溯谁在什么时候做了什么操作
二、binlog的三种格式
binlog有三种格式,不同的格式记录的内容不一样。
1. STATEMENT(语句模式)
这种格式记录的是SQL语句本身。比如你执行了一条INSERT语句,binlog里就记录这条INSERT语句。
优点:
- 日志量小,占用空间少
- 同步的时候从库重放SQL就行
缺点:
- 有些函数(比如NOW()、UUID())在主库和从库执行结果可能不一样,导致主从不一致
- 某些复杂的SQL可能在从库上执行结果不一样
2. ROW(行模式)
这种格式记录的是每一行数据的修改。比如你更新了100行数据,binlog里就记录这100行每一行改前是什么样,改后是什么样。
优点:
- 记录的是真实的数据修改,不会出现主从不一致的问题
- 能精确知道哪一行被改了
缺点:
- 日志量大,因为每一行修改都要记录
- 批量更新的时候,日志会特别大
3. MIXED(混合模式)
这种模式是前两种的混合。MySQL会自动判断:一般的SQL用STATEMENT模式,遇到那些可能出问题的SQL(比如用了NOW()、UUID()这些函数的),就自动切换成ROW模式。
总结: 现在一般推荐用ROW模式,虽然日志量大一点,但是数据一致性有保证,不会出主从不一致的问题。
三、怎么开启binlog
默认情况下,MySQL的binlog可能是没开的。我们先看看开没开:
SHOW VARIABLES LIKE 'log_bin';
如果Value是ON,说明开了;如果是OFF,说明没开。
开启binlog
编辑MySQL的配置文件 /etc/my.cnf,在[mysqld]下面添加:
[mysqld]
# 开启binlog
log_bin = mysql-bin
# binlog的格式,推荐用ROW
binlog_format = ROW
# 保存多少天的binlog,过期自动删除
expire_logs_days = 7
# 单个binlog文件最大多大
max_binlog_size = 100M
修改完之后重启MySQL服务:
systemctl restart mysqld
重启完之后再查一下,应该就开了。
四、怎么查看binlog
查看有哪些binlog文件
SHOW BINARY LOGS;
执行完之后会看到类似这样的结果:
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 15264 |
| mysql-bin.000002 | 126 |
| mysql-bin.000003 | 126 |
+------------------+-----------+
binlog文件是按编号来的,mysql-bin.000001满了就生成mysql-bin.000002,以此类推。
查看binlog里的内容
binlog是二进制文件,不能直接用cat看,要用mysqlbinlog工具。
比如要看mysql-bin.000001这个文件:
mysqlbinlog /var/lib/mysql/mysql-bin.000001
如果是ROW格式的binlog,直接看是看不懂的,要加-vv参数:
mysqlbinlog -vv /var/lib/mysql/mysql-bin.000001
这样就能看到具体改了哪一行,改前是什么,改后是什么。
五、怎么用binlog恢复数据
这是大家最关心的:不小心删了数据,怎么用binlog恢复?
恢复的原理
binlog记录了所有的写操作。如果你不小心删了某段时间的数据,只要把这段时间之前的binlog重新执行一遍,数据就回来了。
举个例子
假设你在2026-10-05 10:00的时候,不小心执行了一条DELETE语句,把testdb库的users表全删了。现在要恢复数据。
步骤1:找到要恢复的binlog文件
先看看有哪些binlog文件,找到那个时间点对应的文件:
SHOW BINARY LOGS;
步骤2:找到删除操作的位置
用mysqlbinlog工具查看binlog,找到DELETE语句的位置:
mysqlbinlog --start-datetime="2026-10-05 09:00:00" --stop-datetime="2026-10-05 11:00:00" /var/lib/mysql/mysql-bin.000003
然后找到那条DELETE语句在binlog里的位置(position)。
步骤3:恢复数据
把DELETE语句之前的binlog重新执行一遍,数据就回来了:
mysqlbinlog --stop-position=刚才找到的位置 /var/lib/mysql/mysql-bin.000003 | mysql -u root -p
这样就把DELETE之前的数据恢复了。
注意: 恢复完之后,DELETE之后的操作也没了,所以还要把DELETE之后的操作也重新执行一遍,直到最新的位置。
六、binlog的其他常用操作
手动生成新的binlog文件
FLUSH LOGS;
这个命令会关闭当前的binlog文件,生成一个新的。一般备份完数据库之后执行这个,这样备份之后的操作都记录到新的binlog里,恢复的时候方便。
删除旧的binlog文件
-- 删除指定文件之前的所有binlog
PURGE BINARY LOGS TO 'mysql-bin.000003';
-- 删除指定日期之前的所有binlog
PURGE BINARY LOGS BEFORE '2026-10-01 00:00:00';
查看当前正在写的binlog
SHOW MASTER STATUS;
这个命令会显示当前正在写的binlog文件名和位置,主从复制的时候经常用到。
常见坑
坑1:binlog没开,删了数据找不回来
很多同学的MySQL默认没开binlog,结果不小心删了数据,才发现根本没有日志可以恢复,欲哭无泪。生产环境一定要开binlog!
坑2:binlog格式用了STATEMENT,主从不一致
很多同学用默认的STATEMENT格式,结果主从数据不一致。推荐用ROW格式,虽然日志大一点,但是数据一致性有保证。
坑3:binlog占满磁盘
很多同学开了binlog但是没设置过期时间,结果binlog文件越来越多,把磁盘占满了,MySQL直接挂了。一定要设置expire_logs_days,让旧的binlog自动删除。
坑4:恢复数据的时候把DELETE也执行了
很多同学恢复的时候,把DELETE语句也一起执行了,结果恢复完数据又被删了。一定要找到DELETE之前的位置,只恢复到那个位置之前。
坑5:恢复完没验证
很多同学恢复完数据就以为完事了,结果一查发现数据不对。恢复完一定要仔细核对数据,确保没问题了再上线。
总结
MySQL binlog的核心知识点:
- binlog记录所有写操作,不记录查询
- binlog的三个作用:数据恢复、主从复制、数据审计
- 三种格式:
- STATEMENT:记录SQL语句,日志小,但是可能主从不一致
- ROW:记录每行数据修改,日志大,但是数据一致,推荐用
- MIXED:混合模式,自动选择
- 开启binlog:在my.cnf里配置log_bin和binlog_format
- 查看binlog:用mysqlbinlog工具,ROW格式要加-vv
- 恢复数据:找到误操作之前的位置,重新执行之前的binlog
- 注意设置过期时间:不然binlog会把磁盘占满
binlog是MySQL最重要的日志之一,生产环境必须开。学会了用binlog恢复数据,以后不小心删数据的时候就不用慌了。
遇到问题加QQ23979811 协助处理
Nginx 日志分析技巧
Nginx 日志分析技巧
Nginx 日志是排查问题、分析流量的重要工具。学会看日志,网站问题排查效率翻倍。
1. 日志位置
# 默认访问日志
/var/log/nginx/access.log
# 默认错误日志
/var/log/nginx/error.log
可以在 nginx.conf 里自定义:
access_log /var/log/nginx/www.access.log;
error_log /var/log/nginx/www.error.log;
2. 日志格式
默认日志格式:
127.0.0.1 - - [04/Oct/2026:10:00:00 +0800] "GET / HTTP/1.1" 200 612 "https://www.baidu.com/" "Mozilla/5.0..."
各字段含义:
- IP 地址
- 请求时间
- 请求方法和路径
- 状态码
- 响应大小
- 来源页面
- User-Agent
3. 常用分析命令
# 查看访问量前10的IP
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head 10
# 查看访问量前10的页面
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head 10
# 查看状态码分布
awk '{print $9}' access.log | sort | uniq -c | sort -nr
# 查看 404 请求
grep ' 404 ' access.log
# 查看 502 错误
grep ' 502 ' access.log
4. 排查问题
排查 502 错误:
grep ' 502 ' access.log | tail 20
排查慢请求:
开启慢日志:
slow_request_log /var/log/nginx/slow.log;
slow_request_time 5s;
排查爬虫:
grep 'Baiduspider' access.log
grep 'Googlebot' access.log
5. 流量统计
# 今天总访问量
grep '04/Oct/2026' access.log | wc -l
# 今天总流量
grep '04/Oct/2026' access.log | awk '{sum+=$10} END {print sum/1024/1024 " MB"}'
# 每小时访问量
awk '{print $4}' access.log | cut -d: -f2 | uniq -c
6. 日志切割
日志太大要切割,用 logrotate:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
notifempty
create 0640 nginx adm
postrotate
systemctl reload nginx
endscript
}
7. 常用工具
- GoAccess:实时日志分析工具
- ELK:Elasticsearch + Logstash + Kibana
- Zabbix:监控告警
总结
Nginx 日志分析核心:
- 位置:/var/log/nginx/
- 命令:awk + sort + uniq
- 排查:看状态码、看慢请求
- 切割:用 logrotate
学会这些,日常日志分析基本够用了。
PHP 错误与异常处理:从 die 到优雅的错误处理
前言
很多 PHP 新手处理错误就是 die() 或者 exit(),页面直接白屏,用户体验极差。本文讲清楚 PHP 的错误和异常处理机制,帮你写出更健壮的代码。
一、错误 vs 异常
很多人搞不清错误和异常的区别:
- 错误:PHP 本身的问题,比如语法错误、调用不存在的函数
- 异常:程序逻辑上的问题,比如数据库连不上、文件不存在
PHP 7 以后,很多错误也变成了异常,可以用 try-catch 捕获。
二、错误级别
PHP 有很多错误级别:
E_ERROR 致命错误,脚本停止运行
E_WARNING 警告,脚本继续运行
E_NOTICE 注意,一般不影响运行
E_PARSE 语法解析错误
E_DEPRECATED 过时提醒
开发环境和生产环境的配置不一样:
# 开发环境:显示所有错误
display_errors = On
error_reporting = E_ALL
# 生产环境:不显示错误,只记录日志
display_errors = Off
log_errors = On
error_reporting = E_ALL
三、异常处理基础
try-catch-finally
<?php
try {
// 可能出错的代码
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
} catch (PDOException $e) {
// 捕获异常
echo "数据库连接失败:" . $e->getMessage();
} finally {
// 不管有没有异常都会执行
echo "执行完毕";
}
抛出异常
<?php
function divide($a, $b)
{
if ($b == 0) {
throw new Exception("除数不能为 0");
}
return $a / $b;
}
try {
echo divide(10, 0);
} catch (Exception $e) {
echo "错误:" . $e->getMessage();
}
四、自定义异常类
<?php
class DbException extends Exception
{
public function errorMessage()
{
return "数据库错误:" . $this->getMessage();
}
}
class UserException extends Exception
{
public function errorMessage()
{
return "用户错误:" . $this->getMessage();
}
}
// 使用
try {
if (!$user) {
throw new UserException("用户不存在");
}
} catch (UserException $e) {
echo $e->errorMessage();
} catch (DbException $e) {
echo $e->errorMessage();
} catch (Exception $e) {
echo "其他错误:" . $e->getMessage();
}
五、错误处理器
把 PHP 错误转换成异常,统一处理:
<?php
// 自定义错误处理器
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
// 把错误转换成异常抛出
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
// 这个本来是 warning,现在会被捕获
$result = 10 / 0;
} catch (ErrorException $e) {
echo "错误:" . $e->getMessage();
}
六、异常处理器
兜底处理,最后一道防线:
<?php
// 自定义异常处理器
set_exception_handler(function ($e) {
echo "未捕获的异常:" . $e->getMessage();
// 记录日志
error_log($e->getMessage());
});
// 没有 try-catch 的异常会走这里
throw new Exception("爆炸了");
七、常见错误处理方式对比
| 方式 | 问题 |
|---|---|
die() / exit() |
页面白屏,用户体验差 |
echo 错误信息 |
代码混在一起,不好维护 |
| 错误码返回 | 调用方需要判断错误码 |
| 异常处理 | 代码清晰,错误统一管理 |
八、最佳实践
- 生产环境不要显示错误:会暴露服务器信息
- 一定要记录日志:方便排查问题
- 用异常处理替代 die():代码更优雅
- 自定义异常类:区分不同类型的错误
- 兜底异常处理器:防止未捕获的异常白屏
九、日志记录
<?php
try {
// 可能出错的代码
} catch (Exception $e) {
// 记录日志
error_log(
date('Y-m-d H:i:s') . " 错误:" . $e->getMessage() . "\n",
3,
'/var/log/php/error.log'
);
// 给用户友好提示
echo "系统繁忙,请稍后再试";
}
总结
PHP 错误处理的核心思路:
- 开发环境显示错误,生产环境隐藏错误
- 用 try-catch 捕获异常,不要用 die()
- 自定义异常类,区分不同错误类型
- 设置错误处理器,把错误转成异常
- 一定要记录日志,方便排查问题
掌握这些,你的 PHP 代码会健壮很多。