简体   繁体   中英

c++ Static member function in logging class

For learning purposes, I am doing static class for logging. I have function "startLog" which delete any file with same name and open file for writing. And I have fuction "log" which print into file some text and it works. However when this function is called from "startLog", no writing to file is done.

Expected result in log.log file:
[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

However after running it there is only this in log.log file:
[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;
}

note: there is utilities.hpp and utilities.cpp to get formatting time point and it works fine, so I do not included code here.

Log::startLog can never result in the log file being opened since the s_logFile is set to the default parameter of the log call. There's no file opened initially either, since passing the empty string to the constructor of std::fstream does not result in the file being opened.

You probably want something like

class Log
{
...
    static inline std::string                   s_logFile; // empty initially; will result in opening the file stream the first time a file name is passed to log
    static inline std::fstream                  s_outf; // not opened initially as before (opening file "" fails)
...
};
void Log::startLog(const std::string& logFile)
{
    remove(s_logFile.c_str());
    log("Log opening ... " + s_logFile, Log::INFO, logFile);
}

Furthermore you should listen to your compiler warnings:

In

s_logFile = std::move(logFile);

you're moving a const lvalue reference. You should simply use the copy assignment operator instead.

Does your Code even compile? You have a weird typo in the initialization of testCycles in your Main function. Probably the loop is called zero times. Also static means, that your member variable s_logFile is global. You call it twice with two different paramters. I dont think it will do, what you intended.

Last: Google about ifstream/ofstream. If you use it properly, you don't need to call open/close.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM