Skip to content

RabbitMQ 日志配置

概述

日志是运维排查问题的重要依据。RabbitMQ 提供了灵活的日志配置选项,可以控制日志输出位置、格式、级别等。本文将详细介绍 RabbitMQ 的日志配置方法和最佳实践。

核心知识点

日志输出目标

输出目标配置方式说明
标准输出log.console适合容器环境
文件log.file传统部署方式
Sysloglog.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 = false

Syslog 日志配置

bash
log.syslog.enabled = true
log.syslog.level = info
log.syslog.facility = daemon
log.syslog.identity = rabbitmq
log.syslog.app_name = rabbitmq

JSON 格式日志配置

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 = info

PHP 日志配置管理类

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 = local0

2. 开发环境日志配置

bash
log.console.enabled = true
log.console.level = debug
log.console.formatter = text

log.file.enabled = false

3. 日志级别建议

环境全局级别连接级别队列级别
开发debugdebugdebug
测试infoinfoinfo
生产infowarningwarning

相关链接