Nodejs 一个简单的日志module

Nodejs 一个简单的日志module

<br/> <br/>一个简单的日志module, 功能如下 <br/><ul> <br/> <li>时间显示</li> <br/> <li>调用log的文件名与行号显示</li> <br/> <li>不同日志级别使用不同颜色输出</li> <br/> <li>支持stdout输出的同时写入文件日志</li> <br/> <li>文件日志使用缓存以降低io次数</li> <br/></ul> <br/>使用示例 <br/><pre escaped=“true” lang=“javascript”>var log = require(’./log’), <br/> logWithoutFile = log.create(); <br/> logWithFile = log.create(log.WARNING, ‘my.log’), <br/> <br/>logWithoutFile.info(‘info msg’); <br/>logWithoutFile.debug(‘debug msg’); <br/>logWithoutFile.warning(‘warning msg’); <br/>logWithoutFile.error(‘error msg’); <br/>logWithoutFile.trace(‘trace msg’); <br/> <br/>logWithFile.info(‘info msg’); <br/>logWithFile.debug(‘debug msg’); <br/>logWithFile.warning(‘warning msg’); <br/>logWithFile.error(‘error msg’); <br/>logWithFile.trace(‘trace msg’);</pre> <br/>输出效果 <br/> <br/><img title=“cnode-log-demo.jpg” src=“http://static.data.taobaocdn.com/up/nodeclub/2011/03/cnode-log-demo.jpg” border=“0” alt=“cnode-log-demo” width=“579” height=“159” /> <br/> <br/>源码如下 <br/><pre escaped=“true” lang=“javascript”>var fs = require(‘fs’); <br/> <br/>var cwd = process.cwd() + ‘/’, <br/> INFO = 0; <br/> DEBUG = 1; <br/> WARNING = 2; <br/> ERROR = 3; <br/> TRACE = 4; <br/> INIT = 6; <br/> type = [‘INFO’, ‘DEBUG’, ‘WARNING’, ‘ERROR’, ‘TRACE’, ‘’, ‘LOG_INIT’]; <br/> colors = [38, 34, 35, 31, 32, 36, 33]; <br/> bufferSize = 20000; <br/> writeSize = 16384; <br/> <br/>exports.INFO = INFO; <br/>exports.DEBUG = DEBUG; <br/>exports.WARNING = WARNING; <br/>exports.ERROR = ERROR; <br/>exports.TRACE = TRACE; <br/> <br/>function getPos() { <br/> try { <br/> throw new Error(); <br/> } catch(e) { <br/> var pos = e.stack.split(’\n’)[4].split(’(’)[1].split(’)’)[0].split(’:’); <br/> return pos[0].replace(cwd, ‘’) + ‘:’ + pos[1]; <br/> } <br/>} <br/> <br/>function pad2(num) { <br/> return num > 9 ? num : ‘0’ + num; <br/>} <br/> <br/>function getTime() { <br/> var t = new Date(); <br/> return [t.getFullYear(), ‘-’, pad2(t.getMonth() + 1) , ‘-’, pad2(t.getDate()), ’ ‘, <br/> pad2(t.getHours()), ‘:’, pad2(t.getMinutes()), ‘:’, pad2(t.getSeconds())].join(’’); <br/>} <br/> <br/>function formatLog(log, color) { <br/> var tag = head = foot = ‘’; <br/> if (color) { <br/> head = ‘\x1B[’; <br/> foot = ‘\x1B[0m’; <br/> tag = colors[5]+‘m’; <br/> color = colors[log.type]+‘m’; <br/> } <br/> <br/>return [log.time, ’ [’, head, color, type[log.type], foot, ‘] [’, head, tag, log.pos, foot, ‘] ‘, log.msg].join(’’); <br/>} <br/> <br/>exports.create = function(level, file) { <br/> if (!level) { <br/> level = INFO; <br/> } <br/> if (file) { <br/> var buffer = new Buffer(bufferSize); <br/> var pos = 0; <br/> var fd = fs.openSync(file, ‘a’); <br/> process.on(‘exit’, function(){ <br/> fs.writeSync(fd, buffer, 0, pos, null); <br/> }) <br/> } <br/> function log(type, msg) { <br/> if (type < level){ <br/> return; <br/> } <br/> var log = {type:type, msg:msg, time:getTime(), pos:getPos()}; <br/> console.log(formatLog(log, true)); <br/> if (file) { <br/> if (pos >= writeSize) { <br/> fs.writeSync(fd, buffer, 0, pos, null); <br/> pos = 0; <br/> } <br/> pos += buffer.write(formatLog(log) + “\r\n”, pos); <br/> } <br/> } <br/> console.log(formatLog({type:INIT, pos:file, time:getTime(), msg: 'log init with level ’ + type[level]}, true)); <br/> return { <br/> info : function(msg) {log(INFO, msg);}, <br/> debug : function(msg) {log(DEBUG, msg);}, <br/> warning : function(msg) {log(WARNING, msg);}, <br/> error : function(msg) {log(ERROR, msg);}, <br/> trace : function(msg) {log(TRACE, msg);}, <br/> }; <br/>}</pre>


14 回复

好的,下面是关于“Node.js 一个简单的日志模块”的详细内容:

Node.js 一个简单的日志模块

功能概述

该模块提供了一个简单的日志功能,包含以下特性:

  • 显示时间戳
  • 显示调用 log 函数的文件名和行号
  • 不同的日志级别使用不同的颜色输出
  • 支持标准输出(stdout)的同时写入文件日志
  • 文件日志使用缓存以降低IO次数

使用示例

var log = require('./log');
var logWithoutFile = log.create();
var logWithFile = log.create(log.WARNING, 'my.log');

logWithoutFile.info('info msg');
logWithoutFile.debug('debug msg');
logWithoutFile.warning('warning msg');
logWithoutFile.error('error msg');
logWithoutFile.trace('trace msg');

logWithFile.info('info msg');
logWithFile.debug('debug msg');
logWithFile.warning('warning msg');
logWithFile.error('error msg');
logWithFile.trace('trace msg');

输出效果

cnode-log-demo

源码

var fs = require('fs');

var cwd = process.cwd() + '/';
var INFO = 0;
var DEBUG = 1;
var WARNING = 2;
var ERROR = 3;
var TRACE = 4;
var INIT = 6;

var type = ['INFO', 'DEBUG', 'WARNING', 'ERROR', 'TRACE', '', 'LOG_INIT'];
var colors = [38, 34, 35, 31, 32, 36, 33];
var bufferSize = 20000;
var writeSize = 16384;

exports.INFO = INFO;
exports.DEBUG = DEBUG;
exports.WARNING = WARNING;
exports.ERROR = ERROR;
exports.TRACE = TRACE;

function getPos() {
    try {
        throw new Error();
    } catch(e) {
        var pos = e.stack.split('\n')[4].split('(')[1].split(')')[0].split(':');
        return pos[0].replace(cwd, '') + ':' + pos[1];
    }
}

function pad2(num) {
    return num > 9 ? num : '0' + num;
}

function getTime() {
    var t = new Date();
    return [
        t.getFullYear(),
        '-', pad2(t.getMonth() + 1),
        '-', pad2(t.getDate()),
        ' ',
        pad2(t.getHours()),
        ':', pad2(t.getMinutes()),
        ':', pad2(t.getSeconds())
    ].join('');
}

function formatLog(log, color) {
    var tag = head = foot = '';
    if (color) {
        head = '\x1B[';
        foot = '\x1B[0m';
        tag = colors[5] + 'm';
        color = colors[log.type] + 'm';
    }

    return [
        log.time,
        ' [', head, color, type[log.type], foot, '] [', head, tag, log.pos, foot, '] ',
        log.msg
    ].join('');
}

exports.create = function(level, file) {
    if (!level) {
        level = INFO;
    }
    if (file) {
        var buffer = new Buffer(bufferSize);
        var pos = 0;
        var fd = fs.openSync(file, 'a');
        process.on('exit', function(){
            fs.writeSync(fd, buffer, 0, pos, null);
        });
    }

    function log(type, msg) {
        if (type < level) {
            return;
        }
        var log = {type: type, msg: msg, time: getTime(), pos: getPos()};
        console.log(formatLog(log, true));

        if (file) {
            if (pos >= writeSize) {
                fs.writeSync(fd, buffer, 0, pos, null);
                pos = 0;
            }
            pos += buffer.write(formatLog(log) + "\r\n", pos);
        }
    }

    console.log(formatLog({type: INIT, pos: file, time: getTime(), msg: 'log init with level ' + type[level]}, true));
    return {
        info: function(msg) { log(INFO, msg); },
        debug: function(msg) { log(DEBUG, msg); },
        warning: function(msg) { log(WARNING, msg); },
        error: function(msg) { log(ERROR, msg); },
        trace: function(msg) { log(TRACE, msg); },
    };
}

解释

  1. 定义常量:定义了不同日志级别的常量。
  2. 获取位置信息:通过抛出错误来获取调用者的文件名和行号。
  3. 格式化时间:将当前时间格式化为字符串。
  4. 格式化日志:根据日志级别添加颜色,并将日志信息格式化为字符串。
  5. 创建日志对象:创建一个日志对象,可以指定日志级别和日志文件。如果指定了日志文件,则会使用缓冲区来减少IO操作。

希望这些内容能帮助你理解和使用这个简单的日志模块。


实用小模块。buffer是细节,细节体现专业!

buffer的值设置得不专业,清爷迷糊了

偷了个懒而已…

长过3k的单条log毕竟是少数, 这样少做一次bytelength…可以提高点性能

那倒是。如果这个log非常重要,比如计费系统的log,就不能这么搞了

顶个~~不错的东东。。

一般来说,INFO和WARNING的日志级别不应该输出DEBUG级别的log <br/>all < debug < info < waring < error < trace

适当的去做一些偷懒来提高性能,对于某些情况还是必要的( 比如:log长度不可能超过3K)。

求server及client完整代码。

var pos = e.stack.split(’\n’)[4].split(’(’)[1].split(’)’)[0].split(’:’); <br/> <br/>有些情况下 是没有()会导致一个错误 <br/> <br/>某种情况我猜测是在不同的文件夹下的原因. <br/> <br/>这是我的修改 <br/> var pos = e.stack.split(/\n/)[4].split(‘at’)[1].replace(’)’, ‘’).replace(’(’, ‘’).replace(’ ', ‘’); <br/> pos = cwd + pos.split(":")[1]; <br/> return pos.replace("\/", ‘’);

你好 , 初学nodeJS <br/>我试了下…… 不知道为什么 <br/>info : function(msg) {log(INFO, msg);}, <br/>这个位置报语法错误% 求详解

如果是计费log,具体需要考虑那些东西呢。能给个思路吗?TX

为了实现一个简单的日志模块,我们可以根据上述描述编写一个Node.js模块。这个模块将提供时间戳、调用文件名和行号、不同日志级别的颜色输出、同时输出到标准输出和文件,并且通过缓存减少IO操作。

以下是根据上述描述编写的日志模块的简化版本:

// log.js
const fs = require('fs');
const util = require('util');

const INFO = 0;
const DEBUG = 1;
const WARNING = 2;
const ERROR = 3;
const TRACE = 4;

const type = ['INFO', 'DEBUG', 'WARNING', 'ERROR', 'TRACE'];
const colors = ['', '\x1b[34m', '\x1b[35m', '\x1b[31m', '\x1b[32m'];

function getPos() {
    try {
        throw new Error();
    } catch (e) {
        const stack = e.stack.split('\n')[4];
        const matches = stack.match(/\((.+):(\d+)\)$/);
        return matches ? `${matches[1]}:${matches[2]}` : '';
    }
}

function getTime() {
    const date = new Date();
    return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}

function formatLog(log, color) {
    const tag = colors[log.type];
    return `${tag}[${log.time}] [${log.pos}] ${log.msg}\x1b[0m`;
}

exports.create = function (level = INFO, file) {
    let buffer = '';
    let bufferSize = 1024 * 1024; // 1MB

    if (file) {
        const fd = fs.openSync(file, 'a');
        process.on('exit', () => {
            if (buffer) {
                fs.writeSync(fd, buffer);
                buffer = '';
            }
        });
    }

    function log(type, msg) {
        if (type < level) return;
        const logEntry = {
            type,
            msg,
            time: getTime(),
            pos: getPos()
        };
        console.log(formatLog(logEntry, colors[type]));
        if (file) {
            buffer += formatLog(logEntry) + '\n';
            if (buffer.length > bufferSize) {
                fs.writeSync(fd, buffer);
                buffer = '';
            }
        }
    }

    return {
        info: msg => log(INFO, msg),
        debug: msg => log(DEBUG, msg),
        warning: msg => log(WARNING, msg),
        error: msg => log(ERROR, msg),
        trace: msg => log(TRACE, msg),
    };
};

使用示例:

const log = require('./log');
const logWithoutFile = log.create();
const logWithFile = log.create(log.WARNING, 'app.log');

logWithoutFile.info('info message');
logWithoutFile.debug('debug message');
logWithoutFile.warning('warning message');
logWithoutFile.error('error message');
logWithoutFile.trace('trace message');

logWithFile.info('info message');
logWithFile.debug('debug message');
logWithFile.warning('warning message');
logWithFile.error('error message');
logWithFile.trace('trace message');

这个模块提供了时间戳、调用文件名和行号以及不同日志级别的颜色输出。它还支持将日志同时输出到标准输出和文件,并使用缓冲区来减少IO操作。

回到顶部