initial: db_log_exporter v1.0

This commit is contained in:
QClaw Bot
2026-05-12 19:02:46 +08:00
commit 7cd8f78404
6 changed files with 1364 additions and 0 deletions

306
README.md Normal file
View File

@@ -0,0 +1,306 @@
# db_log_exporter
从 MySQL / PostgreSQL 数据库表中**定时拉取日志**,写入标准 **syslog 格式**RFC 5424 变体)文本文件。
---
## 功能特性
| 特性 | 说明 |
|------|------|
| **多数据库支持** | MySQL + PostgreSQL 同时运行,互不干扰 |
| **断点续传** | 每个数据源独立记录最后拉取的 ID重启不丢、不重复 |
| **标准格式** | 输出 RFC 5424 syslog 行,可被 rsyslog、Filebeat、Promtail 等直接采集 |
| **多数据源** | 一个进程管理多个表,不同表可配置不同数据库、轮询间隔、输出文件 |
| **线程安全** | 每个数据源独立线程,并发拉取,互不影响 |
| **灵活列映射** | 数据库列名不同时可在配置中映射 |
| **Dry-run** | `--dry-run` 模式测试连接,不写文件 |
| **单次模式** | `--once` 模式跑完一轮即退出,适合 cron 场景 |
| **systemd 集成** | 提供 `.service` 文件,支持开机自启 |
---
## 输出格式
每行一条日志格式如下RFC 5424 变体):
```
<priority>1 2026-05-12T15:30:00.123456+08:00 hostname app_name[12345]: [trace=abc123] [span=def456] 日志内容
```
| 字段 | 说明 |
|------|------|
| `<priority>` | syslog 优先级,`<6>`=INFO `<4>`=WARN `<3>`=ERROR 等 |
| `version` | RFC 5424 版本号,始终为 `1` |
| `timestamp` | ISO 8601 时间(含微秒和时区) |
| `hostname` | 配置文件中的 hostname默认系统 hostname |
| `app_name[pid]` | 配置的 app_name + 本进程 PID |
| `[trace=...] [span=...]` | 结构化数据trace_id / span_id 等) |
| `message` | 日志正文 |
---
## 快速开始
### 1. 安装依赖
```bash
# CentOS / RHEL / Fedora
sudo yum install -y python3 python3-pip
sudo pip3 install PyMySQL psycopg2-binary PyYAML
# Debian / Ubuntu
sudo apt-get install -y python3 python3-pip
sudo pip3 install PyMySQL psycopg2-binary PyYAML
```
### 2. 下载程序
```bash
sudo mkdir -p /opt/db_log_exporter
sudo curl -L https://your-repo/db_log_exporter.py \
-o /opt/db_log_exporter/db_log_exporter.py
sudo chmod +x /opt/db_log_exporter/db_log_exporter.py
```
### 3. 编写配置
```bash
sudo mkdir -p /etc/db_log_exporter
sudo nano /etc/db_log_exporter/config.yaml
```
参考 `config.yaml.example`(本仓库根目录),主要填:
```yaml
databases:
mysql_prod:
type: mysql
host: 192.168.1.100
port: 3306
user: log_reader
password: "your_password"
database: app_logs
sources:
- name: access_log
database: mysql_prod
table: access_log
columns:
id: id
timestamp: created_at
level: log_level
message: message
```
### 4. 测试连接Dry-run
```bash
python3 /opt/db_log_exporter/db_log_exporter.py \
-c /etc/db_log_exporter/config.yaml \
--dry-run
```
### 5. 运行方式
**方式 Asystemd 守护进程(推荐)**
```bash
# 复制 service 文件
sudo cp db_log_exporter.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now db_log_exporter
sudo journalctl -u db_log_exporter -f # 实时查看日志
```
**方式 Bcron 定时任务(单次模式)**
```bash
# crontab -e
* * * * * python3 /opt/db_log_exporter/db_log_exporter.py \
-c /etc/db_log_exporter/config.yaml --once
```
**方式 C直接运行前台守护**
```bash
python3 /opt/db_log_exporter/db_log_exporter.py \
-c /etc/db_log_exporter/config.yaml
```
---
## 配置说明
详细配置参考 `config.yaml.example`,核心字段:
```yaml
global:
output_dir: /var/log/db_exporter # 日志输出目录
checkpoint_dir: /var/lib/... # 断点文件目录
hostname: myserver # syslog hostname
interval: 30 # 默认轮询间隔(秒)
batch_size: 1000 # 默认每次最多读条数
databases:
别名:
type: mysql | postgresql
host: ...
port: ...
user: ...
password: ...
database: ... # MySQL: database 名
dbname: ... # PostgreSQL: dbname
charset: utf8mb4 # MySQL 专用
sources:
- name: 源名称 # 唯一标识,用于断点文件名
database: 引用上方别名
table: 表名
log_file: 输出文件名 # 相对于 output_dir
app_name: syslog程序名
interval: 15 # 覆盖全局间隔
batch_size: 500 # 覆盖全局批次大小
columns: # 列名映射
id: id
timestamp: created_at
level: log_level
message: message
trace_id: trace_id # 可选
span_id: span_id # 可选
```
### 数据库用户权限(最小权限)
**MySQL:**
```sql
CREATE USER 'log_reader'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON app_logs.access_log TO 'log_reader'@'%';
GRANT SELECT ON app_logs.error_log TO 'log_reader'@'%';
FLUSH PRIVILEGES;
```
**PostgreSQL:**
```sql
CREATE USER log_reader WITH PASSWORD 'password';
GRANT CONNECT ON DATABASE app_logs TO log_reader;
GRANT SELECT ON application_logs TO log_reader;
GRANT SELECT ON audit_log TO log_reader;
```
---
## 与日志采集系统集成
### rsyslog服务器接收
```conf
# /etc/rsyslog.d/60-db-exporter.conf
module(load="imfile" PollingInterval="10")
input(type="imfile"
File="/var/log/db_exporter/mysql_access.log"
Tag="db:access:"
Facility="local0")
```
### Filebeat采集到 Elasticsearch
```yaml
# filebeat.yml
filebeat.inputs:
- type: log
paths:
- /var/log/db_exporter/*.log
fields:
log_type: db_exporter
fields_under_root: true
```
### PromtailLoki 采集)
```yaml
# promtail.yml
scrape_configs:
- job_name: db_exporter
static_configs:
- targets: [localhost]
labels:
job: db_exporter
__path__: /var/log/db_exporter/*.log
```
---
## 故障排查
| 问题 | 排查方法 |
|------|---------|
| 服务启动失败 | `journalctl -u db_log_exporter -e` 查看错误日志 |
| 连接被拒绝 | 确认数据库允许该 IP 连接,检查防火墙/安全组 |
| 权限不足 | 确认运行用户对 `output_dir``checkpoint_dir` 有写权限 |
| 日志重复 | 删除对应断点文件并重启,程序会从头拉取 |
| 中文乱码 | 确认数据库字符集为 `utf8mb4`MySQL`UTF8`PG |
| 连接超时 | 在 `databases` 中加 `connect_timeout: 10` |
---
## 目录结构
```
db_log_exporter/
├── db_log_exporter.py # 主程序Python 守护进程)
├── config.yaml.example # 配置文件示例
├── requirements.txt # Python 依赖
├── db_log_exporter.service # systemd 服务文件
├── setup.sh # 自动化安装脚本
└── README.md # 本文件
```
---
## 命令行参数
```
-c, --config YAML 配置文件路径(必填)
--once 仅执行一次轮询后退出(适合 cron
--dry-run 仅测试数据库连接,不写文件
--log-level 日志级别: DEBUG|INFO|WARNING|ERROR默认 INFO
--log-file 本程序日志输出文件(默认 stdout
```
---
## 安全建议
1. **数据库密码不要明文写在配置中**,使用环境变量或 systemd secret
```bash
# /etc/db_log_exporter/env
DB_PASSWORD=your_password
```
然后在 `config.yaml` 中用 `${DB_PASSWORD}` 引用
2. **以最小权限用户运行服务**,不要用 root
```bash
useradd -r -s /sbin/nologin db_exporter
chown -R db_exporter:db_exporter /var/log/db_exporter /var/lib/db_exporter
# 修改 service 文件中的 User=db_exporter
```
3. **日志文件及时轮转**,防止磁盘爆满:
```bash
# /etc/logrotate.d/db_log_exporter
/var/log/db_exporter/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 root root
sharedscripts
postrotate
systemctl reload db_log_exporter > /dev/null 2>&1 || true
endscript
}
```