架构设计 - 日志管理接口设计

在后端代码中,日志无处不在,设计一套自己的日志管理代码,给框架提供一套好用的日志接口将大大方便代码的开发。

其中在日志管理代码的编写中,主要有以下难点:

1.数目不确定的入参函数编写

2.日志权限控制

3.日志输出形式。

接口设计:

1.提供三类日志打印形式:1)控制台打印信息,类似printf的接口封装

            2)函数追踪接口,打印当前代码的文件名,函数名及行,以及一些设定的输出参数

            3)日志打印函数,提供打印级别控制,且打印内容输出到日志文件中

2.提供日志级别控制:1)在打印日志时提供当前日志级别,代码依据级别进行控制打印

          2)日志打印级别控制暂时使用配置文件,后续可以通过通信接口进行实时修改

下面附上代码实现:DMLogManager.h

 1 //=============================================================================
 2 /* 
 3 *  File: DMLogManager.h
 4 *
 5 *  Author: bing
 6 *
 7 *  Date: 2016-09-07
 8 *
 9 *  Version: v2.0
10 *
11 *  Github/Mail: https://github.com/binchen-china    <563853086@qq.com>
12 *
13 *  Note:
14 */
15 //=============================================================================
16 
17 #pragma once
18 #include "DMaker.h"
19 
20 enum LOG_LEVEL
21 {
22     DM_ERROR = 0x0001,
23     DM_WARNING  = 0x0010,
24     DM_INFO = 0x0100,
25     DM_DEBUG = 0x1000
26 };
27 
28 class DMLogManager
29 {
30 public:
31     DMLogManager();
32     
33     ~DMLogManager();
34 
35     void print_log(const DM_CHAR* fmt, ...);
36    
37     void trace_log(string file, string func, DM_INT line, const DM_CHAR* fmt, ...);
38           
39     void write_log(DM_INT log_level, string file, string func, DM_INT line, const DM_CHAR* fmt, ...);
40     
41 private:
42     void init();
43 
44     void get_log_config();
45     
46     inline void open_log_file();
47     
48     inline void close_log_file();
49     
50     void set_log_level();
51 
52 private:
53     FILE* _log_file;
54     string _log_name;
55     string _log_level;
56     DM_INT _log_mask;
57 };
58 
59 typedef ACE_Singleton<DMLogManager, ACE_Thread_Mutex> DMLogMgr;
60 
61 //console output without code info
62 #define DM_PRINT(LOG_FMT,args...) DMLogMgr::instance()->print_log(LOG_FMT,##args)
63 //console output with code info
64 #define DM_TRACE(LOG_FMT,args...) DMLogMgr::instance()->trace_log(__FILE__,__FUNCTION__,__LINE__,LOG_FMT,##args)
65 //write logs into log file
66 #define DM_LOG(LOG_LEVEL,LOG_FMT,args...) DMLogMgr::instance()->write_log(LOG_LEVEL,__FILE__,__FUNCTION__,__LINE__,LOG_FMT,##args)

DMLogManager.cpp

#include "DMLogManager.h"

DMLogManager::DMLogManager():_log_mask(0)
{
    init();
}

DMLogManager::~DMLogManager()
{
    
}

void DMLogManager::init()
{
    get_log_config(); 
    set_log_level();
}

void DMLogManager::get_log_config()
{
    _log_name = DMJsonCfg::instance()->GetItemString("service_info", "service_name");
    _log_level = DMJsonCfg::instance()->GetItemString("service_info", "log_level");
    _log_name.append(".log");
}

inline  void DMLogManager::open_log_file()
{
    _log_file = fopen(_log_name.c_str(), "a");
    if (nullptr == _log_file)
    {    
        return;
    }    
}

inline  void DMLogManager::close_log_file()
{
    fclose(_log_file);
}

void DMLogManager::set_log_level()
{
    if ("DEBUG" == _log_level)
    {
        _log_mask = 0x1111;
    }
    else if ("INFO" == _log_level)
    {
        _log_mask = 0x0111;
    }
    else if ("WARNING" == _log_level)
    {
        _log_mask = 0x0011;
    }
    else if ("ERROR" == _log_level)
    {
        _log_mask = 0x0001;
    }
}

void DMLogManager::print_log(const DM_CHAR* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
               
    string log_info = fmt;     
    ACE_OS::vfprintf(stdout, fmt, ap);  

    va_end (ap);
}

void DMLogManager::trace_log(string file, string func, DM_INT line, const DM_CHAR* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
               
    ACE_OS::printf("[DM_TRACE][%s][%s][%d]:",file.c_str(), func.c_str(), line);               
    string log_info = fmt;     
    ACE_OS::vfprintf(stdout, fmt, ap);  

    va_end (ap);
}

void DMLogManager::write_log(DM_INT log_level, string file, string func, DM_INT line, const DM_CHAR* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    
    open_log_file();
    
    switch (log_level)
    {
        case DM_DEBUG:
        {
            if (DM_DEBUG & _log_mask)
            {               
                ACE_OS::fprintf(_log_file, "[DM_DEBUG][%s][%s][%d]:",file.c_str(), func.c_str(), line);                 
                ACE_OS::vfprintf(_log_file, fmt, ap);  
            }            
            break;
        }
        case DM_INFO:
        {
            if (DM_INFO & _log_mask)
            {
                ACE_OS::fprintf(_log_file, "[DM_INFO][%s][%s][%d]:",file.c_str(), func.c_str(), line);                  
                ACE_OS::vfprintf(_log_file, fmt, ap);  
            }
            break;
        }
        case DM_WARNING:
        {
            if (DM_WARNING & _log_mask)
            {
                ACE_OS::fprintf(_log_file, "[DM_WARNING][%s][%s][%d]:",file.c_str(), func.c_str(), line);                 
                ACE_OS::vfprintf(_log_file, fmt, ap);  
            }
            break;
        }
        case DM_ERROR:
        {
            if (DM_ERROR & _log_mask)
            {
                ACE_OS::fprintf(_log_file, "[DM_ERROR][%s][%s][%d]:",file.c_str(), func.c_str(), line);                 
                ACE_OS::vfprintf(_log_file, fmt, ap);       
            }
            break;
        }
    }
    
    close_log_file();
    va_end (ap);
}

更多技术信息请关注github:https://github.com/binchen-china

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏跟着阿笨一起玩NET

C#如何快速高效地导出大量数据?

本文转载:http://www.cnblogs.com/herbert/archive/2010/07/28/1787095.html

901
来自专栏技术博文

Linux命令英文全称

su:Swith user  切换用户,切换到root用户 cat: Concatenate  串联 uname: Unix name  系统名称 df: Di...

3405
来自专栏高性能服务器开发

(三) 服务器端的程序架构介绍2

下面我们以pc端登录为例来具体看一个数据包在服务器端各个服务之间走过的流程: 步骤1:login_server初始化侦听socket,设置新连接到来的回调函数。...

3594
来自专栏码匠的流水账

聊聊spring对kafka的集成方式

除了官方的java api类库外,spring生态中又额外包装了很多,这里一一简单介绍下。

931
来自专栏菩提树下的杨过

将淘宝数据包导入自己的商城系统

淘宝网有一个淘宝助理,可以方便的将淘宝店的商品资源导出成csv格式的数据包。很多商城系统为了能快速输入商品,都会要求开发者能最大限度的利用淘宝数据包直接导入产品...

1939
来自专栏我和未来有约会

Silverlight 2 has a Timer (DispatcherTimer)

在Silverlight 2以前的版本里中有很多不同的方法来模拟Timer.其中最流行的方法就是用StoryBoard来完成.在结束时不停的调用自己. 例如: ...

1949
来自专栏数据库新发现

Oracle诊断案例-SGA与Swap之一

案例描述: 用户报告,服务器启动一段时间以后,无法建立数据库连接 重新启动几分钟以后,再次无法连接 系统无法正常使用.

762
来自专栏大大的微笑

ActiveMQ几个重要的配置文件

version:5.10,在5.8以后增加了levelDB的方式进行集群配置 ①.wrapper.conf: # -----------------------...

4159
来自专栏杨建荣的学习笔记

dataguard中的密码文件管理(r8笔记第39天)

这篇文章的动力来自于一个朋友的提问,他问我备库的密码文件直接重建可以吗,我说最好还是复制,如果重建可能会有一些潜在的问题,当然这个所谓潜在问题也是自己给自己打的...

37013
来自专栏名山丶深处

springboot集成redis(mybatis、分布式session)

1558

扫码关注云+社区