Appearance
RabbitMQ 日志配置
概述
日志是运维排查问题的重要依据。RabbitMQ 提供了灵活的日志配置选项,可以控制日志输出位置、格式、级别等。本文将详细介绍 RabbitMQ 的日志配置方法和最佳实践。
核心知识点
日志输出目标
| 输出目标 | 配置方式 | 说明 |
|---|---|---|
| 标准输出 | log.console | 适合容器环境 |
| 文件 | log.file | 传统部署方式 |
| Syslog | log.syslog | 集中式日志收集 |
日志配置结构
erlang
log [
{console, [
{enabled, true},
{level, info},
{formatter, {rabbit_log_text_formatter, []}}
]},
{file, [
{enabled, true},
{file, "/var/log/rabbitmq/rabbit.log"},
{level, info},
{formatter, {rabbit_log_text_formatter, []}}
]}
]日志级别
| 级别 | 说明 | 适用场景 |
|---|---|---|
| debug | 调试信息 | 问题排查 |
| info | 一般信息 | 日常运维 |
| warning | 警告信息 | 需要关注 |
| error | 错误信息 | 需要处理 |
| critical | 严重错误 | 紧急处理 |
| none | 不输出 | 关闭日志 |
配置示例
基础日志配置
bash
log.file.level = info
log.file.formatter = text
log.file.rotation.date = $D0
log.file.rotation.count = 10
log.file.rotation.size = 50MB控制台日志配置
bash
log.console.enabled = true
log.console.level = info
log.console.formatter = text
log.console.standard_error = falseSyslog 日志配置
bash
log.syslog.enabled = true
log.syslog.level = info
log.syslog.facility = daemon
log.syslog.identity = rabbitmq
log.syslog.app_name = rabbitmqJSON 格式日志配置
bash
log.file.formatter = json
log.file.json.field_map = [
{time, timestamp},
{level, level},
{msg, message},
{pid, pid},
{mfa, module},
{line, line}
]完整配置示例
bash
log.file.level = info
log.file.formatter = text
log.file = /var/log/rabbitmq/rabbit.log
log.file.rotation.date = $D0
log.file.rotation.count = 10
log.file.rotation.size = 104857600
log.console.enabled = false
log.console.level = info
log.console.formatter = text
log.syslog.enabled = true
log.syslog.level = info
log.syslog.facility = daemon
log.syslog.identity = rabbitmq-server
log.connection.level = info
log.channel.level = info
log.queue.level = info
log.federation.level = info
log.mirroring.level = infoPHP 日志配置管理类
php
<?php
class RabbitMQLogConfig
{
private $configFile = '/etc/rabbitmq/rabbitmq.conf';
private $logDir = '/var/log/rabbitmq';
public function __construct($configFile = null, $logDir = null)
{
if ($configFile) {
$this->configFile = $configFile;
}
if ($logDir) {
$this->logDir = $logDir;
}
}
public function getCurrentConfig()
{
$config = [
'file' => $this->parseFileLogConfig(),
'console' => $this->parseConsoleLogConfig(),
'syslog' => $this->parseSyslogConfig(),
'categories' => $this->parseCategoryConfig(),
];
return $config;
}
private function parseFileLogConfig()
{
$config = [
'enabled' => true,
'level' => 'info',
'file' => '/var/log/rabbitmq/rabbit.log',
'formatter' => 'text',
'rotation' => [
'date' => '$D0',
'count' => 10,
'size' => 104857600,
],
];
if (file_exists($this->configFile)) {
$content = file_get_contents($this->configFile);
if (preg_match('/log\.file\.level\s*=\s*(\w+)/', $content, $m)) {
$config['level'] = $m[1];
}
if (preg_match('/log\.file\s*=\s*(.+)/', $content, $m)) {
$config['file'] = trim($m[1]);
}
if (preg_match('/log\.file\.formatter\s*=\s*(\w+)/', $content, $m)) {
$config['formatter'] = $m[1];
}
if (preg_match('/log\.file\.rotation\.count\s*=\s*(\d+)/', $content, $m)) {
$config['rotation']['count'] = (int)$m[1];
}
if (preg_match('/log\.file\.rotation\.size\s*=\s*(\d+)/', $content, $m)) {
$config['rotation']['size'] = (int)$m[1];
}
}
return $config;
}
private function parseConsoleLogConfig()
{
$config = [
'enabled' => false,
'level' => 'info',
'formatter' => 'text',
];
if (file_exists($this->configFile)) {
$content = file_get_contents($this->configFile);
if (preg_match('/log\.console\.enabled\s*=\s*(true|false)/', $content, $m)) {
$config['enabled'] = $m[1] === 'true';
}
if (preg_match('/log\.console\.level\s*=\s*(\w+)/', $content, $m)) {
$config['level'] = $m[1];
}
}
return $config;
}
private function parseSyslogConfig()
{
$config = [
'enabled' => false,
'level' => 'info',
'facility' => 'daemon',
'identity' => 'rabbitmq-server',
];
if (file_exists($this->configFile)) {
$content = file_get_contents($this->configFile);
if (preg_match('/log\.syslog\.enabled\s*=\s*(true|false)/', $content, $m)) {
$config['enabled'] = $m[1] === 'true';
}
if (preg_match('/log\.syslog\.level\s*=\s*(\w+)/', $content, $m)) {
$config['level'] = $m[1];
}
if (preg_match('/log\.syslog\.facility\s*=\s*(\w+)/', $content, $m)) {
$config['facility'] = $m[1];
}
}
return $config;
}
private function parseCategoryConfig()
{
$categories = [];
$categoryPatterns = [
'connection' => 'log\.connection\.level',
'channel' => 'log\.channel\.level',
'queue' => 'log\.queue\.level',
'federation' => 'log\.federation\.level',
'mirroring' => 'log\.mirroring\.level',
];
if (file_exists($this->configFile)) {
$content = file_get_contents($this->configFile);
foreach ($categoryPatterns as $category => $pattern) {
if (preg_match("/{$pattern}\s*=\s*(\w+)/", $content, $m)) {
$categories[$category] = $m[1];
}
}
}
return $categories;
}
public function setLogLevel($level, $category = null)
{
$validLevels = ['debug', 'info', 'warning', 'error', 'critical', 'none'];
if (!in_array($level, $validLevels)) {
throw new InvalidArgumentException("Invalid log level: {$level}");
}
$configKey = $category ? "log.{$category}.level" : 'log.file.level';
$this->updateConfig($configKey, $level);
}
public function enableConsoleLog($enabled = true)
{
$this->updateConfig('log.console.enabled', $enabled ? 'true' : 'false');
}
public function enableSyslog($enabled = true, $facility = 'daemon')
{
$this->updateConfig('log.syslog.enabled', $enabled ? 'true' : 'false');
if ($enabled) {
$this->updateConfig('log.syslog.facility', $facility);
}
}
public function setLogFile($path)
{
$dir = dirname($path);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$this->updateConfig('log.file', $path);
}
public function setRotation($count, $sizeMB)
{
$this->updateConfig('log.file.rotation.count', $count);
$this->updateConfig('log.file.rotation.size', $sizeMB * 1024 * 1024);
}
private function updateConfig($key, $value)
{
$content = '';
if (file_exists($this->configFile)) {
$content = file_get_contents($this->configFile);
}
$pattern = '/^' . preg_quote($key, '/') . '\s*=.*$/m';
$replacement = "{$key} = {$value}";
if (preg_match($pattern, $content)) {
$content = preg_replace($pattern, $replacement, $content);
} else {
$content .= "\n{$replacement}";
}
file_put_contents($this->configFile, $content);
}
public function getLogFiles()
{
$files = [];
if (is_dir($this->logDir)) {
$iterator = new DirectoryIterator($this->logDir);
foreach ($iterator as $file) {
if ($file->isFile() && preg_match('/\.log$/', $file->getFilename())) {
$files[] = [
'name' => $file->getFilename(),
'path' => $file->getPathname(),
'size' => $file->getSize(),
'modified' => date('Y-m-d H:i:s', $file->getMTime()),
];
}
}
}
usort($files, function($a, $b) {
return strcmp($b['modified'], $a['modified']);
});
return $files;
}
public function getLogDiskUsage()
{
$totalSize = 0;
$files = $this->getLogFiles();
foreach ($files as $file) {
$totalSize += $file['size'];
}
return [
'total_files' => count($files),
'total_size' => $totalSize,
'total_size_human' => $this->formatBytes($totalSize),
];
}
private function formatBytes($bytes)
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
public function applyConfig()
{
exec('rabbitmqctl eval "application:stop(rabbit)." 2>&1', $stopOutput, $stopCode);
exec('rabbitmqctl eval "application:start(rabbit)." 2>&1', $startOutput, $startCode);
return [
'success' => $startCode === 0,
'stop_output' => $stopOutput,
'start_output' => $startOutput,
];
}
}实际应用场景
场景一:Docker 环境日志配置
yaml
version: '3.8'
services:
rabbitmq:
image: rabbitmq:3.12-management
environment:
RABBITMQ_LOG: "-"
RABBITMQ_LOG_LEVEL: info
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "5"场景二:Kubernetes 日志配置
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: rabbitmq-config
data:
rabbitmq.conf: |
log.console.enabled = true
log.console.level = info
log.console.formatter = json
log.file.enabled = false
log.syslog.enabled = false
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: rabbitmq
spec:
template:
spec:
containers:
- name: rabbitmq
image: rabbitmq:3.12-management
volumeMounts:
- name: config
mountPath: /etc/rabbitmq
resources:
limits:
memory: "2Gi"
volumes:
- name: config
configMap:
name: rabbitmq-config场景三:集中式日志收集
yaml
version: '3.8'
services:
rabbitmq:
image: rabbitmq:3.12-management
environment:
RABBITMQ_ENABLED_PLUGINS_FILE: /etc/rabbitmq/enabled_plugins
volumes:
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
logging:
driver: "syslog"
options:
syslog-address: "tcp://logstash:514"
tag: "rabbitmq"
logstash:
image: logstash:8.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- "514:514"常见问题与解决方案
问题一:日志文件过大
现象:日志文件占用大量磁盘空间。
解决方案:
bash
log.file.rotation.date = $D0
log.file.rotation.count = 7
log.file.rotation.size = 104857600问题二:日志丢失
现象:部分日志没有记录。
原因:日志级别设置过高。
解决方案:
bash
log.file.level = info
log.connection.level = debug
log.channel.level = debug问题三:日志格式不统一
现象:不同节点日志格式不一致。
解决方案:
bash
log.file.formatter = json
log.file.json.field_map = time level msg pid mfa line最佳实践
1. 生产环境日志配置
bash
log.file.level = info
log.file.formatter = json
log.file.rotation.date = $D0
log.file.rotation.count = 30
log.file.rotation.size = 104857600
log.console.enabled = false
log.syslog.enabled = true
log.syslog.level = info
log.syslog.facility = local02. 开发环境日志配置
bash
log.console.enabled = true
log.console.level = debug
log.console.formatter = text
log.file.enabled = false3. 日志级别建议
| 环境 | 全局级别 | 连接级别 | 队列级别 |
|---|---|---|---|
| 开发 | debug | debug | debug |
| 测试 | info | info | info |
| 生产 | info | warning | warning |
