Program Listing for File LogFile.cpp

Return to documentation for file (necsim/LogFile.cpp)

// This file is part of necsim project which is released under MIT license.
// See file **LICENSE.txt** or visit https://opensource.org/licenses/MIT) for full license details.
#include <sstream>
#include <iomanip>
#include <boost/filesystem.hpp>
#include "LogFile.h"
#include "file_system.h"
#include "custom_exceptions.h"
namespace necsim
{
    string getTime()
    {
#ifdef DEBUG
        auto t = time(nullptr);
        auto tm = *localtime(&t);
        stringstream ss;
        ss << put_time(&tm, LOGNAME_FORMAT);
        return ss.str();
#endif
        return string("");
    }

    string getDefaultLogFile()
    {
        time_t now = time(0);
        static char name[30];
        strftime(name, sizeof(name), LOGNAME_FORMAT, localtime(&now));
        boost::filesystem::path full_path(boost::filesystem::current_path());
        string out = full_path.string() + "/log/" + string(name) + ".log";
        return out;
    }

    void getUniqueFileName(string &basic_string)
    {
        boost::filesystem::path file_path(basic_string);
        const string file_name = basic_string.substr(0, basic_string.find('.'));
        const string file_extension = basic_string.substr(basic_string.find('.'));
        unsigned long iterator = 0;
        while(boost::filesystem::exists(file_path))
        {
            if(iterator > 10000000)
            {
                basic_string = file_name + file_extension;
                throw FatalException("Could not create unique file name after 10000000 tries.");
            }
            basic_string = file_name + "_" + to_string(iterator) + file_extension; // NOLINT
            file_path = boost::filesystem::path(basic_string);
            iterator++;
        }
    }

    LogFile::LogFile()
    {
        init(getDefaultLogFile());
    }

    LogFile::LogFile(string file_name_in)
    {
        init(file_name_in);
    }

    LogFile::~LogFile()
    {

        output_stream << getTime() << " LOGGING ENDED" << endl;
        output_stream.close();
    }

    void LogFile::init(string file_name_in)
    {
        createParent(file_name_in);
        file_name = file_name_in;
        getUniqueFileName(file_name);
        output_stream.open(file_name);
        if(!output_stream)
        {
            // Throw runtime error to avoid problems of attempting to write py object out before the logger has been set.
            throw runtime_error("Could not create log file at " + file_name_in + ".");
        }
        levels_map[0] = "noneset";
        levels_map[10] = "debug";
        levels_map[20] = "info";
        levels_map[30] = "warning";
        levels_map[40] = "error";
        levels_map[50] = "critical";
        output_stream << getTime() << " LOGGING STARTED" << endl;
    }

    void LogFile::write(const int &level, string message)
    {
        if(levels_map.count(level) == 0)
        {
            throw FatalException("Logging level must be one of 0, 10, 20, 30, 40 or 50.");
        }
        output_stream << getTime() << " ";
        replace(message.begin(), message.end(), '\n', ' ');
        output_stream << levels_map[level] << ": " << message << endl;

    }

    void LogFile::write(const int &level, stringstream &message)
    {
        write(level, message.str());
    }

}