首页 > 代码库 > 參考mudo logging写的win下logging

參考mudo logging写的win下logging

#pragma once
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>

class CountDownLatch : boost::noncopyable
{
public:

	explicit CountDownLatch(int count);

	void wait();

	void countDown();

	int getCount();

private:
	boost::mutex			m_Mutex;
	boost::condition_variable m_ConditionVar;
	int count_;
};

#include "stdafx.h"
#include "CountDownLatch.h"


CountDownLatch::CountDownLatch(int count)
	: count_(count)
{
}

void CountDownLatch::wait()
{
	boost::mutex::scoped_lock lock(m_Mutex);
	while (count_ > 0) {
		m_ConditionVar.wait(lock);
	}
}

void CountDownLatch::countDown()
{
	boost::mutex::scoped_lock lock(m_Mutex);
	--count_;
	if (count_ == 0) {
		m_ConditionVar.notify_all();
	}
}

int CountDownLatch::getCount()
{
	boost::mutex::scoped_lock lock(m_Mutex);
	return count_;
}

#pragma once
#include <string>
#include <boost/noncopyable.hpp>
using namespace std;
const int kSmallBuffer = 4000;
const int kLargeBuffer = 4000*1000;

template<int SIZE>
class FixedBuffer : boost::noncopyable
{
public:
	FixedBuffer()
		: cur_(data_)
	{
		setCookie(cookieStart);
	}

	~FixedBuffer()
	{
		setCookie(cookieEnd);
	}

	void append(const char*  buf, size_t len)
	{
		if (static_cast<size_t>(avail()) > len)
		{
			memcpy(cur_, buf, len);
			cur_ += len;
		}
	}

	const char* data() const { return data_; }
	int length() const { return static_cast<int>(cur_ - data_); }

	// write to data_ directly
	char* current() { return cur_; }
	int avail() const { return static_cast<int>(end() - cur_); }
	void add(size_t len) { cur_ += len; }

	void reset() { cur_ = data_; }
	void bzero() { memset(data_, 0, sizeof(data_)); }
	void setCookie(void (*cookie)()) { cookie_ = cookie; }
	string asString() const { return string(data_, length()); }

private:
	const char* end() const { return data_ + sizeof data_; }
	// Must be outline function for cookies.
	static void cookieStart();
	static void cookieEnd();

	void (*cookie_)();
	char data_[SIZE];
	char* cur_;
};

#pragma once
#include <boost/date_time/posix_time/posix_time.hpp> 
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/atomic/atomic.hpp"
#include <queue>
#include <string>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include "FixedBuffer.h"
#include "CountDownLatch.h"

enum LoggingEnum{
	LOG_INFO,
	LOG_DBBUG,
	LOG_ERROR,
	LOG_WARNNING,
	LOG_END
};

enum GLogColor {
	COLOR_DEFAULT,
	COLOR_RED,
	COLOR_GREEN,
	COLOR_YELLOW
};

class Logging
{
public:
	Logging();
	~Logging();
	void	WriteWithFunLine(LoggingEnum eLoggingEnum, char* fun, int line, char* msg, ...);
	void	WriteMsg(LoggingEnum eLoggingEnum, char* fun, int line, char* msg);

private:
	int		CreateLogFile(LoggingEnum aLoggingEnum);
	void	Write(LoggingEnum eLoggingEnum, char* msg, int msgLen);
	void threadFunc();
private:
	bool running_;
	FILE*					m_File[LOG_END];
	typedef boost::posix_time::ptime PTIME;
	std::string					m_AppPreStr;
	typedef FixedBuffer<kLargeBuffer> Buffer;
	typedef boost::ptr_vector<Buffer> BufferVector;
	typedef BufferVector::auto_type BufferPtr;
	BufferPtr currentBuffer_;
	BufferPtr nextBuffer_;
	BufferVector buffers_;
	boost::thread			m_Thread;
	boost::mutex			m_Mutex;
	boost::condition_variable m_ConditionVar;
	CountDownLatch latch_;
};

#include "Logging.h"
#include <iomanip>
#include <sstream>
#include <fcntl.h>
#include <io.h>
#include <Windows.h>
#include "SSActive.h"

Logging g_Logging;
string LOGPreStr[LOG_END] = {"LOG_INFO", "LOG_DBBUG", "LOG_ERROR", "LOG_WARNNING"};

#ifdef _WINDOWS
// Returns the character attribute for the given color.
WORD GetColorAttribute(GLogColor color) {
	switch (color) {
	case COLOR_RED:    return FOREGROUND_RED;
	case COLOR_GREEN:  return FOREGROUND_GREEN;
	case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
	default:           return 0;
	}
}
#else
// Returns the ANSI color code for the given color.
const char* GetAnsiColorCode(GLogColor color) {
	switch (color) {
	case COLOR_RED:     return "1";
	case COLOR_GREEN:   return "2";
	case COLOR_YELLOW:  return "3";
	case COLOR_DEFAULT:  return "";
	};
	return NULL; // stop warning about return type.
}

#endif  // OS_WINDOWS

GLogColor GLogColorVec[LOG_END] = {COLOR_GREEN, COLOR_DEFAULT, COLOR_RED, COLOR_YELLOW};

Logging::Logging():latch_(1){
	currentBuffer_.reset(new Buffer);
	currentBuffer_->bzero();

	nextBuffer_.reset(new Buffer);
	nextBuffer_->bzero();

	buffers_.reserve(16);

	boost::mutex::scoped_lock lock(m_Mutex);
	char szAppPath[256] = "";
	::GetModuleFileNameA(0, szAppPath, 256);
	m_AppPreStr = szAppPath;
	m_AppPreStr = m_AppPreStr.substr(m_AppPreStr.rfind("\\") + 1);
	m_AppPreStr = m_AppPreStr.substr(0, m_AppPreStr.size()-4);

	int n32Res = 0;
	for (int i = LOG_INFO; i < LOG_END; ++i){
		m_File[i] = NULL;
	}

	n32Res = CreateLogFile(LOG_INFO);
	if (n32Res != 0){
		printf("Createfile(i) failed", 0);
	}

	lock.unlock();

	running_ = true;
	m_Thread = boost::thread(&Logging::threadFunc, this);
	latch_.wait();
}

void Logging::WriteWithFunLine(LoggingEnum eLoggingEnum, char* fun, int line, char* msg, ...){
	if (eLoggingEnum < LOG_INFO || eLoggingEnum > LOG_WARNNING){
		eLoggingEnum = eLoggingEnum;
	}

	char tmp[1024] = {0};
	PTIME nowTime = boost::posix_time::microsec_clock::local_time();
	sprintf(tmp, "%s.%d %s:%d ", boost::posix_time::to_iso_string(nowTime).c_str(), boost::this_thread::get_id(), fun, line);
	int curPos = strlen(tmp);

	va_list pArg = NULL;
	va_start(pArg, msg);
	vsprintf(tmp+curPos, msg, pArg);
	va_end(pArg);

	curPos = strlen(tmp);
	char end[] = "\n";
	sprintf(tmp + curPos, "%s", end);

	int totlen = curPos + 1;
	boost::mutex::scoped_lock lock(m_Mutex);
	if (currentBuffer_->avail() > totlen)
	{
		currentBuffer_->append(tmp, totlen);
	}
	else
	{
		buffers_.push_back(currentBuffer_.release());

		if (nextBuffer_)
		{
			currentBuffer_ = boost::ptr_container::move(nextBuffer_);
		}
		else
		{
			currentBuffer_.reset(new Buffer); // Rarely happens
		}
		currentBuffer_->append(tmp, totlen);
		m_ConditionVar.notify_all();
	}
}

Logging::~Logging(){
	running_ = false;
	m_ConditionVar.notify_all();
	m_Thread.join();

	for (INT32 i = 0; i < 4; ++i){
		if (NULL != m_File[i]){
			fclose(m_File[i]);
		}
	}
}


int Logging::CreateLogFile(LoggingEnum aLoggingEnum){
	string strPre;
	switch (aLoggingEnum){
	case LOG_DBBUG:
		strPre = "DBBUG";
		break;
	case LOG_INFO:
		strPre = "INFO";
		break;
	case LOG_WARNNING:
		strPre = "WARNNING";
		break;
	case LOG_ERROR:
		strPre = "ERROR";
		break;
	}
	char str[128];
	sprintf(str, "./Log/%s-%s-%d-%s", m_AppPreStr.c_str(), strPre.c_str() ,boost::this_thread::get_id(), boost::posix_time::to_iso_string(boost::posix_time::microsec_clock::local_time()).c_str());
	string fileName(str);
	fileName += ".log";
	int fd = open(fileName.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0664);
	if (fd == -1){
		printf("%s create(%d) file error\n", __FUNCTION__, aLoggingEnum);
		return -1;
	}

	m_File[aLoggingEnum] = fdopen(fd, "a");
	if (NULL == m_File[aLoggingEnum]){
		printf("%s open file(%d) failed\n", __FUNCTION__, aLoggingEnum);
		return -1;
	}

	return 0;
}

void Logging::threadFunc()
{
	assert(running_ == true);
	latch_.countDown();
	BufferPtr newBuffer1(new Buffer);
	BufferPtr newBuffer2(new Buffer);
	newBuffer1->bzero();
	newBuffer2->bzero();
	BufferVector buffersToWrite;
	buffersToWrite.reserve(16);

	while (running_)
	{
		assert(newBuffer1 && newBuffer1->length() == 0);
		assert(newBuffer2 && newBuffer2->length() == 0);
		assert(buffersToWrite.empty());

		{
			boost::mutex::scoped_lock lock(m_Mutex);
			if (buffers_.empty())  // unusual usage!
			{
				m_ConditionVar.wait(lock);
			}

			buffers_.push_back(currentBuffer_.release());
			currentBuffer_ = boost::ptr_container::move(newBuffer1);
			buffersToWrite.swap(buffers_);
			if (!nextBuffer_)
			{
				nextBuffer_ = boost::ptr_container::move(newBuffer2);
			}
		}

		assert(!buffersToWrite.empty());

		if (buffersToWrite.size() > 25)
		{
			buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end());
		}

		for (size_t i = 0; i < buffersToWrite.size(); ++i)
		{
			fwrite(buffersToWrite[i].data(), buffersToWrite[i].length(), 1, stderr);
			fflush(stderr);

			fwrite(buffersToWrite[i].data(), 1, buffersToWrite[i].length(), m_File[0]);
			fflush(m_File[0]);
		}

		if (buffersToWrite.size() > 2)
		{
			// drop non-bzero-ed buffers, avoid trashing
			buffersToWrite.resize(2);
		}

		if (!newBuffer1)
		{
			assert(!buffersToWrite.empty());
			newBuffer1 = buffersToWrite.pop_back();
			newBuffer1->reset();
		}

		if (!newBuffer2)
		{
			assert(!buffersToWrite.empty());
			newBuffer2 = buffersToWrite.pop_back();
			newBuffer2->reset();
		}

		buffersToWrite.clear();
	}
}
临时还没想清楚,假设写多个日志等级,logging的锁 应该怎样加。

參考mudo logging写的win下logging