Linux日志服务

1 篇文章 0 订阅
1 篇文章 0 订阅

这个是用于Linux下的一个日志服务,日志的使用很简单,支持多线程输入到文件,并且对日志文件大小也有限制。

[2020-06-12T09:46:36.547+0100]-[test]-[error]-[filename:0]-[51086:51086] 

时间                          执行程序名 级别    第几个文件   线程号 子线程号

 对外接口

#ifndef _SMART_LOG_SERVER_H__
#define _SMART_LOG_SERVER_H__

#include "Smart.h"

typedef std::stringstream SmartString;

#define TRACE(str, ToWhere, Level)  { \
		  TextFormat _log_c_; \
		  _log_c_ << str; \
		  unsigned int _c_len_ = 0; \
		  const char* _c_ptr_ = _log_c_.GetContent(_c_len_); \
		  TraceApi::Write(ToWhere, Level, _c_ptr_, _c_len_); \
		  }

/
// interfaces provided
#define OUTPUT_GBJECTIVE   OUTPUT_FILE

#define CLASSFUNC_TRACE(str)  TRACE(str, OUTPUT_GBJECTIVE, TRACE_LEVEL_DEBUG)
#define STATE_TRACE(str)      TRACE(str, OUTPUT_GBJECTIVE, TRACE_LEVEL_DEBUG)
#define INFO_TRACE(str)       TRACE(str, OUTPUT_GBJECTIVE, TRACE_LEVEL_INFO)
#define WARNING_TRACE(str)    TRACE(str, OUTPUT_GBJECTIVE, TRACE_LEVEL_WARNING)
#define ERROR_TRACE(str)      TRACE(str, OUTPUT_GBJECTIVE, TRACE_LEVEL_ERROR)

#define ERROR_TRACE_THIS(str)    ERROR_TRACE(str << " this=" << this)
#define WARNING_TRACE_THIS(str)  WARNING_TRACE(str << " this=" << this)
#define INFO_TRACE_THIS(str)     INFO_TRACE(str << " this=" << this)
#define STATE_TRACE_THIS(str)    STATE_TRACE(str << " this=" << this)

//debug
#define ASSERTE(expr) \
do { \
	if (!(expr)) { \
		ERROR_TRACE(__FILE__ << ":" << __LINE__ << " Assert failed: " << #expr); \
			} \
	} while (0)

#define ASSERTE_RETURN(expr, rv) \
do { \
	bool resexpr = (expr)?true:false; \
	ASSERTE((resexpr)); \
	if (!(resexpr)) { \
		ERROR_TRACE(__FILE__ << ":" << __LINE__ << " Assert failed: " << #expr); \
		return rv; \
			} \
	} while (0)

#define ASSERTE_RETURN_VOID(expr) \
do { \
	bool resexpr = (expr)?true:false; \
	ASSERTE((resexpr)); \
	if (!(resexpr)) { \
		ERROR_TRACE(__FILE__ << ":" << __LINE__ << " Assert failed: " << #expr); \
		return; \
			} \
	} while (0)

//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <time.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>

#include <assert.h>
#include <netinet/tcp.h>
#include <semaphore.h>

using namespace std;

#endif

实现,可以编译为库文件

#include "Smart.h"
 
void TraceApi::Destroy()
{
	TraceImpl::DestroyInstance();
}

void TraceApi::Write(TRACE_OUTPUT_WHERE_TYPE ToWhere,
	TRACE_LEVEL_TYPE Level,
	const char* szTraceContent,
	unsigned int uContentLen)
{
	TraceImpl* ptr = TraceImpl::GetInstance();
	if (!ptr)
	{
		return;
	}
	ptr->Write(ToWhere, Level, szTraceContent, uContentLen);
}

//impl
TraceImpl* TraceImpl::s_LogInstance = NULL;
MyMutex    TraceImpl::s_Mutex;
int        TraceImpl::s_HasDeleted = 0;

TraceImpl* TraceImpl::GetInstance()
{
	if (s_LogInstance == NULL)
	{
		s_Mutex.Lock();

		if (s_HasDeleted)
		{
			s_Mutex.UnLock();
			return NULL;
		}

		if (s_LogInstance == NULL)
		{
			s_LogInstance = new TraceImpl();
			if (s_LogInstance == NULL)
			{
				s_Mutex.UnLock();
				return NULL;
			}
		}

		s_Mutex.UnLock();
		return s_LogInstance;
	}

	return s_LogInstance;
}

void TraceImpl::DestroyInstance()
{
	s_Mutex.Lock();
	s_HasDeleted = 1;

	// CloseFile();

	if (s_LogInstance != NULL)
	{
		delete s_LogInstance;
		s_LogInstance = NULL;
	}

	s_Mutex.UnLock();
}

void TraceImpl::CloseFile()
{
	if (m_File)
	{
		fclose(m_File);
		m_File = NULL;
	}
}

void TraceImpl::GetFileName(bool writealbe_file, std::string& fn)
{
	std::stringstream ssfn;

	ssfn << m_FilenamePrefix << '_' << "linux";

	if (writealbe_file)
	{
		ssfn << "_" << "w" << ".log";
	}
	else
	{
		ssfn << "_" << m_uProcessID << "_" << m_uFileNoIndex << ".log";
	}

	fn = ssfn.str();
}

FILE* TraceImpl::OpenFile()
{
	CheckFilesize();

	if ((++m_uAccessCount & 127) == 0 && access(_writable_fname.c_str(), 0) == -1)
	{
		CloseFile();
		m_uFileSize = 0;
		m_uFlushIndex = 0;
	}

	if (m_File == NULL)
	{
		m_File = fopen(_writable_fname.c_str(), "a+");
	}
	return m_File;
}

void TraceImpl::CheckFilesize()
{
	if (m_uFileSize > m_uMaxSizeInFile)
	{
		if (m_File)
		{
			fprintf(m_File, "=============================== end of this file ====================\n");
		}

		CloseFile();

		// rename file 
		std::string new_fn;
		GetFileName(false, new_fn);
		int res = ::rename(_writable_fname.c_str(), new_fn.c_str());
		if (res != 0)
		{
			::printf("media server trace module, rename failed");
		}

		m_uFileNoIndex++;
		m_uFileNoIndex %= m_uMaxFileNums;

		m_uFileSize = 0;
		m_uFlushIndex = 0;
	}
}

void TraceImpl::WriteToFile(const char* szAContent, unsigned int uConLen)
{
	s_Mutex.Lock();

	FILE* tmp_file = OpenFile();
	if (tmp_file == NULL)
	{
		s_Mutex.UnLock();
		return;
	}

	fprintf(tmp_file, "%s", szAContent);

	if ((++m_uFlushIndex % m_uMaxFlush) == 0)
	{
		fflush(tmp_file);
	}

	m_uFileSize += uConLen;
	CheckFilesize();

	s_Mutex.UnLock();
}

static const char* _trace_level_str_arr[] = { "debug",
	"info",
	"warn",
	"error" };

unsigned int TraceImpl::GetTracePrefix(int Level, char* szContentBuf, unsigned int uBufLen)
{
	if (Level > (int)TRACE_LEVEL_ERROR)
	{
		Level = (int)TRACE_LEVEL_ERROR;
	}

	// streaming time, process ID and thread ID
	int rets = 0;
	unsigned int reslen = 0;
	struct timeval tv;
	struct timezone zn;

	gettimeofday(&tv, &zn);
	struct tm tm_now;
	localtime_r(&tv.tv_sec, &tm_now);

	int utcSec = tv.tv_sec % (24 * 60 * 60);
	int nowSec = tm_now.tm_hour * 3600 + tm_now.tm_min * 60 + tm_now.tm_sec;

	char tzBuf[8] = { 0 };
	int diff = (nowSec - utcSec) / 3600;

	//Adjust to the same day
	if (diff <= -12)
	{
		diff += 24;
	}
	else if (diff > 12)
	{
		diff -= 24;
	}

	if (diff > 0)
	{
		snprintf(tzBuf, 6, "+%02d00", diff);
	}
	else if (diff < 0)
	{
		snprintf(tzBuf, 6, "-%02d00", abs(diff));
	}
	else
	{
		snprintf(tzBuf, 6, "+0000");
	}

	rets = snprintf(szContentBuf,
		uBufLen,
		"[%02d-%02d-%02dT%02d:%02d:%02d.%03d%s]-[%s]-[%s]-[%s:%d]-[%u:%u] ",
		(int)(tm_now.tm_year + 1900),
		(int)(tm_now.tm_mon + 1),
		(int)tm_now.tm_mday,
		(int)tm_now.tm_hour,
		(int)tm_now.tm_min,
		(int)tm_now.tm_sec,
		(int)(tv.tv_usec / 1000),
		tzBuf,
		m_FilenamePrefix.c_str(),
		_trace_level_str_arr[Level],
		"filename",
		m_uFileNoIndex,
		m_uProcessID,
		(unsigned int)gettid());

	if (rets < 0)
	{
		reslen = uBufLen;
	}
	else
	{
		reslen = rets;
	}

	return reslen;
}

void TraceImpl::Write(TRACE_OUTPUT_WHERE_TYPE ToWhere,
	TRACE_LEVEL_TYPE Level,
	const char* szTraceContent,
	unsigned int uContentLen)
{
	char logcon[CONLEN_ONELINE];

	unsigned int bufflen = CONLEN_ONELINE - 4;
	char* bufflog = logcon;

	if (bufflen > m_uMaxCharsOneLine)
	{
		bufflen = m_uMaxCharsOneLine;
	}

	unsigned int reslen = 0;

	unsigned int rest = GetTracePrefix(Level, bufflog, bufflen);
	if (rest < bufflen)
	{
		bufflen -= rest;

		reslen += rest;
		bufflog += rest;

		if (uContentLen > bufflen)
		{
			uContentLen = bufflen;
		}

		if (uContentLen)
		{
			memcpy(bufflog, szTraceContent, uContentLen);

			reslen += uContentLen;
			bufflog += uContentLen;
		}

		// append '\n'
		bufflog[0] = '\n';
		reslen++;

		// append '\0'
		bufflog[1] = 0;
	}
	else if (rest == bufflen)
	{
		reslen += rest;

		// append '\n'
		bufflog[rest] = '\n';
		reslen++;

		// append '\0'
		bufflog[rest + 1] = 0;
	}
	else
	{
		WriteToStdout("logwrite, outof memory\n");
		return;
	}

	if (ToWhere == OUTPUT_STDOUT)
	{
		WriteToStdout(logcon);
	}
	else
	{
		WriteImpl(logcon, reslen, Level);
	}

}

void TraceImpl::WriteImpl(const char* szAContent, unsigned int uConLen, TRACE_LEVEL_TYPE Level)
{
	WriteToFile(szAContent, uConLen);
}



 

#ifndef _smart_h__
#define _smart_h__

#include "../Intelligent/SmartPtr.h" 
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sstream> 
#include <iostream>
#include <string>

#define FILE_NAME_PREFIX       "mediaserver"
#define MAX_CHARS_IN_ONE_LINE  1024
#define FLUSH_FREQUENCY        1
#define FILE_NUMS_BY_REWRITE   2  
#define MAX_TRACE_FILESIZE     50*1024*1024  

// must use syscall.h
// __NR_gettid = 224
#include <sys/syscall.h>
#define gettid()   syscall(__NR_gettid)  //
/
// trace level for filter trace, trace can be filtered by level
enum TRACE_LEVEL_TYPE
{
	TRACE_LEVEL_DEBUG,
	TRACE_LEVEL_INFO,
	TRACE_LEVEL_WARNING,
	TRACE_LEVEL_ERROR
};

enum TRACE_OUTPUT_WHERE_TYPE
{
	OUTPUT_STDOUT,
	OUTPUT_FILE,
	OUTPUT_SYSLOG
};

#define _MSNPRINTF snprintf

struct TextFormat
{
public:
	TextFormat() : m_uIndex(0)
	{}

	~TextFormat()
	{}

	const char* GetContent(unsigned int& uContentLen) const
	{
		uContentLen = m_uIndex;
		return m_aContent;
	}

	TextFormat& operator<<(unsigned int uVal)
	{
		return *this << (unsigned long)uVal;
	}

	TextFormat& operator<<(unsigned long ulVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%lu", ulVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}
	TextFormat& operator<<(unsigned long long ullVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%llu", ullVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

	TextFormat& operator<<(int iVal)
	{
		return *this << (long)iVal;
	}

	TextFormat& operator<<(long lVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%ld", lVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}
	TextFormat& operator<<(long long llVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%lld", llVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

	TextFormat& operator<<(const char* pszCont)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		if (pszCont == NULL)
		{
			*this << (void *)pszCont;
		}
		else
		{
			unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;
			int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%s", pszCont);

			if (r_len >= 0)
			{
				if (r_len > (int)buf_len)
				{
					r_len = buf_len;
				}

				m_uIndex += r_len;
			}
			else
			{
				m_uIndex += buf_len;
			}

			m_aContent[m_uIndex] = 0;
		}

		return *this;
	}
	TextFormat& operator<<(const void* pCont)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%p", pCont);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

	TextFormat& operator<<(short nVal)
	{
		return (*this << (int)nVal);
	}

	TextFormat& operator<<(char cVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		if (cVal > 126 || cVal < 32)
		{
			return *this << (int)cVal;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%c", cVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

	TextFormat& operator<<(unsigned short wVal)
	{
		return (*this << (unsigned int)wVal);
	}

	TextFormat& operator<<(unsigned char byVal)
	{
		return *this << (char)byVal;
	}

	TextFormat& operator<<(float fVal)
	{
		return *this << (double)fVal;
	}

	TextFormat& operator<<(double fVal)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;

		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%f", fVal);
		if (r_len >= 0)
		{
			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

	TextFormat& operator<<(const std::string& con)
	{
		if (m_uIndex >= CONT_BUFF_LEN)
		{
			return *this;
		}

		if (con.empty())
		{
			return *this;
		}

		unsigned int buf_len = CONT_BUFF_LEN - m_uIndex;
		int r_len = _MSNPRINTF(m_aContent + m_uIndex, buf_len, "%s", con.c_str());

		if (r_len >= 0)
		{
			if (r_len > (int)buf_len)
			{
				r_len = buf_len;
			}

			m_uIndex += r_len;
		}
		else
		{
			m_uIndex += buf_len;
		}

		m_aContent[m_uIndex] = 0;
		return *this;
	}

private:
	TextFormat(const TextFormat&);
	TextFormat& operator=(const TextFormat&);

private:
	enum
	{
		CONT_BUFF_LEN = 1024
	};

	unsigned int m_uIndex;
	char m_aContent[CONT_BUFF_LEN + 32];

};

typedef PthreadMutex MyMutex;

struct TraceImpl
{
public:
	void Write(TRACE_OUTPUT_WHERE_TYPE ToWhere,
		TRACE_LEVEL_TYPE Level,
		const char* szTraceContent,
		unsigned int uContentLen);

	static TraceImpl* GetInstance();
	static void DestroyInstance();

private:
	TraceImpl() :m_File(NULL),
		m_uFlushIndex(0),
		m_uMaxFlush(FLUSH_FREQUENCY),
		m_uAccessCount(0),
		m_uFileNoIndex(0),
		m_uMaxFileNums(FILE_NUMS_BY_REWRITE),
		m_uFileSize(0),
		m_uMaxSizeInFile(MAX_TRACE_FILESIZE),
		m_uProcessID(0),
		m_uMaxCharsOneLine(MAX_CHARS_IN_ONE_LINE),
		m_FilterLevel(TRACE_LEVEL_INFO)
	{
		std::string pn;
		m_uProcessID = (unsigned int)(::getpid());
		pn = program_invocation_short_name;
		if (!pn.empty())
		{
			size_t pos = pn.rfind('.');

			if (pos != std::string::npos)
			{
				m_FilenamePrefix = pn.substr(0, pos);
			}
			else
			{
				m_FilenamePrefix = pn;
			}
		}

		if (m_FilenamePrefix.empty())
		{
			m_FilenamePrefix = std::string(FILE_NAME_PREFIX);
		}
		GetFileName(true, _writable_fname);

	}
	~TraceImpl()
	{
		CloseFile();
	}

	unsigned int GetTracePrefix(int Level, char* szContentBuf, unsigned int uBufLen);

	void WriteToStdout(const char* szAContent)
	{
		// std::cout << szAContent << std::endl;
		// has append '\n'
		s_Mutex.Lock();
		::printf("%s", szAContent);
		s_Mutex.UnLock();
	}

	enum
	{
		CONLEN_ONELINE = 1096
	};

private:
	FILE* OpenFile();
	void CloseFile();

	void WriteToFile(const char* szAContent, unsigned int uConLen);
	void WriteImpl(const char* szAContent, unsigned int uConLen, TRACE_LEVEL_TYPE Level);

private:
	void CheckFilesize();
	void GetFileName(bool writealbe_file, std::string& fn);

private:
	FILE* m_File;  // m_File

	unsigned int m_uFlushIndex; // m_uFlushIndex
	unsigned int m_uMaxFlush;   // m_uMaxFlush

	unsigned int m_uAccessCount;

	unsigned int m_uFileNoIndex;
	unsigned int m_uMaxFileNums;

	unsigned int m_uFileSize;
	unsigned int m_uMaxSizeInFile;

	unsigned int m_uProcessID;
	unsigned int m_uMaxCharsOneLine;

	TRACE_LEVEL_TYPE m_FilterLevel;  // m_Filter
	std::string m_FilenamePrefix;
	std::string _writable_fname;

	/
	// static related members
	static TraceImpl* s_LogInstance; // s_LogInstance
	static int s_HasDeleted;
	static MyMutex s_Mutex;
	/
};

// trace function wrapper
struct TraceApi
{
public:
	static void Destroy();

	static void Write(TRACE_OUTPUT_WHERE_TYPE ToWhere,
		TRACE_LEVEL_TYPE Level,
		const char* szTraceContent,
		unsigned int uContentLen);
};



#endif

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值