//
// logger.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2013 Zhu Nengjie (dotphoenix@qq.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "logger.hpp"
logger* logger::instance_ = NULL;
boost::mutex logger::mutex_;
logger::logger():io_service_(), socket_(io_service_), callback_(NULL),
show_level_(LEVEL_WARNING), destination_(DESTINATION_CONSOLE)
{
}
logger::~logger()
{
show_level_ = LEVEL_NONE;
destination_ = DESTINATION_NONE;
close_file_if_opened();
close_socket_if_connected();
callback_ = NULL;
}
void logger::close_file_if_opened()
{
if(file_.is_open())
{
file_.flush();
file_.close();
}
}
void logger::close_socket_if_connected()
{
if(socket_.is_open())
{
boost::system::error_code ignored_ec;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
socket_.close(ignored_ec);
}
}
std::string logger::get_path()
{
boost::filesystem::path rootpath = boost::filesystem::initial_path<boost::filesystem::path>();
boost::filesystem::path logpath = rootpath / "logger";
logpath += boost::filesystem::path::preferred_separator;
if(!boost::filesystem::exists(logpath))
{
boost::system::error_code ec;
boost::filesystem::create_directory(logpath, ec);
assert(ec);
}
return logpath.string();
}
std::string logger::current_time()
{
std::string current_time = boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time());
/* 这时候strTime里存放时间的格式是YYYYMMDDTHHMMSS,日期和时间用大写字母T隔开了 */
size_t pos = current_time.find('T');
current_time.replace(pos,1,std::string("-"));
current_time.replace(pos + 3,0,std::string(":"));
current_time.replace(pos + 6,0,std::string(":"));
return current_time;
}
void logger::set_filename(const std::string& filename)
{
boost::mutex::scoped_lock lock(mutex_);
destination_ = DESTINATION_FILE;
filename_ = filename;
close_file_if_opened();
file_.open(filename_.c_str(), std::ios_base::out | std::ios_base::app);
}
void logger::set_callback(log_function fun)
{
boost::mutex::scoped_lock lock(mutex_);
destination_ = DESTINATION_CALLBACK;
callback_ = fun;
}
void logger::set_logserver(const std::string& logserver_ip, unsigned short logserver_port)
{
boost::mutex::scoped_lock lock(mutex_);
destination_ = DESTINATION_SOCKET;
logserver_ip_ = logserver_ip;
logserver_port_ = logserver_port;
try
{
close_socket_if_connected();
boost::asio::ip::tcp::resolver resolver(io_service_);
std::stringstream stream;
stream<<logserver_port_;
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), logserver_ip_.c_str(), stream.str());
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::connect(socket_, iterator);
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
close_socket_if_connected();
}
}
void logger::log(const char* domain, LEVEL level, const char* format, ...)
{
std::string smsg;
{
boost::mutex::scoped_lock lock(mutex_);
va_list arg_ptr;
static char msg[4096] = {0};
va_start(arg_ptr, format);
vsnprintf(msg, 4096 - 2, format, arg_ptr);
va_end(arg_ptr);
smsg = msg;
}
log(domain, level, smsg);
}
void logger::log(const char* domain, LEVEL level, const std::string& msg)
{
boost::mutex::scoped_lock lock(mutex_);
if(level <= show_level_)
{
std::string slevel;
switch(level)
{
case LEVEL_INFO:
slevel = "<Info> ";
break;
case LEVEL_DEBUG:
slevel = "<Debug> ";
break;
case LEVEL_WARNING:
slevel = "<Warning> ";
break;
case LEVEL_ERROR:
slevel = "<Error> ";
break;
case LEVEL_FATAL:
slevel = "<Fatal> ";
break;
default:
slevel = "<None>";
break;
}
std::stringstream stream;
stream<<"["<<domain<<"]"<<slevel
<<"["<<current_time()<<"]"
<<" "<<msg.c_str()<<"\n";
switch(destination_)
{
case DESTINATION_CONSOLE:
{
fprintf(stdout, "%s", (const char*)stream.str().c_str());
break;
}
case DESTINATION_FILE:
{
if(file_.is_open())
{
file_<<stream.str();
}
break;
}
case DESTINATION_SOCKET:
{
if(socket_.is_open())
{
std::size_t written = 0;
try
{
size_t len = stream.str().length();
written = boost::asio::write(socket_, boost::asio::buffer((void*)&len, sizeof(size_t)));
written = boost::asio::write(socket_, boost::asio::buffer((void*)stream.str().c_str(), stream.str().length()));
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
break;
}
case DESTINATION_CALLBACK:
{
if(callback_ != NULL)
{
callback_(stream.str().c_str());
}
break;
}
}
}
}
void logger_init(LEVEL show_level)
{
logger::get_instance()->set_level(show_level);
}
void logger_init(LEVEL show_level, const std::string& filename)
{
logger::get_instance()->set_level(show_level);
logger::get_instance()->set_filename(filename);
}
void logger_init(LEVEL show_level, const std::string& logserver_ip, unsigned short logserver_port)
{
logger::get_instance()->set_level(show_level);
logger::get_instance()->set_logserver(logserver_ip, logserver_port);
}
void logger_init(LEVEL show_level, log_function callback)
{
logger::get_instance()->set_level(show_level);
logger::get_instance()->set_callback(callback);
}
void logger_log(const char* domain, LEVEL level, const char* format, ...)
{
va_list arg_ptr;
static char msg[4096] = {0};
va_start(arg_ptr, format);
vsnprintf(msg, 4096 - 2, format, arg_ptr);
va_end(arg_ptr);
logger::get_instance()->log(domain, level, std::string(msg));
}
void logger_uninit()
{
logger::get_instance()->free_instance();
}
void logger_set_level(LEVEL show_level)
{
logger::get_instance()->set_level(show_level);
}
void logger_set_callback(log_function callback)
{
logger::get_instance()->set_callback(callback);
}
void logger_set_filename(const std::string& filename)
{
logger::get_instance()->set_filename(filename);
}
void logger_set_logserver(const std::string& logserver_ip, unsigned short logserver_port)
{
logger::get_instance()->set_logserver(logserver_ip, logserver_port);
}
std::string logger_get_path()
{
return logger::get_instance()->get_path();
}
void logger_tester_callback(const char* msg)
{
fprintf(stdout, "%s ", (char*)msg);
}
/*
I did not implement a tcp server here, you can go to www.boost.org/docs to get a normal tcp server(search boost
asio tcp server on google), or you also can contact with me(dotphoenix@qq.com), I will help you.
*/
void logger_tester_tcpserver_start()
{
}
void logger_tester_tcpserver_stop()
{
}
void logger_tester()
{
//测试console
logger_init(LEVEL_DEBUG);
logger_log("console test", LEVEL_WARNING, "console test warning");
logger_log("console test", LEVEL_DEBUG, "console test debug");
logger_log("console test", LEVEL_INFO, "console test info");
std::string log_file = logger_get_path() + "log_file.log";
logger_set_filename(log_file);
logger_log("file test", LEVEL_WARNING, "file test warning");
logger_log("file test", LEVEL_DEBUG, "file test debug");
logger_log("file test", LEVEL_INFO, "file test info");
logger_set_callback(logger_tester_callback);
logger_set_level(LEVEL_WARNING);
logger_log("callback test", LEVEL_WARNING, "callback test warning");
logger_log("callback test", LEVEL_DEBUG, "callback test debug");
logger_log("callback test", LEVEL_INFO, "callback test info");
logger_uninit();
std::string