Generalized Log File in c++

4.4k Views Asked by At

I am trying to build a Log File in c++... Can anyone tell how multiple variables such as a string,integer be written onto the file... the write to the file part of code is written in a different function present in a different file (ex. log_file.h) linked to the main file..

example:

for(int i=0;i<3;i++)
{....}

I want to write each iteration value of i to the log file... I can do this by passing "value of i"-->in a string and "i"--> as an integer... but this will not work for all functions..

4

There are 4 best solutions below

0
On

If you want to do it in a C++ way then I think you should use streams and templates. Like the following:

#include <iostream>
#include <fstream>
#include <stdexcept>

class Logger
{
public:
    // Logger cannot exist without file.
    Logger() = delete;

    // Disable copy constructor  since std::ofstream is not copyable.
    Logger(Logger const&) = delete;

    // Constructor
    explicit Logger(std::string const& f_path)
        : log_file { f_path }
    {
        if (!log_file.is_open())
        {
            throw std::runtime_error("Unable to open log file");
        }
    }

    // Disable copy.
    Logger& operator=(Logger const&) = delete;

    // Cleanup.
    ~Logger()
    {
        log_file.close();
    }

    // Write a single value into log file stream.
    template<typename T>
    void write(T const& v)
    {
        log_file << v;
    }

    // Write multiple values.
    template<typename Arg, typename ...Args>
    void write(Arg const& arg, Args const&... args)
    {
        // here we write the first value of the values list.
        write(arg);
        // here we recursively pass the rest values to the function.
        write(args...);
    }
private:
    // Log file stream.
    std::ofstream log_file;
};

int main(int argc, char* argv[])
{
    Logger l { "test.log" };
    l.write(1);
    l.write("qwe", 34);
    return 0;
}

As you see the logger depends on std::ofstream. So if you need to log some unsupported type you just need to make an overload for it. Like this:

// A custom type
struct MyType
{
    int id;
    std::string name;

    // an overload
    friend std::ofstream& operator<<(std::ofstream& ofs, MyType const& v)
    {
        ofs << "(" << v.id << ":" << v.name <<")";
    }
};

And then use it in main:

MyType person { 23, "John" };
l.write(person);
0
On

I do not get your problem. For a log-file, you could use something similar like this:

#include <fstream>
#include <string>
using namespace std;

string myString = "bla";

ofstream out;
out.open("myLog.dat"); // ios::app or ios::trunc, check it in the documentation what you need
if (out.is_open()) {
  for (int i = 0; i < I; i++) {
    out << i << "," << myString << endl;
    out << i*3 << endl;
  }
}
else
  throwError();

Please specify your problem.

0
On

You can define the log method something like this

void Log(uint16_t level, const char * format, ...)

using va_list you can format your log

char buffer[4096] = { 0 };
va_list argList;
va_start(argList, format);
vsprintf(buffer, format, argList);
va_end(argList);

now buffer holds the formatted log message, you can use buffer to write into a file, print to console etc

Usage

for(int i=0; i<10; i++)
    Log(1, "%d iteration = %s", i, "hello");

in you buffer you will get

0 iteration hello
1 iteration hello
....
9 iteration hello

Use level to identify the type of log message

0
On

You can implement printf like function which will log the parameters to a log file using variable argument list.

#include <stdarg.h>     /* va_list, va_start, va_arg, va_end */

void logger(const char *_pcFormat, ...)
{
    char cszFilePath[] = "/var/tmp/mylog.txt";


    //assuming each log line will be less than equal to 2048 bytes.
    char cszLine[2048] = {0};

    //optional: you can even log the time, uncomment the following 2 lines, if required
    //time_t ulTime = time(NULL);
    //snprintf(cszLine, sizeof(cszLine), "%02d:%02d:%02d ", stTime.tm_hour, stTime.tm_min, stTime.tm_sec);

    va_list aptr;
    va_start(aptr, _pcFormat);
    char *pcLine = cszLine;
    vsprintf(pcLine + strlen(cszLine), _pcFormat, aptr);
    va_end(aptr);

    FILE *fp = fopen(cszFilePath, "a+");
    if(fp == NULL)
    {
            return;
    }

    fprintf(fp, "%s\n", cszLine);

    fclose(fp);
    fp = NULL;
} 

UPDATE_1: In this version there will be no initial assumption on the length of line.

void logger(const char *_pcFormat, ...)
{
    char cszFilePath[] = "/var/tmp/mylog.txt";
    FILE *fp = fopen(cszFilePath, "a+");
    if(fp == NULL)
    {
            return;
    }        

    va_list aptr;
    va_start(aptr, _pcFormat);
    vfprintf(fp, _pcFormat, aptr);
    va_end(aptr);

    fclose(fp);
    fp = NULL;
}