- 论坛徽章:
- 0
|
5可用积分
我想写程序时,打印自己的日志,大家给点建议,谢谢
自己实现了一个,没怎么测试,需要的拿去用吧。后果自负。
头文件
#ifndef __MYLOG_H_
#define __MYLOG_H_
#include <pthread.h>
#include <stdint.h>
/*
* Name: MyLog - The Mutil-Thread Logger
* Features:
* (1) Mutil-Thread
* (2) 支持日志文件大小限制, 最大 1G
* (3) 支持4个日志级别:
* -0- DEBUG, 调试模式
* -1- ROUTN, 正常模式
* -2- ALARM, 警告,本次会话可能无法正常服务
* -3- FATAL, 致命问题,程序已经无法运行
* (4) 支持日志切分,切分支持时,只需要把日志文件重命名即可
*/
class MyLog
{
private:
static const uint32_t LogNameMaxLen = 128;
static const uint32_t LogFileMaxSize = 1024*1024*1024;
static const uint32_t TimeBuffMaxLen = 32;
static const uint32_t LogContentMaxLen = 2048;
static const char* const strLogName;
static const char* LevelTag[];
uint32_t m_level; // 日志级别
uint32_t m_file_size; // 日志大小
char m_path[LogNameMaxLen]; // 日志路径
int m_log_fd; // 当前日志的文件描述符
pthread_mutex_t m_lock; // 写文件锁
char m_timebuff[TimeBuffMaxLen];
const char* GetTimeNow();
void LogFileSizeCheck();
void LogFileCheckOpen(); // 如果不存在就创建
void Mkdirs(const char* dir); // 递归的创建文件夹
void WriteNByte(int fd, const char* buff, uint32_t size);
MyLog();
public:
enum { DEBUG = 0, ROUTN, ALARM, FATAL, };
MyLog(const uint32_t level, const uint32_t size, const char* logname);
~MyLog();
void WriteLog(const uint32_t mylevel, const char* file,
const uint32_t line, const char* func, const char *format, ...);
};
#endif
代码文件
#include <stdarg.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "MyLog.h"
const char* const MyLog::strLogName = "./log/"PROJNAME".log";
const char* MyLog::LevelTag[] = { "DEBUG", "ROUTN", "ALARM", "FATAL", };
MyLog :: MyLog(const uint32_t level, const uint32_t size, const char* logname)
{
pthread_mutex_init(&m_lock, NULL);
m_level = (level > (uint32_t)FATAL) ? (uint32_t)ROUTN : level;
m_file_size = size > LogFileMaxSize ? LogFileMaxSize : size;
const char* mylogname = (logname[0] != 0 ) ? logname : strLogName;
snprintf(m_path, sizeof(m_path), "%s", mylogname);
m_log_fd = -1;
LogFileCheckOpen();
fprintf(stderr, "MyLog Level[%u] OL[%u] Path[%s] Size[%u] fd[%d]\n",
m_level, level, m_path, m_file_size, m_log_fd);
}
void MyLog :: WriteNByte(const int fd, const char* buff, const uint32_t size)
{
int32_t left = size;
uint32_t offset = size;
while (left > 0)
{
int len = write(fd, buff+offset-left, left);
if (len == -1 || len == 0)
{
return;
}
left -= len;
}
}
void MyLog :: WriteLog(const uint32_t mylevel, const char* file,
const uint32_t line, const char* func, const char *format, ...)
{
pthread_mutex_lock(&m_lock);
LogFileCheckOpen();
va_list args;
va_start(args, format);
char buff[LogContentMaxLen];
uint32_t pos = 0;
if (mylevel < m_level) {
pthread_mutex_unlock(&m_lock);
return;
}
uint32_t level = (mylevel > (uint32_t)FATAL) ? (uint32_t)FATAL : mylevel;
pos = snprintf(&buff[pos], LogContentMaxLen-pos, "%s ", LevelTag[level]);
pos += snprintf(&buff[pos], LogContentMaxLen-pos, "%s ", GetTimeNow());
pos += snprintf(&buff[pos], LogContentMaxLen-pos, "%lu ", pthread_self());
pos += snprintf(&buff[pos], LogContentMaxLen-pos, "file[%s:%u] ", file, line);
pos += snprintf(&buff[pos], LogContentMaxLen-pos, "func[%s] ", func);
vsnprintf(&buff[pos], LogContentMaxLen-pos-2, format, args);
va_end(args);
pos = strlen(buff);
buff[pos] = '\n';
buff[pos+1] = '\0';
WriteNByte(m_log_fd, buff, pos+1);
pthread_mutex_unlock(&m_lock);
}
void MyLog :: LogFileCheckOpen()
{
char tmppath[LogNameMaxLen];
char curpath[LogNameMaxLen];
if (NULL == getcwd(curpath, sizeof(curpath))) {
fprintf(stderr, "Get Current Dir Fail.\n");
return;
}
char* p = NULL;
// 不存在就创建日志文件, 兼顾初始化和运行时的状态
// 第一步,创建文件夹
if (0 != access(m_path,F_OK)) {
snprintf(tmppath, sizeof(tmppath), "%s", m_path);
p = strrchr(tmppath, '/');
if (p) {
*p = '\0';
Mkdirs(tmppath);
}
if (m_log_fd >= 0){
close(m_log_fd);
m_log_fd = -1;
}
}
chdir(curpath);
// 第二步,创建文件
if (m_log_fd < 0) {
m_log_fd = open(m_path, O_WRONLY|O_CREAT|O_APPEND, S_IRWXU|S_IRWXG|S_IRWXO);
if (m_log_fd < 0) {
fprintf(stderr, "FILE[%s:%u] create logfile[%s] fail. msg[%m]\n",
__FILE__, __LINE__, m_path);
while(0 != raise(SIGKILL)){}
}
}
}
void MyLog :: LogFileSizeCheck()
{
struct stat st;
fstat(m_log_fd, &st);
if (st.st_size + LogContentMaxLen > m_file_size)
{
ftruncate(m_log_fd, 0);
}
}
const char* MyLog :: GetTimeNow()
{
time_t now;
struct tm mytm;
m_timebuff[0] = 0;
time(&now);
localtime_r(&now, &mytm);
mytm.tm_year += 1900;
sprintf(m_timebuff, "%02d-%02d %02d:%02d:%02d",
mytm.tm_mon+1, mytm.tm_mday, mytm.tm_hour, mytm.tm_min, mytm.tm_sec);
return m_timebuff;
}
void MyLog :: Mkdirs(const char* dir)
{
char tmp[1024];
char *p = NULL;
if (strlen(dir) == 0 || dir == NULL) {
return;
}
memset(tmp, '\0', sizeof(tmp));
strncpy(tmp, dir, strlen(dir));
if (tmp[0] == '/') {
p = strchr(tmp + 1, '/');
} else {
p = strchr(tmp, '/');
}
if (p) {
*p = '\0';
mkdir(tmp, 0777);
chdir(tmp);
} else {
mkdir(tmp, 0777);
chdir(tmp);
return;
}
Mkdirs(p + 1);
}
[ 本帖最后由 科技牛 于 2009-11-8 15:59 编辑 ] |
|