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

C++静态日志类startLog调用log无写入问题求助

静态日志类startLog内部调用log无写入的问题

我正在实现一个静态日志类,其中startLog函数负责删除同名文件并准备写入,log函数负责写入日志内容。目前单独调用log能正常写入,但在startLog内部调用log时,日志内容并未写入目标文件。

期望日志内容(log.log)

[INFO] 2022-07-29 20:04:07.?????? | log.cpp:34: void startLog (const std::string&) | Log opening ... log.log
[DEBUG] 2022-07-29 20:04:07.465570 | main.cpp:15: int main(int, char**) | TEST1 - START!
[DEBUG] 2022-07-29 20:04:08.547214 | main.cpp:22: int main(int, char**) | TEST1 - END!

实际日志内容(log.log)

[DEBUG] 2022-07-29 20:04:07.465570 | main.cpp:15: int main(int, char**) | TEST1 - START!
[DEBUG] 2022-07-29 20:04:08.547214 | main.cpp:22: int main(int, char**) | TEST1 - END!


main.cpp

#include "log.hpp"

#include <iostream>

int main(int, char*[])
{
    std::string logFile {"log.log"};
    Log::startLog (logFile);
    Log::startLog ("log1.txt");
    int testCycles {100'000};


    Log::log ("TEST1 - START!", Log::DEBUG, logFile);

    for (int i = 0; i < testCycles; ++i)
    {
        Log::log("TEST" + std::to_string(i), Log::INFO, "log1.txt");
    }

    Log::log ("TEST1 - END!", Log::DEBUG, logFile);



    return EXIT_SUCCESS;

}

log.hpp

#ifndef LOG_HPP
#define LOG_HPP

#include <fstream>
#include <source_location>
#include <string>
#include <string_view>

class Log
{
    public:
        enum
        {
            INFO,
            DEBUG,
            WARNING,
            ERROR,
            FATAL,
        };

        static void log                             (std::string_view errorMsg, int severity = Log::INFO, const std::string& logFile = s_logFile,
                                                                const std::source_location location = std::source_location::current());
        static void startLog                        (const std::string& logFile = "log.log");
        static std::string getLogFile               (){return s_logFile;};
        static void setLogLevel                     (int logLevel);

    private:
        static inline std::string                   s_logFile;
        static inline std::fstream                  s_outf {s_logFile, std::ios::app};
        static inline std::string                   s_logMsg [] = {"[INFO]", "[DEBUG]", "[WARNING]","[ERROR]", "[FATAL]"};
        static inline int                           s_logLevel = Log::INFO;
        Log                                         (){};


};

#endif // LOG_HPP_INCLUDED

log.cpp

#include "log.hpp"
#include "utilities.hpp"

#include <filesystem>
#include <fstream>
#include <iomanip>
#include <string_view>

void Log::log                               (std::string_view errorMsg, int severity, const std::string& logFile, const std::source_location location)
{
    if (severity < Log::INFO)               severity = Log::INFO;
    else if (severity > Log::FATAL)         severity = Log::FATAL;
    if (severity < s_logLevel)              return;
    if (logFile != s_logFile)
    {
        s_outf.close();
        s_outf.open (logFile, std::ios::app);
        s_logFile = std::move (logFile);
    }
    s_outf
        << std::left << std::setw(10) << s_logMsg[severity]
        << Util::getTimeMillisec() << " | "
        << std::filesystem::path(location.file_name()).filename().string() << ":" << location.line() << ": " << location.function_name() << " | "
        << errorMsg <<'\n';

    // should be optimized in C++23 using location.resource_file to get filename instead of using std::filesystem

}

void Log::startLog                          (const std::string& logFile)
{
    s_logFile = logFile;
    remove (s_logFile.c_str());
    log ("Log opening ... " + s_logFile);
}

void Log::setLogLevel                       (int logLevel)
{
    if (logLevel < 0)                       s_logLevel = 0;
    else if (logLevel > Log::FATAL)         s_logLevel = Log::FATAL;
    else                                    s_logLevel = logLevel;
}

注:utilities.hpp和utilities.cpp用于格式化时间戳,功能正常,此处未附上代码。


问题原因分析

  1. 静态成员初始化顺序问题:静态成员s_outf初始化时,s_logFile还是空字符串,导致s_outf初始化为无效的文件流。
  2. startLog逻辑漏洞:设置s_logFile并删除文件后,调用log时因logFile与s_logFile相等,不会执行open操作,直接使用了之前无效的s_outf流,写入失败。
  3. 文件打开模式问题:删除文件后未重新以正确模式打开流,app模式无法自动修复无效的流句柄。

修复方案

1. 修正startLog函数

删除文件后主动重新打开流,确保流有效:

void Log::startLog(const std::string& logFile)
{
    s_logFile = logFile;
    s_outf.close();
    remove(s_logFile.c_str());
    s_outf.open(s_logFile, std::ios::out | std::ios::app);
    log("Log opening ... " + s_logFile);
}

2. 调整静态成员初始化逻辑

延迟初始化文件流,避免空路径初始化:
在log.hpp中修改静态成员声明:

private:
    static inline std::string s_logFile;
    static inline std::fstream s_outf; // 不在这里初始化
    // 其他成员不变

在log函数中增加流有效性检查:

void Log::log(std::string_view errorMsg, int severity, const std::string& logFile, const std::source_location location)
{
    if (severity < Log::INFO) severity = Log::INFO;
    else if (severity > Log::FATAL) severity = Log::FATAL;
    if (severity < s_logLevel) return;

    if (logFile != s_logFile || !s_outf.is_open())
    {
        s_outf.close();
        s_outf.open(logFile, std::ios::out | std::ios::app);
        s_logFile = logFile;
    }

    // 写入逻辑不变
}

3. 增加流有效性判断(可选)

写入前检查流状态,避免无效操作:

if (!s_outf) {
    std::cerr << "Failed to write log to file: " << logFile << std::endl;
    return;
}

修复后验证

修改后,startLog内部调用log时,文件流已被正确打开,日志内容会正常写入目标文件,符合预期输出。

内容的提问来源于stack exchange,提问作者Tomáš Nadrchal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 14:15:41