#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 ();p rivate:boost::mutexm_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_ directlychar* 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 (); Voidwritewithfunline (Loggingenum eloggingenum, char* fun, int line, char* msg, ...); Voidwritemsg (Loggingenum eloggingenum, char* fun, int. line, char* msg);p Rivate:intcreatelogfile (loggingenum Aloggingenum); Voidwrite (Loggingenum eloggingenum, char* msg, int msglen); void ThreadFunc ();p rivate:bool running_; File*m_file[log_end];typedef boost::p OSIx_time::p time ptime;std::stringm_appprestr;typedef fixedbuffer<klargebuffer> buffer;typedef boost::p tr_ vector<buffer> buffervector;typedef Buffervector::auto_type bufferptr; Bufferptr Currentbuffer_; Bufferptr Nextbuffer_; Buffervector buffers_;boost::threadm_thread;boost::mutexm_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:retur n 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) {CAs E 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_windowsglogcolor 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 (+); Boost::mutex::scoped_lock lock (M_mutex); char szapppath[256] = "";:: GetModuleFileNameA (0, Szapppath, 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::p osix_time::microsec_clock::local_time () sprintf (tmp, "%s.%d%s:%d", Boost::p osix_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 = Curpo S + 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::p tr_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 (NUL L! = 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::p osix_time::to_iso_string (boost::p osix_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 (+); 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::p tr_container::move (NewBuffer1); Bufferstowrite.swap (Buffers_); if (!nextbuffer_) {nextbuffer_ = boost::p tr_container::move (NewBuffer2);}} ASSERT (!bufferstowrite.empty ()), if (Bufferstowrite.size () >) {bufferstowrite.erase (Bufferstowrite.begin () +2, Bufferstowrite.end ());} for (size_t i = 0; i < bufferstowrite.size (); ++i) {fwrite (Bufferstowrite[i].data (), Bufferstowrite[i].length (), 1, STD ERR); 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 trashingbufferstowrite.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 ();}}
For the time being, if you write multiple log levels, logging locks should be added.