惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
博客园 - 【当耐特】
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Attack and Defense Labs
Attack and Defense Labs
爱范儿
爱范儿
The Cloudflare Blog
腾讯CDC
Security Archives - TechRepublic
Security Archives - TechRepublic
TaoSecurity Blog
TaoSecurity Blog
云风的 BLOG
云风的 BLOG
Recent Announcements
Recent Announcements
C
Check Point Blog
Schneier on Security
Schneier on Security
S
Schneier on Security
J
Java Code Geeks
B
Blog RSS Feed
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
Stack Overflow Blog
Stack Overflow Blog
博客园_首页
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
About on SuperTechFans
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
A
Arctic Wolf
S
Secure Thoughts
P
Palo Alto Networks Blog
The Last Watchdog
The Last Watchdog
SecWiki News
SecWiki News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
U
Unit 42
I
InfoQ
D
DataBreaches.Net
P
Privacy International News Feed
T
Troy Hunt's Blog
博客园 - 叶小钗
T
Threatpost
博客园 - Franky
K
Kaspersky official blog
Hugging Face - Blog
Hugging Face - Blog
IT之家
IT之家
www.infosecurity-magazine.com
www.infosecurity-magazine.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cisco Blogs

博客园 - 进击的程序员

cuowu Angular4+路由 由href return false 来看阻止默认事件 TypeScript的配置文件 tsconfig.json Java标记接口 Shell语言系列之一:文件处理 给Amazon ec2 增加卷(Volume)并挂载到系统 Java打包问题之一:打包出现java.io.IOException: invalid header field struct中长度为0的数组用途与原理 面试题之堆栈队列系列一:设计包含min函数的栈 awk处理之案例六:awk根据条件插入文本 程序员的数学之余数:星期数的思考 面试题之实现系统函数系列一:实现memmove函数 awk处理之案例五:awk匹配字段2包含字段1的文本 awk处理之案例四:sort加awk来过滤文本 字符串面试题系列之七:字符串全排列 awk处理之案例三:awk去掉不需要的文本行 awk处理之案例二:awk匹配文本 awk处理之案例一:awk 处理百分比的问题
动手编写TCP服务器系列之一:日志文件
进击的程序员 · 2013-08-12 · via 博客园 - 进击的程序员

前言

   在几个月之前,笔者想自己实现一个性能比较良好的基于tcp的服务器。于是断断续续写了个把月,因为还需要找工,还有论文什么的。拖了这么久。现在开辟这样的一个博客,我想记录下自己的思路,也和大家分享自己的代码。个人觉得一个优秀的服务器,不能考虑各种通用性,平台无关性。我写的这个服务器只针对linux平台。

   在写这个系列文章之前,我想把功能都独立出来。每一篇文章专注于一个功能。

    本系列文章均系笔者所写,难免有一些错误或者纰漏,如果小伙伴们有好的建议或者更好的算法,请不吝赐教。

正文

目标

   本篇文章主要是讲TCP Server的日志功能。那么在一个服务器当中日志功能是必不可少的。无论是定位错误或者打印一些信息等等。日志的预期目标如下图所示。

8

   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

   本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。