Skip to content

RabbitMQ 日志级别与分类

概述

RabbitMQ 的日志系统采用分层设计,支持全局日志级别和分类日志级别。合理配置日志级别可以在问题排查和性能之间取得平衡。本文将详细介绍 RabbitMQ 的日志级别体系和分类方法。

核心知识点

日志级别层次

debug < info < warning < error < critical < none
级别数值说明典型内容
debug128调试信息详细的内部状态
info64一般信息正常操作记录
warning48警告信息潜在问题提示
error32错误信息操作失败记录
critical16严重错误系统级故障
none0关闭日志无输出

日志分类

分类说明关键事件
connection连接相关连接建立、断开、认证
channel通道相关通道打开、关闭、操作
queue队列相关队列创建、删除、状态
federation联邦相关联邦链接、状态
mirroring镜像相关镜像同步、状态
shovelShovel 相关数据迁移状态
upgrade升级相关版本升级过程
default默认分类其他所有日志

日志级别继承关系

全局级别 (log.file.level)
    ├── 连接日志 (log.connection.level)
    ├── 通道日志 (log.channel.level)
    ├── 队列日志 (log.queue.level)
    ├── 联邦日志 (log.federation.level)
    ├── 镜像日志 (log.mirroring.level)
    └── 默认日志 (log.default.level)

配置示例

全局日志级别配置

bash
log.file.level = info

分类日志级别配置

bash
log.connection.level = debug
log.channel.level = info
log.queue.level = warning
log.federation.level = info
log.mirroring.level = info
log.shovel.level = info
log.upgrade.level = info
log.default.level = info

不同环境配置模板

bash
# 生产环境
log.file.level = info
log.connection.level = warning
log.channel.level = warning
log.queue.level = warning
log.federation.level = info
log.mirroring.level = info

# 测试环境
log.file.level = info
log.connection.level = info
log.channel.level = info
log.queue.level = info

# 开发环境
log.file.level = debug
log.connection.level = debug
log.channel.level = debug
log.queue.level = debug

PHP 日志级别管理类

php
<?php

class RabbitMQLogLevelManager
{
    private $configFile;
    private $validLevels = ['debug', 'info', 'warning', 'error', 'critical', 'none'];
    private $validCategories = [
        'connection', 'channel', 'queue', 'federation',
        'mirroring', 'shovel', 'upgrade', 'default'
    ];
    
    private $levelPriority = [
        'none' => 0,
        'critical' => 16,
        'error' => 32,
        'warning' => 48,
        'info' => 64,
        'debug' => 128,
    ];
    
    public function __construct($configFile = '/etc/rabbitmq/rabbitmq.conf')
    {
        $this->configFile = $configFile;
    }
    
    public function getValidLevels()
    {
        return $this->validLevels;
    }
    
    public function getValidCategories()
    {
        return $this->validCategories;
    }
    
    public function getCurrentLevels()
    {
        $levels = [
            'global' => 'info',
        ];
        
        foreach ($this->validCategories as $category) {
            $levels[$category] = null;
        }
        
        if (!file_exists($this->configFile)) {
            return $levels;
        }
        
        $content = file_get_contents($this->configFile);
        
        if (preg_match('/^log\.file\.level\s*=\s*(\w+)/m', $content, $m)) {
            $levels['global'] = $m[1];
        }
        
        foreach ($this->validCategories as $category) {
            $pattern = '/^log\.' . preg_quote($category, '/') . '\.level\s*=\s*(\w+)/m';
            if (preg_match($pattern, $content, $m)) {
                $levels[$category] = $m[1];
            }
        }
        
        return $levels;
    }
    
    public function setLevel($level, $category = null)
    {
        if (!in_array($level, $this->validLevels)) {
            throw new InvalidArgumentException("Invalid log level: {$level}");
        }
        
        if ($category !== null && !in_array($category, $this->validCategories)) {
            throw new InvalidArgumentException("Invalid category: {$category}");
        }
        
        $key = $category ? "log.{$category}.level" : 'log.file.level';
        $this->updateConfig($key, $level);
        
        return true;
    }
    
    public function setMultipleLevels(array $levels)
    {
        foreach ($levels as $category => $level) {
            if ($category === 'global') {
                $this->setLevel($level, null);
            } else {
                $this->setLevel($level, $category);
            }
        }
        
        return true;
    }
    
    public function getEffectiveLevel($category)
    {
        $levels = $this->getCurrentLevels();
        
        if (isset($levels[$category]) && $levels[$category] !== null) {
            return $levels[$category];
        }
        
        return $levels['global'];
    }
    
    public function shouldLog($level, $category = null)
    {
        $effectiveLevel = $this->getEffectiveLevel($category ?: 'default');
        
        $levelValue = $this->levelPriority[$level] ?? 0;
        $effectiveValue = $this->levelPriority[$effectiveLevel] ?? 0;
        
        return $levelValue <= $effectiveValue;
    }
    
    public function increaseLogLevel($category = null)
    {
        $currentLevel = $this->getEffectiveLevel($category);
        $currentIndex = array_search($currentLevel, $this->validLevels);
        
        if ($currentIndex > 0) {
            $newLevel = $this->validLevels[$currentIndex - 1];
            $this->setLevel($newLevel, $category);
            return $newLevel;
        }
        
        return $currentLevel;
    }
    
    public function decreaseLogLevel($category = null)
    {
        $currentLevel = $this->getEffectiveLevel($category);
        $currentIndex = array_search($currentLevel, $this->validLevels);
        
        if ($currentIndex < count($this->validLevels) - 1) {
            $newLevel = $this->validLevels[$currentIndex + 1];
            $this->setLevel($newLevel, $category);
            return $newLevel;
        }
        
        return $currentLevel;
    }
    
    public function enableDebugMode()
    {
        return $this->setMultipleLevels([
            'global' => 'debug',
            'connection' => 'debug',
            'channel' => 'debug',
            'queue' => 'debug',
        ]);
    }
    
    public function disableDebugMode()
    {
        return $this->setMultipleLevels([
            'global' => 'info',
            'connection' => 'warning',
            'channel' => 'warning',
            'queue' => 'warning',
        ]);
    }
    
    public function getLevelDescription($level)
    {
        $descriptions = [
            'debug' => '调试级别,输出所有详细信息,适合问题排查',
            'info' => '信息级别,输出正常操作信息,适合日常运维',
            'warning' => '警告级别,输出潜在问题提示',
            'error' => '错误级别,仅输出错误信息',
            'critical' => '严重级别,仅输出严重错误',
            'none' => '关闭日志输出',
        ];
        
        return $descriptions[$level] ?? '未知级别';
    }
    
    public function getCategoryDescription($category)
    {
        $descriptions = [
            'connection' => '连接相关日志,包括连接建立、断开、认证等',
            'channel' => '通道相关日志,包括通道打开、关闭、操作等',
            'queue' => '队列相关日志,包括队列创建、删除、状态变化等',
            'federation' => '联邦相关日志,包括联邦链接状态、消息同步等',
            'mirroring' => '镜像相关日志,包括镜像同步、主从切换等',
            'shovel' => 'Shovel 相关日志,包括数据迁移状态',
            'upgrade' => '升级相关日志,包括版本升级过程',
            'default' => '默认分类,其他所有未分类的日志',
        ];
        
        return $descriptions[$category] ?? '未知分类';
    }
    
    public function generateConfigReport()
    {
        $levels = $this->getCurrentLevels();
        
        $report = "RabbitMQ 日志级别配置报告\n";
        $report .= str_repeat("=", 50) . "\n\n";
        
        $report .= "全局日志级别: {$levels['global']}\n";
        $report .= "说明: " . $this->getLevelDescription($levels['global']) . "\n\n";
        
        $report .= "分类日志级别:\n";
        $report .= str_repeat("-", 40) . "\n";
        
        foreach ($this->validCategories as $category) {
            $level = $levels[$category];
            $effective = $level ?: $levels['global'] . ' (继承全局)';
            
            $report .= sprintf(
                "%-12s: %s\n",
                $category,
                $effective
            );
        }
        
        return $report;
    }
    
    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 = rtrim($content) . "\n{$replacement}\n";
        }
        
        $this->ensureConfigDir();
        file_put_contents($this->configFile, $content);
    }
    
    private function ensureConfigDir()
    {
        $dir = dirname($this->configFile);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
    }
}

实际应用场景

场景一:动态调整日志级别

php
<?php

class DynamicLogLevelAdjuster
{
    private $manager;
    private $stateFile;
    
    public function __construct(RabbitMQLogLevelManager $manager, $stateFile = '/tmp/rabbitmq_log_state.json')
    {
        $this->manager = $manager;
        $this->stateFile = $stateFile;
    }
    
    public function enableDebugForTroubleshooting($duration = 3600)
    {
        $previousState = $this->manager->getCurrentLevels();
        $this->saveState($previousState);
        
        $this->manager->enableDebugMode();
        
        $this->scheduleRevert($duration);
        
        return [
            'message' => 'Debug mode enabled',
            'duration' => $duration,
            'previous_state' => $previousState,
        ];
    }
    
    public function revertToPreviousState()
    {
        $previousState = $this->loadState();
        
        if ($previousState) {
            $this->manager->setMultipleLevels($previousState);
            $this->clearState();
            
            return [
                'message' => 'Reverted to previous state',
                'state' => $previousState,
            ];
        }
        
        return [
            'message' => 'No previous state found',
        ];
    }
    
    public function adjustForHighLoad()
    {
        return $this->manager->setMultipleLevels([
            'global' => 'warning',
            'connection' => 'error',
            'channel' => 'error',
            'queue' => 'warning',
        ]);
    }
    
    public function adjustForMaintenance()
    {
        return $this->manager->setMultipleLevels([
            'global' => 'debug',
            'connection' => 'debug',
            'channel' => 'debug',
            'queue' => 'debug',
            'mirroring' => 'debug',
        ]);
    }
    
    private function saveState(array $state)
    {
        file_put_contents($this->stateFile, json_encode($state));
    }
    
    private function loadState()
    {
        if (file_exists($this->stateFile)) {
            return json_decode(file_get_contents($this->stateFile), true);
        }
        return null;
    }
    
    private function clearState()
    {
        if (file_exists($this->stateFile)) {
            unlink($this->stateFile);
        }
    }
    
    private function scheduleRevert($duration)
    {
        $script = __DIR__ . '/revert_log_level.php';
        $command = sprintf(
            '(sleep %d && php %s) > /dev/null 2>&1 &',
            $duration,
            $script
        );
        
        exec($command);
    }
}

场景二:基于时间的日志级别调整

php
<?php

class ScheduledLogLevelManager
{
    private $manager;
    private $schedule;
    
    public function __construct(RabbitMQLogLevelManager $manager)
    {
        $this->manager = $manager;
        $this->schedule = [
            'business_hours' => [
                'start' => '09:00',
                'end' => '18:00',
                'levels' => [
                    'global' => 'info',
                    'connection' => 'warning',
                    'channel' => 'warning',
                ],
            ],
            'off_hours' => [
                'start' => '18:00',
                'end' => '09:00',
                'levels' => [
                    'global' => 'warning',
                    'connection' => 'error',
                    'channel' => 'error',
                ],
            ],
            'weekend' => [
                'days' => [0, 6],
                'levels' => [
                    'global' => 'warning',
                    'connection' => 'error',
                    'channel' => 'error',
                ],
            ],
        ];
    }
    
    public function applyScheduledLevel()
    {
        $now = new DateTime();
        $dayOfWeek = (int)$now->format('w');
        $time = $now->format('H:i');
        
        if (isset($this->schedule['weekend']['days']) &&
            in_array($dayOfWeek, $this->schedule['weekend']['days'])) {
            return $this->applyLevels($this->schedule['weekend']['levels'], 'weekend');
        }
        
        if ($this->isInTimeRange($time, $this->schedule['business_hours'])) {
            return $this->applyLevels($this->schedule['business_hours']['levels'], 'business_hours');
        }
        
        return $this->applyLevels($this->schedule['off_hours']['levels'], 'off_hours');
    }
    
    private function isInTimeRange($time, $range)
    {
        $start = $range['start'];
        $end = $range['end'];
        
        if ($start <= $end) {
            return $time >= $start && $time < $end;
        }
        
        return $time >= $start || $time < $end;
    }
    
    private function applyLevels($levels, $scheduleName)
    {
        $this->manager->setMultipleLevels($levels);
        
        return [
            'schedule' => $scheduleName,
            'applied_levels' => $levels,
            'timestamp' => date('Y-m-d H:i:s'),
        ];
    }
    
    public function getCurrentSchedule()
    {
        return $this->schedule;
    }
    
    public function setSchedule($name, array $config)
    {
        $this->schedule[$name] = $config;
        return true;
    }
}

场景三:日志级别监控

php
<?php

class LogLevelMonitor
{
    private $manager;
    private $alertThresholds;
    
    public function __construct(RabbitMQLogLevelManager $manager)
    {
        $this->manager = $manager;
        $this->alertThresholds = [
            'max_debug_duration' => 7200,
            'production_min_level' => 'info',
        ];
    }
    
    public function checkLogLevelCompliance()
    {
        $issues = [];
        $levels = $this->manager->getCurrentLevels();
        
        if ($levels['global'] === 'debug') {
            $issues[] = [
                'severity' => 'warning',
                'message' => '全局日志级别设置为 debug,可能影响性能',
                'recommendation' => '建议在问题排查完成后恢复为 info 或更高',
            ];
        }
        
        foreach (['connection', 'channel', 'queue'] as $category) {
            $level = $levels[$category];
            if ($level === 'debug') {
                $issues[] = [
                    'severity' => 'info',
                    'message' => "{$category} 日志级别为 debug",
                    'recommendation' => '确认是否需要 debug 级别日志',
                ];
            }
        }
        
        return [
            'compliant' => empty($issues),
            'issues' => $issues,
            'current_levels' => $levels,
        ];
    }
    
    public function generateReport()
    {
        $levels = $this->manager->getCurrentLevels();
        $compliance = $this->checkLogLevelCompliance();
        
        $report = [
            'timestamp' => date('Y-m-d H:i:s'),
            'current_levels' => $levels,
            'compliance' => $compliance,
            'recommendations' => $this->generateRecommendations($levels),
        ];
        
        return $report;
    }
    
    private function generateRecommendations($levels)
    {
        $recommendations = [];
        
        if ($levels['global'] === 'debug') {
            $recommendations[] = '考虑将全局日志级别提高到 info 以减少性能影响';
        }
        
        if ($levels['connection'] === 'debug' && $levels['channel'] === 'debug') {
            $recommendations[] = '连接和通道同时为 debug 级别,建议仅在排查问题时启用';
        }
        
        return $recommendations;
    }
}

常见问题与解决方案

问题一:日志级别设置不生效

现象:修改配置后日志级别没有变化。

解决方案

bash
rabbitmqctl eval "logger:set_primary_config(level, info)."
rabbitmqctl eval "logger:set_module_level(rabbit_log_connection, info)."

问题二:Debug 日志过多影响性能

现象:开启 debug 后系统变慢。

解决方案

php
$manager->setMultipleLevels([
    'global' => 'info',
    'connection' => 'debug',
]);

问题三:无法追踪特定问题

现象:需要追踪特定分类的问题。

解决方案

bash
log.queue.level = debug
log.channel.level = debug

最佳实践

1. 日志级别选择原则

场景推荐级别
生产环境info
问题排查debug(临时)
高负载期间warning
维护窗口debug

2. 分类级别配置建议

bash
log.file.level = info
log.connection.level = warning
log.channel.level = warning
log.queue.level = warning
log.federation.level = info
log.mirroring.level = info

3. 动态调整策略

  • 问题排查时临时开启 debug
  • 设置自动恢复机制
  • 记录调整历史

相关链接