You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不修改Node.js代码库原有函数的情况下为自定义函数添加执行前后日志?

如何在不修改Node.js代码库原有函数的情况下为自定义函数添加执行前后日志?

这需求太接地气了——不想动原有代码,也不想挨个给函数加包装,还得只给自己的代码加日志,用Babel插件绝对是最优解!我来给你一步步拆解实现方法:

核心思路

Babel可以在代码编译阶段修改抽象语法树(AST),自动给我们的函数注入日志代码,全程不用手动修改业务函数,还能通过配置轻松排除node_modules里的第三方代码。

第一步:编写自定义Babel插件

这个插件的作用就是遍历所有函数节点,在函数执行前插入「打印函数名+参数」的代码,在函数返回前插入「打印函数名+返回值」的代码。直接上代码:

module.exports = function({ types: t }) {
  return {
    visitor: {
      // 处理常规函数声明(比如function foo() {})
      FunctionDeclaration(path) {
        injectLogging(path, t);
      },
      // 处理函数表达式(比如const foo = function() {})
      FunctionExpression(path) {
        injectLogging(path, t);
      },
      // 处理箭头函数(比如const foo = () => {})
      ArrowFunctionExpression(path) {
        injectLogging(path, t);
      }
    }
  };
};

function injectLogging(path, t) {
  // 智能获取函数名,适配匿名函数、变量赋值、对象属性等场景
  let functionName = '匿名函数';
  if (path.node.id) {
    functionName = path.node.id.name;
  } else if (path.parentPath.isVariableDeclarator()) {
    functionName = path.parentPath.node.id.name;
  } else if (path.parentPath.isAssignmentExpression()) {
    if (t.isIdentifier(path.parentPath.node.left.property)) {
      functionName = path.parentPath.node.left.property.name;
    }
  }

  // 1. 插入执行前的日志:打印函数名和传入的所有参数
  const beforeLog = t.expressionStatement(
    t.callExpression(
      t.memberExpression(t.identifier('console'), t.identifier('log')),
      [
        t.stringLiteral(`[执行前] 函数: ${functionName}`),
        t.stringLiteral('参数:'),
        t.spreadElement(t.identifier('arguments'))
      ]
    )
  );

  // 2. 处理函数体,插入执行后的日志
  if (t.isBlockStatement(path.node.body)) {
    // 把前置日志插到函数体最开头
    path.node.body.body.unshift(beforeLog);

    // 遍历所有return语句,在return前打返回值日志
    path.traverse({
      ReturnStatement(returnPath) {
        const returnValue = returnPath.node.argument;
        const afterLog = t.expressionStatement(
          t.callExpression(
            t.memberExpression(t.identifier('console'), t.identifier('log')),
            [
              t.stringLiteral(`[执行后] 函数: ${functionName}`),
              t.stringLiteral('返回值:'),
              returnValue || t.identifier('undefined')
            ]
          )
        );
        returnPath.insertBefore(afterLog);
      }
    });

    // 如果函数没有return语句,在函数末尾打返回undefined的日志
    const hasReturn = path.node.body.body.some(node => t.isReturnStatement(node));
    if (!hasReturn) {
      const afterLog = t.expressionStatement(
        t.callExpression(
          t.memberExpression(t.identifier('console'), t.identifier('log')),
          [
            t.stringLiteral(`[执行后] 函数: ${functionName}`),
            t.stringLiteral('返回值:'),
            t.identifier('undefined')
          ]
        )
      );
      path.node.body.body.push(afterLog);
    }
  } else {
    // 处理箭头函数的表达式体(比如const foo = () => 123),先转成带{}的块级语句
    const originalBody = path.node.body;
    path.node.body = t.blockStatement([
      beforeLog,
      t.returnStatement(originalBody),
      t.expressionStatement(
        t.callExpression(
          t.memberExpression(t.identifier('console'), t.identifier('log')),
          [
            t.stringLiteral(`[执行后] 函数: ${functionName}`),
            t.stringLiteral('返回值:'),
            originalBody
          ]
        )
      )
    ]);
  }
}

第二步:配置Babel

在项目根目录创建babel.config.js,把刚才的插件加进去,同时关键要排除node_modules:

module.exports = {
  presets: ['@babel/preset-env'], // 按需添加你的preset,比如React项目加@babel/preset-react
  plugins: [require('./path/to/your/log-plugin.js')], // 替换成你的插件路径
  exclude: /node_modules/ // 重中之重!不处理第三方模块的函数
};

第三步:运行代码

可以直接用babel-node运行你的代码,或者编译后运行:

  • 直接运行:
npx babel-node src/your-entry-file.js
  • 或者在package.json里配置scripts:
"scripts": {
  "dev": "babel-node src/index.js",
  "build": "babel src --out-dir dist"
}

然后执行npm run dev就能看到日志了!

额外说明

  • 这个插件适配常规函数、箭头函数、匿名函数、对象方法等绝大多数场景,函数名识别也比较精准;
  • 异步函数(async/await)也能完美处理,因为日志是注入到函数体内部的;
  • 如果不想给某些函数加日志,可以在插件里加判断逻辑(比如给函数加特定注释,插件识别后跳过)。

备注:内容来源于stack exchange,提问作者Meir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 10:59:30