动手编写TCP服务器系列之一:日志文件
前言
在几个月之前,笔者想自己实现一个性能比较良好的基于tcp的服务器。于是断断续续写了个把月,因为还需要找工,还有论文什么的。拖了这么久。现在开辟这样的一个博客,我想记录下自己的思路,也和大家分享自己的代码。个人觉得一个优秀的服务器,不能考虑各种通用性,平台无关性。我写的这个服务器只针对linux平台。
在写这个系列文章之前,我想把功能都独立出来。每一篇文章专注于一个功能。
本系列文章均系笔者所写,难免有一些错误或者纰漏,如果小伙伴们有好的建议或者更好的算法,请不吝赐教。
正文
目标
本篇文章主要是讲TCP Server的日志功能。那么在一个服务器当中日志功能是必不可少的。无论是定位错误或者打印一些信息等等。日志的预期目标如下图所示。
Time是记录日志时间;Level是日志级别;PID是进程ID;TID是线程ID;Function是日志所在函数;Line是文件行;File是日志文件;Message是所打印的信息。
#ifndef LOG_HPP_
#define LOG_HPP_ #include <string>
#include <cstdio>
#include <cstring> #include <stdarg.h> #include <syscall.h>
#include <sys/time.h>
#include <linux/limits.h> #define LOG_STRING_MAX 4096 #define NEWLINE "\n"
#define MAX_PATHSIZE PATH_MAX
#define RETURN_OK 0 #define LOG(level,fmt,...) \
do { \
if( _curPDLevel >= level ) \
{ \
log(level,__func__,__FILE__,__LINE__,fmt,##__VA_ARGS__);\
} \
}while( 0 ) \ #define CHECK( cond, retCode, gotoLabel, level, fmt, ... ) \
do { \
if( !( cond ) ) \
{ \
rc = ( retCode ); \
LOG( (level), fmt, ##__VA_ARGS__ ); \
goto gotoLabel; \
} \
}while( 0 ) \ enum PDLEVEL
{
PDSERVER=0,
PDERROR,
PDEVENT,
PDWARNING,
PDINFO,
PDDEBUG
}; extern PDLEVEL _curPDLevel;
const char * getPDLevelDesp( PDLEVEL level ); #define PD_DFT_DIAGLEVEL PDWARNING void log( PDLEVEL level, const char * func, const char * file,
unsigned int line, const char * format, ... ); void log( PDLEVEL level, const char * func, const char * file,
unsigned int lne, std::string message ); #endif
#include "log.hpp"
#include "latch.hpp"
#include "FileOp.hpp" const static char * PDLEVELSTRING[] =
{
"SEVERE",
"ERROR",
"EVENT",
"WARNING",
"INFO",
"DEBUG"
}; const char * getLevelDesp( PDLEVEL level )
{
if( (unsigned int)level > (unsigned int)PDDEBUG )
{
return "Unknown level";
}
return PDLEVELSTRING[(unsigned int)level];
} const static char * LOG_HEADER_FORMAT = \
"[Time] %04d-%02d-%02d-%02d.%02d.%02d [Level] %s"OSS_NEWLINE \
"[PID] %-30d[TID] %d"OSS_NEWLINE \
"[Function] %-30s[Line] %d"OSS_NEWLINE \
"[File] %s"OSS_NEWLINE\
"[Message] %s"OSS_NEWLINE OSS_NEWLINE; LEVEL _curPDLevel = DFT_DIAGLEVEL; static char _diaglogPath[ OSS_MAX_PATHSIZE+1 ] = { 0 }; Latch _logMutex;
FileOperation _logFile; // open log file
static int _pdLogFileReopen()
{
int rc = RETURN_OK;
_logFile.Close();
rc = _logFile.Open( _pdDiaglogPath );
if( rc )
{
printf( "Failed to open log file, errono = %d", OSS_NEWLINE, rc );
goto error;
} _logFile.SeekToEnd();
done:
return rc;
error:
goto done;
} // write log file
static int _logFileWrite( const char * pData )
{
int rc = RETURN_OK;
size_t dataSize = strlen( pData );
_logMutex.get();
if( !_logFile.IsValid() )
{
// open the file
rc = _logFileReopen();
if( rc )
{
printf( "Failed to open log file, erroro = %d"OSS_NEWLINE, rc);
goto error;
}
}
rc = _logFile.Write( pData, dataSize );
if( rc )
{
printf( "Failed to write into log file, errno = %d"OSS_NEWLINE, rc );
goto error;
}
done:
_logMutex.release();
return rc;
error:
goto done;
} void log( PDLEVEL level, const char * func, const char * file, unsigned int line, const char * format, ... )
{
int rc = RETURN_OK;
if( _curPDLevel < level )
{
return;
}
va_list ap;
char userInfo[ PD_LOG_STRING_MAX ];
char sysInfo[PD_LOG_STRING_MAX];
struct tm otm;
struct timeval tv;
struct timezone tz;
time_t tt; gettimeofday( &tv, &tz );
tt = tv.tv_sec;
localtime_r( &tt, &otm ); // create user information
va_start( ap, format );
vsnprintf( userInfo, PD_LOG_STRING_MAX, format, ap );
va_end( ap ); snprintf( sysInfo, LOG_STRING_MAX, LOG_HEADER_FORMAT,
otm.tm_year + 1900,
otm.tm_mon + 1,
otm.tm_mday,
otm.tm_hour,
otm.tm_min,
otm.tm_sec,
PDLEVELSTRING[level],
getpid(),
syscall(SYS_gettid),
func,
line,
file,
userInfo ); printf( "%s"NEWLINE, sysInfo);
/*
if( _pdDiaglogPath[0] != '\0' )
{
rc = _logFileWrite( sysInfo );
if( rc )
{
printf( "Failed to write into log file, errno = %d"NEWLINE, rc );
printf( "%s"NEWLINE, sysInfo );
}
}
*/
return;
} /*
int main( int argc, char ** argv )
{
PD_LOG( PDERROR, "%d", 1 );
return 0;
}
*/
代码仅供参考。可能中间用到了一些锁的机制或者一些写文件的类。比如FileOp在后续的文章中会慢慢呈现出来。
作者
出处:http://www.cnblogs.com/gina
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
动手编写TCP服务器系列之一:日志文件的更多相关文章
- lnmp vps服务器删除mysql日志文件三种方法
我在上一篇文章介绍了著名的LNMP主机一键安装工具,对比了军哥lnmp和AMH主机的差别,由于AMH拥有用户后台界面,易于新手操作,值得推荐. 但是,上周末我网站宕机,收到DNSPOD发来了宕机提醒, ...
- Golang 编写 Tcp 服务器
Golang 作为广泛用于服务端和云计算领域的编程语言,tcp socket 是其中至关重要的功能.无论是 WEB 服务器还是各类中间件都离不开 tcp socket 的支持. Echo 服务器 拆包 ...
- windows服务器自动删除日志文件
https://blog.csdn.net/u010050174/article/details/72510367 步骤: 1.新建 一个bat脚本 2.添加到window执行计划中,进行每日执行. ...
- php编写tcp服务器和客户端程序
这是我从别的地方看到的. 1.修改php.ini,打开extension=php_sockets.dll 2.客户端程序 SocketClient.php <?php set_time_limi ...
- 【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序
最近通过 PyQt5 设计了一个下载服务器指定日期日志文件的程序,里面有些有意思的技术点,现在做一些分享. PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI ...
- TCP服务器程序
Linux下编写TCP服务器调用的函数顺序为:socket -> bind -> listen -> accept -> recv/send socket 参见:http:// ...
- 记一次log4j日志文件输出错误的解决
log4j错误信息:log4j:ERROR Failed to rename [D:/logs/wmts_] to [D:/logs/wmts_2015-12-21.log ]. 起因:部门网站使用B ...
- Java实时读取日志文件
古怪的需求 在实习的公司碰到一个古怪的需求:在一台服务器上写日志文件,每当日志文件写到一定大小时,比如是1G,会将这个日志文件改名成另一个名字,并新建一个与原文件名相同的日志文件,再往这个新建的日志文 ...
- Windows 2003 Server C盘空间被IIS日志文件消耗殆尽案例
今天突然收到手头一台数据库服务器的磁盘空间告警邮件,C盘空间只剩下5.41GB大小(当系统磁盘剩余空间小于总大小的10%时,发出告警邮件),如下图所示: 由于还有一些微弱印象:前阵子这台服务器的C盘剩 ...
随机推荐
- Netsh命令-网络禁用开启
禁用无线网卡:netsh interface set interface wlan0 disabled 启用无线网卡:netsh interface set interface wlan0 enabl ...
- hdu1693 Eat the Trees 【插头dp】
题目链接 hdu1693 题解 插头\(dp\) 特点:范围小,网格图,连通性 轮廓线:已决策点和未决策点的分界线 插头:存在于网格之间,表示着网格建的信息,此题中表示两个网格间是否连边 状态表示:当 ...
- 使用adb录制手机屏幕视频
adb shell screenrecord命令可以用来录制Android手机视频 screenrecord是一个shell命令,支持Android4.4(API level 19)以上,支持视频格式 ...
- 【bzoj1502】月下柠檬树
Portal -->bzoj1502 Solution 额其实说实在这题我一开始卡在了..这个阴影长啥样上QwQ 首先因为是平行光线然后投影到了一个水平面上所以这个投影一定是..若干个圆再加上这 ...
- Linux基础--------centos7 安装python3(yum安装)
#安装sqlite-devel yum -y install sqlite-devel #安装依赖 yum -y install make zlib zlib-devel gcc-c++ libtoo ...
- joomla! 3.X 开发系列教程
http://www.mengyunzhi.com/members-resource/joomla/87-joomla-menu-study.html 学习地址 http://blog.csdn.ne ...
- POJ2975:Nim(Nim博弈)
Nim Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7279 Accepted: 3455 题目链接:http://p ...
- 电商网站中价格的精确计算(使用BigDecimal进行精确运算(实现加减乘除运算))
使用BigDecimal的String的构造器.商业计算中,使用bigdecimal的String构造器,一定要用. 重要的事情说三遍: 商业计算中,使用bigdecimal的String构造器! 商 ...
- php实现多继承-trait语法
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait. Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制.Trait 为了减少单继承语言的限制,使开发人员能 ...
- 怎样在hibernate的HQL语句中使用mysql 的自定义函数?
问题:怎样在hibernate中使用mysql的函数? 1.hibernate支持原生态的sql语句查询,使用session.createSQLQuery()创建查询对象: 2.怎样在hql中使用my ...