`

debug模块源码

    博客分类:
  • node
 
阅读更多

1.debug日志打印模块

主要实现功能:带命名空间(模块名)、时间戳、色彩输出日志;将日志写入文件;浏览器端使用;格式化函数;支持自定义方法。

 

实现思路:通过环境变量设置配置项如是否启用有彩色输出、设定打印方法、设定命名空间(模块名);

       也可以通过require("debug").enable(namespace)添加命名空间,require("debug").enabled.useColors是否启用有彩色输出,require("debug").enabled.log自定义打印方法,require("debug").enabled.color社会颜色1|2|3|4|5|6,exports.formatters.a=function(){}添加格式化函数

 

2.使用:默认使用process.stderr('%s',"error")标准错误输出,替换%s字符

require("debug").enable("app") // 添加待测试模块
var debug=require("debug")("app") // 选择测试模块
debug("%o funciton(){}") // 打印日志

 

3.源码:服务器端启动文件为node.js,通过node.js加载debug.js

node.js

// package.json约定node.js为入口文件

var tty=require('tty');
var util=require('util');

exports=module.exports=require('./debug');

exports.log=log;

// 带色彩打印消息
exports.formatArgs=formatArgs;

// 更新process.env.DEBUG环境变量
exports.save=save;

// 待测试的模块通过环境变DEBUG量赋值
exports.load=load;

// 是否开启带颜色打印消息
exports.useColors=useColors;

// 颜色码
exports.colors=[6, 2, 3, 4, 5, 1];

/**
 * The file descriptor to write the `debug()` calls to.
 * Set the `DEBUG_FD` env variable to override with another value. i.e.:
 *
 *   $ DEBUG_FD=3 node script.js 3>debug.log
 */
var fd=parseInt(process.env.DEBUG_FD, 10) || 2;
var stream= 1===fd ? process.stdout :// 标准输出
            2===fd ? process.stderr :// 标准错误输出,默认
            createWritableStdioStream(fd);// 流式写入文件

// 是否开启带颜色输出
function useColors(){
    var debugColors=(process.env.DEBUG_COLORS || '').trim().toLowerCase();
    if ( 0===debugColors.length ){
        return tty.isatty(fd);
    }else{
        return '0'!==debugColors
            && 'no'!==debugColors
            && 'false'!==debugColors
            && 'disabled'!==debugColors;
    }
}

// util.inspect(obj,showHidden,depth,color)方法将对象转换为字符串,
// showHidden显示更多数据,depth递归的层数,color设置颜色
var inspect=( 4===util.inspect.length ?
    // node <= 0.8.x
    function (v, colors){
        return util.inspect(v,void 0,void 0,colors);// 
    } :
    // node > 0.8.x
    function (v, colors){
        return util.inspect(v,{colors:colors});
    }
);

// 类型不是字符串时,使用util.inspect方法转化成字符串后输出
exports.formatters.o=function(v){
    return inspect(v,this.useColors).replace(/\s*\n\s*/g, ' ');
};

// 带色彩打印消息
function formatArgs() {
    var args=arguments;
    var useColors=this.useColors;
    var name=this.namespace;

    if ( useColors ){
        var c=this.color;

        args[0]='  \u001b[3'+c+';1m'+name+' '
          +'\u001b[0m'
          +args[0]+
          '\u001b[3'+c+'m'+' +'+exports.humanize(this.diff)+'\u001b[0m';
    }else{
        args[0]=new Date().toUTCString()+' '+name+' '+args[0];
    }
    return args;
}

/**
 * Invokes `console.error()` with the specified arguments.
 */
function log(){
    return stream.write(util.format.apply(this,arguments)+'\n');
}

// 更新process.env.DEBUG环境变量
function save(namespaces){
    if ( null==namespaces ){
        delete process.env.DEBUG;
    }else{
        process.env.DEBUG = namespaces;
    }
}

// 待测试的模块通过环境变DEBUG量赋值
function load(){
    return process.env.DEBUG;
}

/**
 * Copied from `node/src/node.js`.
 *
 * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
 * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
 */
// 写入文件
function createWritableStdioStream (fd){
    var stream;
    var tty_wrap=process.binding('tty_wrap');

    // Note stream._type is used for test-module-load-list.js

    switch (tty_wrap.guessHandleType(fd)) {
        case 'TTY':
            stream = new tty.WriteStream(fd);
            stream._type = 'tty';

            // Hack to have stream not keep the event loop alive.
            // See https://github.com/joyent/node/issues/1726
            if (stream._handle && stream._handle.unref) {
              stream._handle.unref();
            }
            break;

        case 'FILE':
            var fs = require('fs');
            stream = new fs.SyncWriteStream(fd, { autoClose: false });
            stream._type = 'fs';
            break;

        case 'PIPE':
        case 'TCP':
            var net = require('net');
            stream = new net.Socket({
              fd: fd,
              readable: false,
              writable: true
            });

            // FIXME Should probably have an option in net.Socket to create a
            // stream from an existing fd which is writable only. But for now
            // we'll just add this hack and set the `readable` member to false.
            // Test: ./node test/fixtures/echo.js < /etc/passwd
            stream.readable = false;
            stream.read = null;
            stream._type = 'pipe';

            // FIXME Hack to have stream not keep the event loop alive.
            // See https://github.com/joyent/node/issues/1726
            if (stream._handle && stream._handle.unref) {
              stream._handle.unref();
            }
            break;

        default:
            // Probably an error on in uv_guess_handle()
            throw new Error('Implement me. Unknown stream file type!');
    }

    // For supporting legacy API we put the FD here.
    stream.fd=fd;

    stream._isStdio=true;

    return stream;
}

// 待测试的模块通过环境变DEBUG量赋值
exports.enable(load());

 

debug.js

// 使用前需要调用require("debug").enable(namespace)添加待测试模块,debug函数方可用
// 因此可用于区分开发环境和线上环境,开发环境用enable函数开启测试功能,线上则否
exports=module.exports=debug;

// 若为错误,返回错误的堆栈信息或错误消息,否则原样输出
exports.coerce=coerce;

// 更新process.env.DEBUG环境变量,没有清空exports.skips、exports.names忽略和待测试模块队列
exports.disable=disable;

// exports.names、exports.skips添加待测试模块及忽略模块
exports.enable=enable;

// 待测试的模块返回真值,其余返回否,exports.skips需要忽略的模块
exports.enabled=enabled;

exports.humanize = require('ms');

exports.names=[];// 需要测试的模块
exports.skips=[];// 需要忽略的模块

// 以小写字母作为键(o存储非字符串时的格式化函数),存储debug函数打印信息的格式化函数
// require("debug").formatters={a:function(str){return str.replace(/%/,"")}}
// var debug=require("debug").debug("app")
// debug("%123") 将打印app 123 +0ms
exports.formatters={};


var prevColor=0;// exports.colors起始位
var prevTime;// 缓存上次执行的时间

// 获取颜色码
function selectColor(){
    // 取余数,选择颜色码,用以拼接颜色字符串"\u001b[3"+"6|2|3|4|5|1"
    return exports.colors[prevColor++ % exports.colors.length];
}

// 参数namespace为模块名,返回函数,用于打印消息
function debug(namespace){

    function disabled(){
    }
    disabled.enabled=false;

    function enabled(){
        var self=enabled;

        // 计算执行时间
        var curr=+new Date();
        var ms=curr-(prevTime || curr);
        self.diff=ms;
        self.prev=prevTime;
        self.curr=curr;
        prevTime=curr;

        if ( null==self.useColors ) self.useColors=exports.useColors();// 是否开启带颜色输出
        if ( null==self.color && self.useColors ) self.color=selectColor();// 颜色码6|2|3|4|5|1

        var args=Array.prototype.slice.call(arguments);

        args[0]=exports.coerce(args[0]);// 处理错误(返回错误堆栈或错误消息)

        // exports.formatters.o方法,类型不是字符串时,使用util.inspect方法转化成字符串后输出
        if ( 'string'!==typeof args[0] ){
            args=['%o'].concat(args);
        }

        var index=0;

        // match匹配项,format括号内匹配项,没有匹配项将不执行回调函数
        args[0]=args[0].replace(/%([a-z%])/g, function(match,format){
            // %% 起始原样打印
            if ( match==='%%' ) return match;

            // %[a-z] 起始,且exports.formatters存在相应格式化函数,执行格式化、替换前两项后输出
            index++;
            var formatter=exports.formatters[format];
            if ( 'function'===typeof formatter ){
              var val=args[index];
              match=formatter.call(self, val);

              args.splice(index, 1);
              index--;
            }
            return match;
        });

        // 带色彩打印消息
        if ( 'function'===typeof exports.formatArgs ){
            args=exports.formatArgs.apply(self, args);
        }

        // enabled.log用户自定义打印方法; exports.log利用stream流打印消息
        var logFn=enabled.log || exports.log || console.log.bind(console);
        logFn.apply(self,args);
    }
    enabled.enabled=true;

    // 倘若namespace为待测试模块,fn引用enabled函数,否则引用disabled函数
    var fn=exports.enabled(namespace) ? enabled : disabled;

    fn.namespace=namespace;

    return fn;
}

// 字符串形式设置待测试以及忽略的模块,多个模块以空格分割,忽略的模块以"-"起始
// 将模块的正则式推入exports.names或exports.skips中
function enable(namespaces){
    exports.save(namespaces);// 更新process.env.DEBUG环境变量

    var split=(namespaces || '').split(/[\s,]+/);
    var len=split.length;

    for ( var i=0; i<len; i++ ){
        if (!split[i]) continue; // ignore empty strings
        namespaces=split[i].replace(/\*/g, '.*?');
        if (namespaces[0] === '-'){
            exports.skips.push(new RegExp('^'+namespaces.substr(1)+'$'));
        }else{
            exports.names.push(new RegExp('^'+namespaces+'$'));
        }
    }
}

// 没有清空exports.skips、exports.names忽略和待测试模块队列,函数的意义何在???
function disable() {
    exports.enable('');
}

// 待测试的模块返回真值,其余返回否,exports.skips需要忽略的模块
function enabled(name){
    var i,len;
    for ( i=0, len=exports.skips.length; i<len; i++ ){
        if ( exports.skips[i].test(name) ){
          return false;
        }
    }
    for ( i=0, len=exports.names.length; i<len; i++ ){
        if ( exports.names[i].test(name) ){
          return true;
        }
    }
    return false;
}

// 若为错误,返回错误的堆栈信息或错误消息,否则原样输出
function coerce(val){
  if ( val instanceof Error ) return val.stack || val.message;
  return val;
}

 

4.存疑:日志输出为文件,客户端使用

 

 

0
0
分享到:
评论

相关推荐

    debug模块

    "debug模块"通常指的是Python编程语言中的`debugger`模块,也被称为`pdb`(Python Debugger)。这个模块提供了一套完整的交互式源代码调试工具,帮助开发者追踪代码执行流程,查看变量值,设置断点等。 `pdb`模块...

    node.js中debug模块的简单介绍与使用

    总的来说,`debug`模块提供了一种高效且灵活的调试方式,它使得在开发阶段的调试工作变得轻松,同时在生产环境中保持代码的简洁和高效。通过合理利用这个模块,你可以更好地管理和理解你的Node.js应用,提高开发效率...

    Node.js利用debug模块打印出调试日志的方法

    用的比较多的是debug模块,比如express框架中就用到了。下文简单举几个例子进行说明。文中相关代码示例,可在这里找到。 备注:node在0.11.3版本也加入了util.debuglog()用于打印调试日志,使用方法跟debug模块...

    4g模块debug和资源文件.zip

    "4g模块debug和资源文件.zip"这个压缩包包含了帮助开发者解决Android 4G模块问题的多种资料,包括文档、配置文件和可能的源代码片段。下面我们将深入探讨其中涉及的关键知识点。 1. **Android 4G模块的调试(debug...

    一个debug工具的源代码

    本篇文章将基于提供的"一个debug工具的源代码"来探讨Win32平台下的调试工具及其源码解析,旨在帮助开发者更深入地理解和运用调试技术。 首先,我们要明白什么是调试工具。调试工具是一类软件,它允许程序员检查程序...

    乐玩模块8.10源码.rar

    《乐玩模块8.10源码》是一个包含多种编程技术与工具的资源包,主要涉及计算机编程中的图像处理、颜色识别、文字查找、API钩子、窗口与内存操作、DLL注入、进程管理以及多线程等核心概念。下面将对这些知识点进行详细...

    易语言简单提升自身权限模块源码

    易语言简单提升自身权限模块源码例程程序调用API函数RtlAdjustPrivilege提升自身的进程权限。本易语言源码例程属于易语言进阶教程。本源码是提升权限API的例程,遗憾的是没有比较详细的说明。资源作者:。资源下载:...

    GPS模块代码

    综上所述,这段代码展示了如何利用Arduino平台读取并解析GPS模块发出的NMEA 0183协议数据,并对其中的部分信息进行了简单的处理。这对于初学者了解GPS模块的工作原理以及如何在实际项目中应用GPS数据具有很好的参考...

    ARM典型模块的介绍

    Flash存储器是一种非易失性内存,常用于存储程序代码和关键数据。在ARM系统中,Flash通常作为启动存储介质,装载操作系统和应用程序。其主要特点包括: 1. **非易失性**:即使断电,存储的数据也不会丢失。 2. **...

    Unity3D重新封装Debug实现自主控制是否开启Debug输出

    在Unity中,我们可以创建C#类库项目,编译成DLL文件,然后导入到Unity工程中,以实现代码的复用和模块化。 项目的实现方式通常是这样的: 1. 创建一个新的C#类库项目,命名为Debugger,包含一个静态类,例如`...

    tcl-debug安装步骤

    安装完成后,可以通过在CYGWIN终端中输入`tclsh`进入TCL解释器,然后尝试导入tcldebug模块来验证安装是否成功: ```tcl package require tcldebug ``` 如果没有报错并且成功导入,那么TCL-debug已经安装并...

    debugfs例子程序

    首先,模块需要包含`&lt;linux/debugfs.h&gt;`头文件,然后调用`debugfs_create_*()`系列函数创建文件。例如,创建一个只读整数文件: ```c struct dentry *my_entry; my_entry = debugfs_create_u32("my_variable", S_...

    调试用的工具JSdebug

    JSdebug提供了多种调试功能,帮助开发者识别和修复代码中的问题。首先,它具有断点设置功能,允许你在特定行暂停代码执行,以便检查变量状态、调用堆栈和执行流程。这对于追踪代码逻辑和定位错误源非常有帮助。其次...

    常用Log模块设计源码

    四、LC-Log模块源码移植步骤 1. 阅读源码:理解模块的设计思想、实现方式以及提供的功能。 2. 引入库:在项目中引入LC-Log库,通常是添加相应的引用或导入语句。 3. 配置日志:设置日志级别、输出位置等参数,根据...

    ruby-debug-1.87.rar

    `ruby-debug-1.87`是一个强大的Ruby调试器,它允许开发者在代码运行时检查变量状态、设置断点、单步执行等,极大地提高了问题排查的效率。这个版本针对Ruby 1.8.7进行了优化,因此得名`ruby-debug-1.87`。 在`ruby-...

    riscv-debug-spec-0.11nov12 Riscv 调试文档

    10. **调试ROM和RAM**:调试模块可能包括调试ROM(DebugROM),其中包含启动时执行的代码;以及调试RAM(DebugRAM),用于存储运行时的调试数据。 11. **重置控制**:调试模块可能还涉及重置控制(ResetControl),...

    关于Pycharm无法debug问题的总结

    在Pycharm中,调试Python代码是一项非常重要的功能,它能帮助开发者找到并修复代码中的错误。然而,有时候可能会遇到Pycharm无法正常进行debug的情况,这通常表现为“pydev debugger: process XXXX is connecting”...

    OpenCV X64 Debug and Release

    - **Debug模式**:用于开发阶段,提供了丰富的调试信息,如符号表,便于定位代码中的错误。OpenCV的Debug库通常带有"D"后缀(如opencv_core_d.lib),并链接到调试版本的C++运行时库。 - **Release模式**:用于...

    debug资料.rar debug资料.rar debug资料.rar

    在编程工作中,debug是确保代码正确运行的关键步骤。这里,我们深入探讨一下debug相关的知识。 1. **什么是调试**: 调试是识别、定位和修复代码中错误的过程。这些错误可能是语法错误、逻辑错误或运行时错误。...

Global site tag (gtag.js) - Google Analytics