0

This is my code for printing logs in C++. After compiling, when I tried to execute, it will return Segmentation fault in initLogger(). After some trying, I still can't find the solution. Since I don't clearly understand the operation of the file stream, I would like to ask for help. Thank you very much!

Logger.h:

#ifndef  __logger__
#define  __logger__

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <stdint.h>

///
/// \brief log type
///
typedef enum log_rank {
   INFO,
   WARNING,
   ERROR,
   FATAL
}log_rank_t;

///
/// \brief 初始化日志文件
/// \param info_log_filename info file
/// \param warn_log_filename warn file
/// \param error_log_filename error file

void initLogger(const std::string& info_log_filename,
                       const std::string& warn_log_filename,
                       const std::string& erro_log_filename){};


class Logger {

public:

   Logger(log_rank_t log_rank) : m_log_rank(log_rank) {};

   ~Logger(){};   

   static std::ostream& start(log_rank_t log_rank,
                               const int32_t line,
                               const std::string& function){};

   friend void initLogger(const std::string& info_log_filename,
                        const std::string& warn_log_filename,
                        const std::string& erro_log_filename);

private:
   static std::ostream& getStream(log_rank_t log_rank){};

   static std::ofstream m_info_log_file;                   ///< output stream of info file
   static std::ofstream m_warn_log_file;                  ///< op stream of warn file
   static std::ofstream m_error_log_file;                  ///< op stream of error file
   log_rank_t m_log_rank;                             ///< log rank
};
///
/// \brief write different files depend on the log rank
///
#define LOG(log_rank)   \
Logger(log_rank).start(log_rank, __LINE__,__FUNCTION__)

Logger.cpp

#include "Logger.h"
#include <cstdlib>
#include <ctime>

std::ofstream Logger::m_error_log_file;
std::ofstream Logger::m_info_log_file;
std::ofstream Logger::m_warn_log_file;

void initLogger(const std::string&info_log_filename,
                const std::string&warn_log_filename,
               const std::string&error_log_filename){
   Logger::m_info_log_file.open(info_log_filename.c_str());
   Logger::m_warn_log_file.open(warn_log_filename.c_str());
   Logger::m_error_log_file.open(error_log_filename.c_str());
}

std::ostream& Logger::getStream(log_rank_t log_rank){
   return (INFO == log_rank) ?
                (m_info_log_file.is_open() ?m_info_log_file : std::cout) :
                (WARNING == log_rank ?
                    (m_warn_log_file.is_open()? m_warn_log_file : std::cerr) :
                    (m_error_log_file.is_open()? m_error_log_file : std::cerr));
}

std::ostream& Logger::start(log_rank_t log_rank,
                            const int32_t line,
                            const std::string&function) {
   time_t tm;
   time(&tm);
   char time_string[128];
   ctime_r(&tm, time_string);
   return getStream(log_rank) << time_string
                               << "function (" << function << ")"
                               << "line " << line
                               <<std::flush;
}

Logger::~Logger(){
   getStream(m_log_rank) << std::endl << std::flush;

   if (FATAL == m_log_rank) {
       m_info_log_file.close();
       m_warn_log_file.close();
       m_error_log_file.close();
       abort();
    }
}

test.cpp

#include "Logger.h"
#include <iostream>
using namespace std;

int main(int argc, char** argv){
    initLogger("/log/info.txt","/log/warn.txt","/log/error.txt");
    cout<<"Initialized"<<endl;
    return 0;
}
  • Does this answer your question? [how to initialize static reference to std::ofstream?](https://stackoverflow.com/questions/10194253/how-to-initialize-static-reference-to-stdofstream) – NutCracker Apr 02 '20 at 07:43
  • 1
    This code doesn't look legal to me. `void initLogger(const std::string& info_log_filename, const std::string& warn_log_filename, const std::string& erro_log_filename){};` and `static std::ostream& start(log_rank_t log_rank, const int32_t line, const std::string& function){};` What are the `{}` doing there? – john Apr 02 '20 at 07:47
  • Unelated: [Fear the double underscore!](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) It doesn't bite very often, but when it does you wind up looking like Quint. Best if I don't post a link to that reference. – user4581301 Apr 02 '20 at 07:49
  • Same error here `static std::ostream& getStream(log_rank_t log_rank){};` – john Apr 02 '20 at 07:52
  • This code compiles and runs just fine if the illegal redefinitions mentioned by @john are removed (there are several in the header), and the header guard #endif is added. – RadioSilence Apr 02 '20 at 07:52
  • And here `~Logger(){};` – john Apr 02 '20 at 07:52
  • If I don't use {} after my statement, I will get this when I compiling: undefined reference to `initLogger(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&)'. – Josh Newman Apr 02 '20 at 07:53
  • I took your code, fixed the problems with the `{}` and it works, see here https://onlinegdb.com/H13JcfQw8 – john Apr 02 '20 at 07:53
  • @JoshNewman That's a linker error, it means you are failing to link the Logger.cpp file. Probably failing to compile it as well. – john Apr 02 '20 at 07:54
  • @john Thanks for your code, it does work. But how can I solve this link failure? It seems that I can not link the Logger.cpp file well. I didn't change other codes in that error. – Josh Newman Apr 02 '20 at 08:02
  • @JoshNewman What compiler are you using? Your error is not using your compiler correctly, not your code (apart from the `{}` that you added). – john Apr 02 '20 at 08:03
  • @john I compile this code by g++7.4.0. Using the command "g++ test.cpp -o test.o" – Josh Newman Apr 02 '20 at 08:06
  • @JoshNewman Then it's very easy, remove the `{}` and then try `g++ test.cpp Logger.cpp -o test.o` – john Apr 02 '20 at 08:07
  • @JoshNewman But `test.o` is an unusual name for an executable. .o files are normally object files. How are you running this code? – john Apr 02 '20 at 08:08
  • @john It does work! Thank you very much. I think I have misunderstood some operations about the compiler... – Josh Newman Apr 02 '20 at 08:14
  • @john I should put my linked cpp files together after g ++ xxx when compiling, is this right? – Josh Newman Apr 02 '20 at 08:16
  • @JoshNewman You can put the cpp files in any order. – john Apr 02 '20 at 08:18

0 Answers0