• log4c面向对象设计 (转)


    转自 http://blog.csdn.net/xkarl/article/details/6340180

    Log4C,Log4CPlus/Log4cpp,Log4j,Log4Net,Log4Perl,Log4PHP,Log4PLSQL,Log4LS,Log4py,Log4r,qmmslog,JDK1.4's util.logging framework是常用的LOG调试库,log4**的架构都类似

           虽然C不是面向对象语言,但是log4c的实现完全是面向对象思想,和log4j的实现方式几乎雷同

           Log4c需要设置的,也就是面向用户的,接口有

    category:log的日志模块

    Appender:log输出方式stream,mem,syslog等

    Layout:log打印方式,基本的,详细的(比如详细时间等)


    1、  Factory Method工厂方法的管理

           这里的SD(Service Design)就相当于一个N个工厂集合(log4c_category_factory和log4c_appender_factory和log4c_layout_factory是单态的工厂,通过sd_factory_xx来做管理)

           不要理解为polymorphism,只不过提供一个Service Design的统一API而已,根据实际需要是可以分离开的,

    factory.h :

    struct __sd_factory { 

       char* fac_name; 

       const sd_factory_ops_t* fac_ops; 

       sd_hash_t* fac_hash; 

    };

    typedef struct __sd_factory sd_factory_t;

    extern sd_factory_t* sd_factory_new(const char* a_name, const sd_factory_ops_t* a_ops);

    extern voidsd_factory_delete(sd_factory_t* a_this);
    extern void*sd_factory_get(sd_factory_t* a_this, const char* a_name);
    extern voidsd_factory_destroy(sd_factory_t* a_this, void* a_pr);
    extern voidsd_factory_print(const sd_factory_t* a_this, FILE* a_stream);
    extern intsd_factory_list(const sd_factory_t* a_this, void** a_items,
    int a_nitems);

    2、  Factory Method工厂方法

           因为面向用户配置选项,appender和layout在用户看来接口都一样,创建和删除以及打印,拥有共同的操作,fac_new/fac_delete/fac_print

    factory.h :

    struct __sd_factory { 

       char* fac_name; 

       const sd_factory_ops_t* fac_ops; 

       sd_hash_t* fac_hash; 

    };

    typedef struct __sd_factory sd_factory_t;

    struct __sd_factory_ops

    {

       void* (*fac_new)     (const char*);

       void  (*fac_delete)         (void*);

       void  (*fac_print)   (void*, FILE*);

    };

    typedef struct __sd_factory_opssd_factory_ops_t;

           fac_name用来区分appender/layout,fac_hash用来储存,方便查 找,如果更多的接口的话都无妨(个人喜好用链表代替hash),当不同模块Appender.c/ Layout.c都预先添加到hash中,如果还有ABC模块/XYZ模块,照样预先添加到HASH,模块非常的独立

    Appender.c :

    static const sd_factory_ops_tlog4c_appender_factory_ops = {

     (void*) log4c_appender_new,

     (void*) log4c_appender_delete,

     (void*) log4c_appender_print,

    };

    Layout.c :

    static const sd_factory_ops_tlog4c_layout_factory_ops = {

             (void*)log4c_layout_new,

             (void*)log4c_layout_delete,

             (void*)log4c_layout_print,

    };

           添加子fac到HASH后,在用户接口层,根据fac_name,通过 sd_hash_lookup查找HASH,找到fac_ops,有了fac_ops,就有了fac_new/fac_delete /fac_print,这个时候的地址是相应的函数指针----或者appender或者layout或者ABC或者XYZ

    3、  Descriptor多态

           在log4c_appender_new具体函数中,又面临一个问题是,appender有不同的输出方式:stream,mem,syslog等,

    appender.h :

    typedef struct log4c_appender_type {

       const char*       name;

       int (*open)          (log4c_appender_t*);

       int (*append) (log4c_appender_t*, const log4c_logging_event_t*);

       int (*close)  (log4c_appender_t*);

    } log4c_appender_type_t;

    Appender.c :

    static const log4c_appender_type_t * constappender_types[] = {

       &log4c_appender_type_stream,

       &log4c_appender_type_stream2,

       &log4c_appender_type_mmap,

       &log4c_appender_type_syslog,   

       &log4c_appender_type_rollingfile

    };

    static size_t nappender_types =sizeof(appender_types) / sizeof(appender_types[0]);

           这里用一个指针数组,毕竟输出类型是有限的

    Appender_type_stream.c :

    const log4c_appender_type_tlog4c_appender_type_stream = {

       "stream",

       stream_open,

       stream_append,

       stream_close,

    };

    Appender_type_mmap.c :

    const log4c_appender_type_tlog4c_appender_type_mmap = {

       "mmap",

       mmap_open,

       mmap_append,

       mmap_close,

    };

    Appender_type_syslog.c :

    const log4c_appender_type_tlog4c_appender_type_syslog = {

       "syslog",

       syslog_open,

        syslog_append,

       syslog_close,

    };

           同样操作,将上面不同类型添加到HASH,上面是指针数组的成员,在 log4c_appender_type_get运行时候,根据appender_name,通过通过sd_hash_lookup查找HASH,找到 open/ append/ close的指针,也就是具体的函数指针,或者stream_open/ mmap_open/ syslog_open等

           在log4c_layout_new具体函数中,有不同的输出方式:data,time等,同样是一个多态的实现

    4、  实际应用例子

    int main()
    {
    ...
    root = log4c_category_get("root");
    sub1 = log4c_category_get("sub1");


    layout1   = log4c_layout_get("layout1");
    log4c_appender_t* appender1 = log4c_appender_get("appender1");


    log4c_layout_set_type(layout1, &log4c_layout_type_basic_r);


    log4c_appender_set_layout(appender1, layout1);
    log4c_appender_set_udata(appender1,  stdout);


    log4c_category_set_appender(sub1, appender1);
    log4c_category_set_priority(sub1, LOG4C_PRIORITY_ERROR);
    ...
    }

           factory打印结果,udata是stderr、stdout等:
    factory[log4c_category_factory]:
    { name:'root' priority:NOTSET additive:1 appender:'(nil)' parent:'(nil)' }
    { name:'sub1' priority:ERROR additive:1 appender:'appender1' parent:'root' }

    factory[log4c_appender_factory]:
    { name:'stderr' type:'stream' layout:'basic' isopen:0 udata:10311428}
    { name:'stdout' type:'stream' layout:'basic' isopen:0 udata:10311408}
    { name:'appender1' type:'stream' layout:'layout1' isopen:0 udata:10311428}

    factory[log4c_layout_factory]:
    { name:'layout1' type:'basic_r' udata:00000000 }
    { name:'basic' type:'basic' udata:00000000 }
    { name:'dated' type:'dated' udata:00000000 }
           (1)可以看到有几个默认设置的,这是因为代码中默认配置了几项:
    /* build default appenders */
    log4c_appender_set_udata(log4c_appender_get("stderr"), stderr);
    log4c_appender_set_udata(log4c_appender_get("stdout"), stdout);

    /* build default layouts */
    log4c_layout_set_type(log4c_layout_get("dated"), &log4c_layout_type_dated);
    log4c_layout_set_type(log4c_layout_get("basic"), &log4c_layout_type_basic); 

           (2)3次fac_ops

    log4c_category_factory = sd_factory_new("log4c_category_factory",&log4c_category_factory_ops);
    log4c_appender_factory = sd_factory_new("log4c_appender_factory",&log4c_appender_factory_ops);
    log4c_layout_factory = sd_factory_new("log4c_layout_factory",&log4c_layout_factory_ops);  
    (后两个new的时候是默认的类型log4c_appender_type_stream log4c_layout_type_basic)
    (log4c_appender_factory->fac_hash,log4c_layout_factory->fac_hash类似LIST_HEAD的概念)
    (a_name对应就是log4c_***_type_t中的name)

           (3)如果配置在log4crc:
    <category name="mycat" priority="debug" appender="stdout" />     
    <appender name="stdout" type="stream" layout="basic"/>    
    <layout name="basic" type="basic"/>
    3次fac_ops、3次sd_factory_get,不同的是,会增加
    log4c_category_set_priority
    log4c_appender_set_type
    log4c_layout_set_type
    来配置类型

    5、  小结

           其实Factory_ops和Discriptor都没有必要HASH或者链表,毕竟这里分类有限,特别是对于log4c的代码而言,Discriptor直接数组中循环判断即可,HASH完全是多余

           反倒是Factory_ops在分类很多的情况下,采用HASH或者链表,因为 Factory_ops面向的层次更高,实际项目中分工是每个人几个子fac,采用数组耦合性太强,采用HASH或者链表,只要新加一个fac_ops, 只需添加到HASH或者链表,到时候查找即可

           在fac_ops具体实现中,name不同,就必须新开一块内存,所以必须采用HASH或者链表,比如log4c_appender_factory->fac_hash,log4c_layout_factory->fac_has就是HASH的HEAD

  • 相关阅读:
    Different AG groups have the exactly same group_id value if the group names are same and the ‘CLUSTER_TYPE = EXTERNAL/NONE’
    An example of polybase for Oracle
    use azure data studio to create external table for oracle
    Missing MSI and MSP files
    You may fail to backup log or restore log after TDE certification/key rotation.
    Password is required when adding a database to AG group if the database has a master key
    Use KTPASS instead of adden to configure mssql.keytab
    ardunio+舵机
    android webview 全屏100%显示图片
    glide 长方形图片显示圆角问题
  • 原文地址:https://www.cnblogs.com/little-ant/p/3664222.html
Copyright © 2020-2023  润新知