#include "yaolog.h"
#include <algorithm>
#include <queue>
#include <sys/timeb.h>
#ifdef _YAO_LOG_WIN32_
#include <time.h>
#include <process.h>
#include <shlobj.h>
#include <Shlwapi.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "Rpcrt4.lib")
#pragma warning(disable : 4996)
#else
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <net/if.h>
#endif
namespace YaoUtil {
// max size of ini file, in bytes
const int MAX_INI_FILE_SIZE = 1024*32;
// default log buffer size, in bytes
const size_t BUF_SIZE = 1024*4;
// max size of the queue, for post
const size_t MAX_QUEUE_SIZE = 1000;
const int THREAD_CYCLE_SPAN_MILLISECOND = 2000;
const int THREAD_EXIT_TIMEOUT_MILLISECOND = 300;
char *g_pData = NULL;
char *g_pRealData = NULL;
bool g_bUseNewBuffer = false;
std::queue<std::pair<std::string, std::string> > g_textData;
std::queue<std::pair<std::string, std::string> > g_binData;
std::map<std::string, P_FILE> g_files;
void ResetBuffer()
{
memset(g_pData, 0, BUF_SIZE);
if (g_bUseNewBuffer)
{
delete [] g_pRealData;
g_bUseNewBuffer = false;
}
g_pRealData = NULL;
}
LOGOUT_FLAG ToFlag(const std::string& outFlag)
{
LOGOUT_FLAG flag_;
if (StrUtil::CompareNoCase(outFlag, "file")) flag_ = LOGOUT_FLAG_FILE;
else if (StrUtil::CompareNoCase(outFlag, "stdout")) flag_ = LOGOUT_FLAG_STDOUT;
else if (StrUtil::CompareNoCase(outFlag, "remote")) flag_ = LOGOUT_FLAG_REMOTE;
else flag_ = LOGOUT_FLAG_OUTPUTDEBUGSTRING;
return flag_;
}
void Queue2Vector(std::queue<std::pair<std::string, std::string> >& data_,
std::vector<std::pair<std::string, std::vector<std::string> > >& new_data)
{
std::string last_key;
std::vector<std::string> new_value;
bool firstElement = true;
while (!data_.empty())
{
std::string& key_ = data_.front().first;
std::string& value_ = data_.front().second;
if (firstElement)
{
last_key = key_;
new_value.push_back(value_);
firstElement = false;
}
else
{
if (key_ != last_key)
{
new_data.push_back(make_pair(last_key, new_value));
last_key = key_;
new_value.clear();
}
new_value.push_back(value_);
}
data_.pop();
}
if (!last_key.empty())
{
assert(new_value.size() > 0);
new_data.push_back(make_pair(last_key, new_value));
}
}
TinyMutex::TinyMutex()
{
#ifdef _YAO_LOG_WIN32_
InitializeCriticalSection(&m_handle);
#else
pthread_mutex_init(&m_handle, NULL);
#endif
}
TinyMutex::~TinyMutex()
{
#ifdef _YAO_LOG_WIN32_
DeleteCriticalSection(&m_handle);
#else
pthread_mutex_destroy(&m_handle);
#endif
}
void TinyMutex::Lock()
{
#ifdef _YAO_LOG_WIN32_
EnterCriticalSection(&m_handle);
#else
pthread_mutex_lock(&m_handle);
#endif
}
void TinyMutex::Unlock()
{
#ifdef _YAO_LOG_WIN32_
LeaveCriticalSection(&m_handle);
#else
pthread_mutex_unlock(&m_handle);
#endif
}
void StrUtil::vFormat(tstring& s, const TCHAR *fmt, va_list ap)
{
#ifdef _YAO_LOG_UNICODE_
vFormatW(s, fmt, ap);
#else
vFormatA(s, fmt, ap);
#endif
}
void StrUtil::vFormatA(std::string& s, const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time. Be prepared to allocate dynamically if it doesn't fit.
size_t size = 1024;
char stackbuf[1024];
std::vector<char> dynamicbuf;
char *buf = &stackbuf[0];
while (1) {
// Try to vsnprintf into our buffer.
int needed = vsnprintf(buf, size, fmt, ap);
// NB. C99 (which modern Linux and OS X follow) says vsnprintf
// failure returns the length it would have needed. But older
// glibc and current Windows return -1 for failure, i.e., not
// telling us how much was needed.
if (needed <= (int)size && needed >= 0) {
// It fit fine so we're done.
s = std::string(buf, (size_t)needed);
return;
}
// vsnprintf reported that it wanted to write more characters
// than we allotted. So try again using a dynamic buffer. This
// doesn't happen very often if we chose our initial size well.
size = (needed > 0) ? (needed+1) : (size*2);
dynamicbuf.resize(size);
buf = &dynamicbuf[0];
}
}
#ifdef _YAO_LOG_WIN32_
void StrUtil::vFormatW(std::wstring& s, const wchar_t *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time. Be prepared to allocate dynamically if it doesn't fit.
size_t size = 1024;
wchar_t stackbuf[1024];
std::vector<wchar_t> dynamicbuf;
wchar_t *buf = &stackbuf[0];
while (1) {
// Try to vsnprintf into our buffer.
int needed = _vsnwprintf(buf, size, fmt, ap);
// NB. C99 (which modern Linux and OS X follow) says vsnprintf
// failure returns the length it would have needed. But older
// glibc and current Windows return -1 for failure, i.e., not
// telling us how much was needed.
if (needed <= (int)size && needed >= 0) {
// It fit fine so we're done.
s = std::wstring(buf, (size_t)needed);
return;
}
// vsnprintf reported that it wanted to write more characters
// than we allotted. So try again using a dynamic buffer. This
// doesn't happen very often if we chose our initial size well.
size = (needed > 0) ? (needed+1) : (size*2);
dynamicbuf.resize(size);
buf = &dynamicbuf[0];
}
}
#endif
#ifdef _YAO_LOG_WIN32_
std::string StrUtil::WStrToStr(const std::wstring& strIn)
{
int nBufSize = ::WideCharToMultiByte(GetACP(), 0, strIn.c_str(), -1, NULL, 0, 0, FALSE);
char* szBuf = new char[nBufSize];
if (!szBuf) return "";
::WideCharToMultiByte(GetACP(), 0, strIn.c_str(), -1, szBuf, nBufSize, 0, FALSE);
std::string strRet(szBuf);
delete [] szBuf;
szBuf = NULL;
return strRet;
}
#endif
#ifdef _YAO_LOG_WIN32_
std::wstring StrUtil::StrToWStr(const std::string& strIn)
{
int nBufSize = ::MultiByteToWideChar(GetACP(), 0, strIn.c_str(), -1, NULL, 0);
wchar_t* wsBuf = new wchar_t[nBufSize];
if (!wsBuf) return L"";
::MultiByteToWideChar(GetACP(), 0, strIn.c_str(), -1, wsBuf, nBufSize);
std::wstring wstrRet(wsBuf);
delete [] wsBuf;
wsBuf = NULL;
return wstrRet;
}
#endif
bool StrUtil::CompareNoCase(const std::string& strIn1, const std::string& strIn2)
{
std::string s1(strIn1);
std::string s2(strIn2);
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
return s1 == s2;
}
std::string StrUtil::GetSysTimeStr(bool withMillisecond)
{
timeb timebuffer;
ftime(&timebuffer);
tm *local;
local = localtime(&timebuffer.time);
char buf[30] = { 0 };
if (withMillisecond)
{
sprintf(buf, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
local->tm_year+1900, local->tm_mon+1, local->tm_mday,
local->tm_hour, local->tm_min, local->tm_sec, timebuffer.millitm);
}
else
{
sprintf(buf, "%04u-%02u-%02u %02u:%02u:%02u",
local->tm_year+1900, local->tm_mon+1, local->tm_mday,
local->tm_hour, local->tm_min, loca