LoggerTop

This is a simple Logger for C++ with stream interface. It either logs to std::cout or to a file.

UsageTop

To log to std::coutTop

Just use:

#include "Logger.h"

LOG_INFO << "Server is running" << std::endl;
LOG_INFO << "Server is running for " << 42 << " hours" << std::endl;
LOG_INFO << "Server is running for 0x" << std::hex << 42 << std::dec " hours" 
    << std::endl;

results in:

(17-11-05 11:46:37): [Info] Server is running
(17-11-05 11:46:37): [Info] Server is running for 42 hours
(17-11-05 11:46:37): [Info] Server is running for 0x2a hours

To a log fileTop

#include "Logger.h"
// The directory where to store the log file.
// If this string is empty it logs to std::cout.
IO::Logger::logDir_ = logDir;
// If you used the logger before you must call Close()
IO::Logger::Close();
// Now call again
LOG_INFO << "Server is running" << std::endl;

Log rotationTop

To make some kind of log rotation when logging to a file, you could call Logger::Close(), e.g. once a day.

DownloadTop

TL;DRTop

Logger.h

#pragma once

#include <ostream>
#include <iostream>
#include <fstream>
#include <chrono>
#include <ctime>
#include <memory>
#include <string>

#if defined __GNUC__
#define __AB_PRETTY_FUNCTION__ __PRETTY_FUNCTION__
#elif defined _MSC_VER
#define __AB_PRETTY_FUNCTION__ __FUNCTION__
#endif

namespace IO {

/// Logger class with stream interface
class Logger
{
private:
    enum Mode
    {
        ModeStream,
        ModeFile
    };
    static std::unique_ptr<Logger> instance_;
    std::ostream& stream_;
    std::ofstream fstream_;
    bool nextIsBegin_;
    Mode mode_;
    using endlType = decltype(std::endl<char, std::char_traits<char>>);
public:
    static std::string logDir_;

    Logger(std::ostream& stream = std::cout) :
        stream_(stream),
        mode_(ModeStream),
        nextIsBegin_(true)
    {}
    Logger(const std::string& fileName) :
        fstream_(fileName),
        stream_(fstream_),
        mode_(ModeFile),
        nextIsBegin_(true)
    {}
    ~Logger()
    {
        if (mode_ == ModeFile)
        {
            fstream_.flush();
            fstream_.close();
        }
    }

    // Overload for std::endl only:
    Logger& operator << (endlType endl)
    {

        nextIsBegin_ = true;
        stream_ << endl;
        return *this;
    }

    template <typename T>
    Logger& operator << (const T& data)
    {
        if (nextIsBegin_)
        {
            //set time_point to current time
            std::chrono::time_point<std::chrono::system_clock> time_point;
            time_point = std::chrono::system_clock::now();
            std::time_t ttp = std::chrono::system_clock::to_time_t(time_point);
            tm p;
            localtime_s(&p, &ttp);
            char chr[50];
            strftime(chr, 50, "(%g-%m-%d %H:%M:%S)", (const tm*)&p);

            stream_ << chr << ": " << data;
            nextIsBegin_ = false;
        }
        else
        {
            stream_ << data;
        }
        return *this;
    }
    Logger& Error()
    {
        if (nextIsBegin_)
            (*this) << "[ERROR] ";
        return *this;
    }
    Logger& Info()
    {
        if (nextIsBegin_)
            (*this) << "[Info] ";
        return *this;
    }
    Logger& Warning()
    {
        if (nextIsBegin_)
            (*this) << "[Warning] ";
        return *this;
    }
#ifdef _DEBUG
    Logger& Debug()
    {
        if (nextIsBegin_)
            (*this) << "[Debug] ";
        return *this;
    }
#endif

    static void Close()
    {
        Logger::instance_.reset();
    }
    static Logger& Instance();
};

}

#define LOG_INFO (IO::Logger::Instance().Info())
#define LOG_WARNING (IO::Logger::Instance().Warning() << __AB_PRETTY_FUNCTION__ << "(): ")
#define LOG_ERROR (IO::Logger::Instance().Error() << __AB_PRETTY_FUNCTION__ << "(): ")
#ifdef _DEBUG
#define LOG_DEBUG (IO::Logger::Instance().Debug() << __AB_PRETTY_FUNCTION__ << "(): ")
#endif

Logger.cpp

#include "stdafx.h"
#include "Logger.h"

namespace IO {

std::unique_ptr<Logger> Logger::instance_ = nullptr;
std::string Logger::logDir_ = "";

Logger& Logger::Instance()
{
    if (!instance_)
    {
        if (!logDir_.empty())
        {
            std::chrono::time_point<std::chrono::system_clock> time_point;
            time_point = std::chrono::system_clock::now();
            std::time_t ttp = std::chrono::system_clock::to_time_t(time_point);
            tm p;
            localtime_s(&p, &ttp);
            char chr[50];
            strftime(chr, 50, "%g-%m-%d-%H-%M-%S", (const tm*)&p);
            std::string logFile = logDir_ + "/" + std::string(chr) + ".log";
            instance_ = std::make_unique<Logger>(logFile);
        }
        else
            instance_ = std::make_unique<Logger>();
    }
    return *instance_.get();
}

}