动手编写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盘剩 ...
随机推荐
- C/C++语言中让电脑随机的在某个范围中的任一随机数
这是我在笔试中碰见的一题中一部分,这就就记录下来.举例,输出[1,3]中任一随机数. #include<iostream> #include<cstdlib> #include ...
- springboot读取自己定义的配置文件的方式以及使用joda_time来处理时间日期
总的来说呢,有两种方式,一种是原始的方式,即使用PropertiesUtils来读取配置文件. 第二种就是使用springboot的注解的方式来读取配置文件. 1.原始方式处理属性和时间日期: 工具类 ...
- 对于redis底层框架的理解(一)
近期学习了redis底层框架,好多东西之前都没听说过,算是大开眼界了. 先梳理下redis正常的通讯流程吧 首先服务器启动都有主函数main,这个main函数就在redis.c里 首先是initser ...
- CSS3方法总汇
PS:CSS3的3D和我做研发时的3D不一样他们只能旋转180度 横为X竖为Z高为Y transfrom:2D3D转换 rotareX:绕着X轴旋转 rotareY(-180deg):绕着Y轴旋转- ...
- Debian最完美安装flash的教程//适用于所有linux版本
话说不管是新手还是老手,都离不开flash.没有flash的支持,菜鸟们也少了一些把玩linux的动力. flash有很多安装的方法,不过性能相差很大.这里的缘由就不重要了. 下面我介绍在chromi ...
- vue 和react
React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件. 将注意力集中保持在核心库,而将其 ...
- HDU 2138 Miller-Rabin 模板题
求素数个数. /** @Date : 2017-09-18 23:05:15 * @FileName: HDU 2138 miller-rabin 模板.cpp * @Platform: Window ...
- LightOJ 1065 - Number Sequence 矩阵快速幂水题
http://www.lightoj.com/volume_showproblem.php?problem=1065 题意:给出递推式f(0) = a, f(1) = b, f(n) = f(n - ...
- CSS3的新属性
1.圆角矩形 .border_radius_test{ border-radius:25px; -moz-border-radius:25px; } 数值越大越圆 2.容器阴影 .box_shadow ...
- js获取上、下级html元素 js删除html元素方法
js获取下级html元素:htmlEle.childNode; js获取上级html元素:htmlEle.parentNode; js删除当前html元素: htmlEle.removeNode(tr ...