前言

在几个月之前,笔者想自己实现一个性能比较良好的基于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服务器系列之一:日志文件的更多相关文章

  1. lnmp vps服务器删除mysql日志文件三种方法

    我在上一篇文章介绍了著名的LNMP主机一键安装工具,对比了军哥lnmp和AMH主机的差别,由于AMH拥有用户后台界面,易于新手操作,值得推荐. 但是,上周末我网站宕机,收到DNSPOD发来了宕机提醒, ...

  2. Golang 编写 Tcp 服务器

    Golang 作为广泛用于服务端和云计算领域的编程语言,tcp socket 是其中至关重要的功能.无论是 WEB 服务器还是各类中间件都离不开 tcp socket 的支持. Echo 服务器 拆包 ...

  3. windows服务器自动删除日志文件

    https://blog.csdn.net/u010050174/article/details/72510367 步骤: 1.新建 一个bat脚本 2.添加到window执行计划中,进行每日执行. ...

  4. php编写tcp服务器和客户端程序

    这是我从别的地方看到的. 1.修改php.ini,打开extension=php_sockets.dll 2.客户端程序 SocketClient.php <?php set_time_limi ...

  5. 【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序

    最近通过 PyQt5 设计了一个下载服务器指定日期日志文件的程序,里面有些有意思的技术点,现在做一些分享. PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI ...

  6. TCP服务器程序

    Linux下编写TCP服务器调用的函数顺序为:socket -> bind -> listen -> accept -> recv/send socket 参见:http:// ...

  7. 记一次log4j日志文件输出错误的解决

    log4j错误信息:log4j:ERROR Failed to rename [D:/logs/wmts_] to [D:/logs/wmts_2015-12-21.log ]. 起因:部门网站使用B ...

  8. Java实时读取日志文件

    古怪的需求 在实习的公司碰到一个古怪的需求:在一台服务器上写日志文件,每当日志文件写到一定大小时,比如是1G,会将这个日志文件改名成另一个名字,并新建一个与原文件名相同的日志文件,再往这个新建的日志文 ...

  9. Windows 2003 Server C盘空间被IIS日志文件消耗殆尽案例

    今天突然收到手头一台数据库服务器的磁盘空间告警邮件,C盘空间只剩下5.41GB大小(当系统磁盘剩余空间小于总大小的10%时,发出告警邮件),如下图所示: 由于还有一些微弱印象:前阵子这台服务器的C盘剩 ...

随机推荐

  1. Android ActionBar 使用详解

    ActionBar取代了以前的TitleBar,是一种更加灵活的人机交互方式:ActionBar并不是完全自立门户的一个新兴的东西,而是和3.0以下版本的menu进行了合并整合:so,添加action ...

  2. 【BZOJ2437】【NOI2011】兔兔与蛋蛋(博弈论,二分图匹配)

    [BZOJ2437][NOI2011]兔兔与蛋蛋(博弈论,二分图匹配) 题面 BZOJ 题解 考虑一下暴力吧. 对于每个状态,无非就是要考虑它是否是必胜状态 这个直接用\(dfs\)爆搜即可. 这样子 ...

  3. BZOJ5314 [Jsoi2018]潜入行动 【背包类树形dp】

    题目链接 BZOJ5314 题解 设\(f[i][j][0|1][0|1]\)表示\(i\)为根的子树,用了\(j\)个监测器,\(i\)节点是否被控制,\(i\)节点是否放置的方案数 然后转移即可 ...

  4. POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询)

    POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询) 题意分析 注意一下懒惰标记,数据部分和更新时的数字都要是long long ,别的没什么大 ...

  5. 【bzoj4212】神牛的养成计划

    Portal --> bzoj4212 Description ​ 给你\(n\)个字符串,接下来有\(m\)个询问,每个询问由两个给定的字符串\(s_1\)和\(s_2\)组成,对于每个询问输 ...

  6. static_cast 和 dynamic_cast

    1.static_cast static_cast < type-id > ( expression ) 该运算符把expression转换为type-id类型,但没有运行时类型检查来保证 ...

  7. 关于OpenCV的stitching使用

    配置环境:VS2010+OpenCV2.4.9 为了使用OpenCV实现图像拼接头痛了好长时间,一直都没时间做,今天下定决心去实现基本的图像拼接. 首先,看一看使用OpenCV进行拼接的方法 基本都是 ...

  8. CDOJ--1369

    原题链接:http://acm.uestc.edu.cn/problem.php?pid=1369&cid=192 分析:DP,dp[i][0]表示第i个人不是lover时的最小值,dp[i] ...

  9. xshell输入奇怪,空格间距变大

    https://www.macx.cn/thread-2018939-1-1.html 按一下shift+空格就行了 全角/半角转换的快捷键... dd

  10. WPF系列之一:基于并行任务和MVVM创建响应灵敏和数据驱动的UI

    在利用WPF创建桌面应用程序的界面时,经常使用MVVM的设计模式,以减少UI层与逻辑层的代码耦合度. 在MVVM的设计中,最主要的方法和技术是UI中的控件利用Binding来和逻辑层(ViewMode ...