WebKit之log调试

来源:互联网 发布:苹果怎么只用2g网络 编辑:程序博客网 时间:2024/05/16 03:56

WebKit之log调试

       WebKit代码量较大,很多逻辑非常复杂,光使用断点调试,可能不能更直观看到想要观察的数据。一方面对于一些嵌套非常强的逻辑,例如:递归等,使用断点调试很难直观看到相互关系,WebKit中一个典型的递归应用就是对于render树等树形结构的的遍历,比如我们要打印出一个render树的各个节点,要直观的看到其结构,就需要使用Log另外一方面WebKit中很多对象巨大,变量隐藏很深,比如嵌套5,6个基类,并且还有智能指针的包裹,使得使用vc展开观看非常麻烦,所以传统的log打印对于我们来说仍然需要。 这里介绍webkit log打印部分,工程来自webkit.org下载的vc工程,在windows上编译通过。
        可能使用者第一反应就是使用stdio里面的一些printf方法等,还有就是c++的cin,cout等,经笔者尝试都是徒劳的,不能显示出来。进一步研究发现,webkit在wtf里面专门做了打印的相关包装。WTF是一个子工程,其主要为WebKit提供各种基础工具,这里封装了,著名的智能指针,断言,log输出,内存分配管理,甚至重写了一套独立的容器类,比如hashmap,hashSet,Vector等,其中最为重要是智能指针的实现。其输出为\WebKitBuild\lib。
        WTF里面Assertions.cpp提供了log输出的功能函数,其包装了vprintf_stderr_common,并且提供了一个功能强大灵活多变的,带有check性质的Log输出函数WTFLog。
WTFLog是一个传统的变参函数,定义如下:
       void WTFLog(WTFLogChannel* channel, const char* format, ...)
      比较其差别在于第一个参数,channel。该变量作用为可以进行log输出控制等操作。
      typedef enum { WTFLogChannelOff, WTFLogChannelOn } WTFLogChannelState;
      typedef struct {
         unsigned mask;
         const char *defaultName;
         WTFLogChannelState state;
     } WTFLogChannel;
      这里的WTFLogChannelState,管理是否打印输出。
      可能使用者,立马就想到实际调用WTFLog进行打印,但是而WTFLog,该函数没有进行暴露,而是通过Assertions.h进行变化发布出来供大家使用。Assertions.h该文件主要定义了一些assert的一些接口,附带提供了打印输出。
     #define  LOG(channel, ...)
     WTFLog (&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX,  channel), __VA_ARGS__)
 
      这里定义了LOG宏.该宏调用WETLog.
使用者看到这里可能进一步微笑了,终于发现有头文件暴露出打印接口,但是同时也迷惑于第一个参数channel,不知道干啥的。同时查看下面的定义也一头雾水:&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX,  channel)。
     发现下面还定义了两个宏:
     #define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel)
     #define JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) prefix ## channel
     做一个进一步转化发现,这里第一个参数channel会增加一个preifix,传入到WTFLog函数。
 
       快速的在代码中写下LOG(myChannel,“mytest”);并包含对应头文件。发现编译不过,这里需要定义channel这个变量.webkit大致有两个文件定义channel,当然用户可以自行定义。他们分别是; WebKitLogging.h以及Logging.h.其中WebKitLogging.h主要用于和平台交互相关部分的打印,比如windows部分定义在webkit\win.而logging.h主要负责其他部分的打印。在webview.cpp等和平台交互的基本用webKitLogging.h控制,而webCore里面的基本都用Logging.h来控制。当然还有其他的定义文件,没有关注过。
      在Logging.h WebKitLogging.h分别定义了LOG_CHANNEL_PREFIX,如下WebKitLogging.h中的定义:
     #define LOG_CHANNEL_PREFIX WebKitLog,因此组合出变量名为WebKitLogXXX,故我们需要定义类似WebKitLogXXX这样的channl变量。刚好下面extern定义了各个模块的log chanel.
     extern WTFLogChannel WebKitLogTextInput;
     extern WTFLogChannel WebKitLogTiming;等全局变量.
      这样我们只要引用了WebKitLogging.h便能使用类似,LOG(myChannel,“mytest”)的打印语句。进而观察WebKitLogging.cpp详细的定义了各个全局变量,如下:
     WTFLogChannel WebKitLogTextInput =              { 0x00000010, "WebKitLogLevel", WTFLogChannelOff };
     WTFLogChannel WebKitLogTiming =                 { 0x00000020, "WebKitLogLevel", WTFLogChannelOff };
     这里的结构体初始化的最后一个参数就是控制log是否打印的开关。如:WTFLogChannelOff 就是控制。
     同理 Logging.h也定义了类似的LOG_CHANNEL_PREFIX 以及全局变量,而我们的webCore里面的打印基本都使用的Logging.h。
 
    使用该Log输出方式打印出一个简单的render树如下:
     begin to visitor RenderTree
     visitor index=0-#document
     visitor index=1-HTML
     visitor index=2-BODY
     visitor index=3-#text
     visitor index=3-#text
     visitor index=3-BUTTON
     visitor index=4   / /匿名标签生成
     visitor index=5-#text
     visitor index=3-#text
     visitor index=3-#text
 
     综上所述总结一下webkit对于log打印的设计思想:
       1.WebKit的wtf里面封装了log打印的逻辑,并且以LOG宏的形式提供给外部使用,而真实实现函数WTFLog不暴露而被隐藏掉了。调用则使用宏非常简洁,代码得以优雅。
       2.调用者只需要引用WebKitLogging.h或Logging.h,从而回避了去定义channel变量这个过程,也是就说webkit意在隐藏掉WTFLogChannel这个数据结构的存在,而又要能控制log输出开关。
       3. 使用channel全局变量进行配置,并在对应.cpp文件中进行修改,使得如果即使修改控制开关,也不会引起全编译。
       4.使用Channel对log输出进行管理,还能控制打印级别,后面可以在WTFLog函数中添加控制逻辑,也不会影响其他代码。

原创粉丝点击