You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下boost::log彩色输出偏移问题求稳定修复方案

修复Windows下boost::log多日志源彩色输出错位的稳定方案

我之前在做Windows下的boost::log彩色输出时,也踩过一模一样的坑!用Win32 API直接改控制台颜色,在多日志源或者并发场景下,哪怕已经把sink设成同步模式,还是会出现颜色错位、部分行颜色不对的问题——核心原因就是设置颜色和输出日志这两个操作不是原子的,多个线程同时操作控制台时,颜色设置会被互相干扰。下面是我验证过的稳定修复方法:

核心思路

要保证「设置颜色→输出日志→恢复原颜色」这一整套操作是原子执行的,避免多个线程的控制台操作互相穿插。单纯依赖boost::log sink的同步机制不够,因为sink的同步只保证日志记录的处理顺序,但控制台是全局资源,需要额外的全局锁来保护整个输出流程。

具体实现步骤

1. 定义全局互斥锁

用来保护控制台的颜色设置和输出操作,确保同一时间只有一个线程在操作:

#include <mutex>
#include <windows.h>

// 全局互斥锁,保护控制台操作
std::mutex g_console_output_mutex;

2. 自定义带原子颜色控制的sink格式化器

修改你的console sink,在格式化器里包裹锁,把颜色设置、日志输出、颜色恢复做成原子操作:

#include <boost/log/core.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>

namespace logging = boost::log;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;

void setup_colorful_logging() {
    // 创建同步控制台sink
    auto sink = boost::make_shared<sinks::synchronous_sink<sinks::basic_text_ostream_backend<char>>>();
    sink->locked_backend()->add_stream(boost::shared_ptr<std::ostream>(&std::cout, boost::null_deleter()));

    // 获取标准输出控制台句柄
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hConsole == INVALID_HANDLE_VALUE) {
        // 处理句柄获取失败的情况
        return;
    }

    // 设置格式化器,包含原子颜色控制
    sink->set_formatter([hConsole](const logging::record_view& rec, logging::formatting_ostream& strm) {
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        GetConsoleScreenBufferInfo(hConsole, &csbi);
        const WORD original_color = csbi.wAttributes; // 保存原控制台颜色

        // 根据日志级别设置目标颜色
        WORD target_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; // 默认白色
        auto severity = rec[logging::trivial::severity];
        if (severity == logging::trivial::error) {
            target_color = FOREGROUND_RED | FOREGROUND_INTENSITY; // 亮红色
        } else if (severity == logging::trivial::warning) {
            target_color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; // 亮黄色
        }

        // 加锁,保证颜色设置和输出的原子性
        std::lock_guard<std::mutex> lock(g_console_output_mutex);
        SetConsoleTextAttribute(hConsole, target_color);
        strm << rec[expr::smessage]; // 输出日志内容
        SetConsoleTextAttribute(hConsole, original_color); // 恢复原颜色
    });

    // 将sink添加到日志核心
    logging::core::get()->add_sink(sink);
}

关键细节说明

  • 全局锁的必要性:哪怕是同步sink,boost::log的同步只保证sink内部的日志处理顺序,但控制台是全局共享资源,多个sink或多线程操作时必须用全局锁来避免交叉操作。
  • 恢复原颜色:每次输出后必须恢复控制台的原始颜色,否则后续非日志的控制台输出(比如用户输入提示)会继承日志的颜色,导致混乱。
  • 兼容性:这种方案不依赖ANSI转义码,兼容所有Windows版本(包括Win7及以上),不需要开启控制台的ANSI支持。

额外优化(可选)

如果你的日志有复杂的格式(比如包含时间、线程ID等),可以把所有格式化操作都放在锁内执行,确保整个日志行的输出是连续的,避免被其他线程打断。

内容的提问来源于stack exchange,提问作者Vojtek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:39:27