sendBeacon和log4js日志使用

“ 在很早的一篇文章中我提到过我们公司使用node作为中间件,其中node作为中间件很重要的一点就是作为日志使用,日志的打印是需要经过node,也就意味着请求或者响应时都需要经过node。有趣的一点是在一次做项目时看到前端请求node之后不经后端直接打印日志,这种情况也是很常见的一种,可以理解为此时node在做为后端,日志的作用在于方便线上出问题好排查以及定位点。”

温馨提示:看这篇文章是默认你会node的哟。

1. sendBeacon和log4js日志结合

window.navigator.sendBeacon和log4js在这里我就不介绍它们的作用了,如果还不是太了解的同学可以先去看看它们的介绍然后再来看这篇文章。在这里我使用的是expess框架,在学习之前我们先安装好express和log4js,执行代码npm install express log4js –save-dev。

  1. 首先处理前端,在这里我使用的是react,在页面中有一个button按钮用于模拟用户点击事件之后报错,然后上报到node端然后打印相关报错信息,在这里我写了一个很简单的代码例子(前端端口3000,node端口8888,在node端处理cors跨域),前端React代码如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import React from 'react';
    // 模拟用户操作错误请求,上报node打印日志
    const LogTest = () => {
    const ajaxLog = () => {
    const logData = {type: 'click', content: '点击事件报错'};
    const paramStr = JSON.stringify(logData);
    try {
    if (window.navigator.sendBeacon) {
    let ajaxData = new FormData(); // 其实就是form-data表单类型
    ajaxData.append('_logs', paramStr);
    window.navigator.sendBeacon('http://localhost:8888/log', ajaxData);
    }
    } catch (error) {
    console.error(error);
    }
    };
    return (
    <div>
    <button onClick={ajaxLog}>点击发送formData值</button>
    </div>
    );
    };
    export default LogTest;
  1. 由于是post请求因此需要下载body-parser来解析body,执行下载指令:npm install body-parser。还需要注意的一个坑是:上面我们提到React前端代码中通过sendBeacon传递的ajaxData是form-data表单类型的,而body-parser是处理不了这一类型的,因此req.body无法接收到数据,因此在这里我使用了一个multer中间件,它只会解析form设置为enctype=”multipart/form-data”表单,执行下载指令:npm install multer。node后端代码如下所示,
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    const express = require('express');
    const app = express();
    const bodyParser = require('body-parser');
    const log4js = require('log4js');
    const logger = log4js.getLogger('_log');
    const multer = require('multer')();

    //设置跨域访问
    app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    next();
    });
    // multer.none()表示只保留文本信息
    app.post('/log', multer.none(), (req, res) => {
    const _logs = req.body._logs;
    logger.level = 'info'; // 需要添加level,否则不会在终端打印相关日志内容
    logger.info('_LOGS', _logs);
    res.status(200).end();
    });

    app.listen(8888, () => {
    console.log('service start, port 8888');
    });

当我们去点击button按钮时会在终端打印出如下图所示内容,会发现事件点以及相关的重要提示都在日志中打印出来了。
点击button打印的日志内容
点击button打印的日志内容

  1. 这个时候已经成功一大半了,因为我们还需要将相关的日志存储到指定的文件中,方便后续在指定文件中查询时间端来查看相关日志信息,方便排错。我们只需要给log4js进行简单的配置即可,如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 添加日志管理(配置)
    log4js.configure({
    appenders: {
    // 这里的production名字可以随便取,只需要和categories下appenders中对应上即可
    production: {
    type: 'dateFile',
    // 会在当前文件夹下的logs文件夹中生成一个error.log文件,然后相关的信息会在error.log文件中生成
    filename: __dirname + '/logs/error.log',
    }
    },
    categories: {
    default: {
    appenders: ['production'],
    level: 'info',
    }
    }
    });
    比如我点击button三次,然后就会看见logs文件夹下面生成error.log文件,并且点击到文件中会看到三次的信息。如下图所示:
    点击button按钮在生成的error.log文件中打印的内容
    点击button按钮在生成的error.log文件中打印的内容图

到这里就教会大家如何利用sendBeacon和log4js结合来打印存储日志,日志的使用是十分重要的,方便后续在线上排查bug等功能。如果你觉得这篇文章对你有帮助记得连三哟,谢谢大家。