dmplogger.cpp 6.0 KB
/**************************************************************************
* file:              dmplogger.cpp

* Author:            wanzhongping
* Date:              2021-03-03 10:29:10
* Email:             zhongpingw@chinadci.com
* copyright:         广州城市信息研究所有限公司
***************************************************************************/

#include "dmplogger.h"
#include <iostream>
#include <fstream>
#include <boost/core/ref.hpp>
#include <boost/bind/bind.hpp>
#include <boost/log/common.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes/timer.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/from_stream.hpp>
#include <boost/log/utility/setup/filter_parser.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/format.hpp>
#include "dmpapplication.h"

namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
namespace attrs = boost::log::attributes;

static src::severity_logger< SeverityLevel > slg;
// static std::string sConfigName = DmpApplication::Instance()->libexecPath() + "log.config";
//static std::string sConfigName = "/usr/local/lib/dmap/log.config";

//! Formatting operator for severity levels
std::ostream& operator<< (std::ostream& strm, SeverityLevel level)
{
    static const char* const str[] =
    {
        "debug",
        "info",
        "warning",
        "error",
        "critical"
    };
    if (static_cast< std::size_t >(level) < (sizeof(str) / sizeof(*str)))
        strm << str[level];
    else
        strm << static_cast< int >(level);
    return strm;
}

//! Parsing operator for severity levels
std::istream& operator>> (std::istream& strm, SeverityLevel& level)
{
    if (strm.good())
    {
        std::string str;
        strm >> str;
        if (str == "debug")
            level = debug_level;
        else if (str == "info")
            level = info_level;
        else if (str == "warning")
            level = warn_level;
        else if (str == "error")
            level = error_level;
        else if (str == "critical")
            level = critical_level;
        else
            strm.setstate(std::ios_base::failbit);
    }

    return strm;
}

//! Our custom formatter for the scope list
struct scope_list_formatter
{
    typedef void result_type;
    typedef attrs::named_scope::value_type scope_stack;

    explicit scope_list_formatter(logging::attribute_name const& name) :
        name_(name)
    {
    }
    void operator()(logging::record_view const& rec, logging::formatting_ostream& strm) const
    {
        // We need to acquire the attribute value from the log record
        logging::visit< scope_stack >
        (
            name_,
            rec.attribute_values(),
            boost::bind(&scope_list_formatter::format, boost::placeholders::_1, boost::ref(strm))
        );
    }

private:
    //! This is where our custom formatting takes place
    static void format(scope_stack const& scopes, logging::formatting_ostream& strm)
    {
        scope_stack::const_iterator it = scopes.begin(), end = scopes.end();
        for (; it != end; ++it)
        {
            strm << it->scope_name << " (" << it->file_name << ":" << it->line << ")";
        }
    }

private:
    logging::attribute_name name_;
};

class my_scopes_formatter_factory : public logging::formatter_factory< char >
{
public:
    /*!
     * This function creates a formatter for the MyScopes attribute.
     * It effectively associates the attribute with the scope_list_formatter class
     */
    formatter_type create_formatter(logging::attribute_name const& attr_name, args_map const& args)
    {
        return formatter_type(scope_list_formatter(attr_name));
    }
};



DmpLogger::DmpLogger()
{
    // Init();
}

DmpLogger::~DmpLogger()
{
}

void DmpLogger::Init(const std::string &path)
{
    // First thing - register the custom formatter for MyScopes
    logging::register_formatter_factory("Scope", boost::make_shared< my_scopes_formatter_factory >());

    // Also register filter and formatter factories for our custom severity level enum. Since our operator<< and operator>> implement
    // all required behavior, simple factories provided by Boost.Log will do.
    logging::register_simple_filter_factory< SeverityLevel >("Severity");
    logging::register_simple_formatter_factory< SeverityLevel, char >("Severity");


    // Open the setting file

    std::ifstream settings(path);
    boost::format fmt = boost::format("Could not open %s file!") % path;
    
    if (!settings.is_open())
        // throw std::runtime_error("Could not open log.config file!");
        throw std::runtime_error(fmt.str());
    
    logging::init_from_stream(settings);

    // Also let's add some commonly used attributes, like timestamp and record counter.
    logging::add_common_attributes();
    logging::core::get()->add_thread_attribute("Scope", attrs::named_scope());

    slg.add_attribute("Uptime", attrs::timer());
}

void DmpLogger::Debug(const std::string &msg)
{
	BOOST_LOG_SEV(slg, debug_level) << msg;
}

void DmpLogger::Info(const std::string &msg)
{
	BOOST_LOG_SEV(slg, info_level) << msg;
}

void DmpLogger::Warn(const std::string &msg)
{
	BOOST_LOG_SEV(slg, warn_level) << msg;
}

void DmpLogger::Error(const std::string &msg)
{
	BOOST_LOG_SEV(slg, error_level) << msg;
}

void DmpLogger::Critical(const std::string &msg)
{
	BOOST_LOG_SEV(slg, critical_level) << msg;
}

void DmpLogger::SetLevel(SeverityLevel level)
{
    logging::core::get()->set_filter(expr::attr< SeverityLevel >("Severity") >= level);
}

DmpLogger *DmpLogger::Instance()
{
    static DmpLogger logger;
    return &logger;
}