#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,布布扣,bubuko.com
原文:http://blog.csdn.net/boyxiaolong/article/details/37719487