• 动手编写TCP服务器系列之一:日志文件


    前言

       在几个月之前,笔者想自己实现一个性能比较良好的基于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           "
    "
    #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] != '' )
        {
            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

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

  • 相关阅读:
    Java 解惑:Random 种子的作用、含参与不含参构造函数区别
    Linux系统网络性能实例分析
    数据库服务器的性能调优-续
    Spring代理模式及AOP基本术语
    Spring框架总结
    单例模式和多例模式
    jqueryUI小案例
    Ajax讲解
    数据校验和国际化
    文件上传(多文件上传)/下载
  • 原文地址:https://www.cnblogs.com/gina/p/3253189.html
Copyright © 2020-2023  润新知