在使用源映射时如何将堆栈跟踪转换为字符串?

5
为了尽可能多地从我的错误中获取信息,我希望捕获堆栈跟踪,并在浏览器控制台中显示它,同时将其发送到外部记录器服务。
第一种情况很好用,当我使用console.error(myError)时,源映射文件会被浏览器正确解释,堆栈跟踪会显示相关的文件名。
然而,当我尝试将堆栈跟踪以字符串形式获取,使用(new Error()).stack时,文件名就不相关了。
My Error
at applicationError (http://localhost:3000/static/js/main.chunk.js:29259:
at http://localhost:3000/static/js/main.chunk.js:1624:
at onError (http://localhost:3000/static/js/0.chunk.js:82415:3)
at apiCall (http://localhost:3000/static/js/0.chunk.js:82449:12)
at async http://localhost:3000/static/js/main.chunk.js:26165:21
at async App.componentWillMount (http://localhost:3000/static/js/main.chunk.js:246:5)

我该如何获取“解析”堆栈跟踪,以便将相关信息发送到我的记录器?
我看过这些SO问题,但是,虽然问题乍一看似乎相关,但没有一个回答了我的问题:
1个回答

1
我曾经遇到过同样的问题,最后我找到了这个npm模块:https://www.npmjs.com/package/sourcemapped-stacktrace 自README中的示例:
try {
  // break something
  bork();
} catch (e) {
  // pass e.stack to window.mapStackTrace
  window.mapStackTrace(e.stack, function(mappedStack) {
    // do what you want with mappedStack here
    console.log(mappedStack.join("\n"));
  }, {
    filter: function (line) {
      // process only sources containing `spec.js`
      return /(spec\.js)/.test(line);
    }
  });
}

编辑: 我无法让上述的库正常工作,所以我自己创建了一个简单的实现。可能在一些边缘情况下会失败,并且可能不是最高效的,但对于我的需求来说已经足够了。
import {RawSourceMap, SourceMapConsumer} from 'source-map-js';

const sourceMaps: {[key: string] : RawSourceMap} = {};
async function getSourceMapFromUri(uri: string) {
  if (sourceMaps[uri] != undefined) {
    return sourceMaps[uri];
  }
  const uriQuery = new URL(uri).search;
  const currentScriptContent = await (await fetch(uri)).text();

  let mapUri = RegExp(/\/\/# sourceMappingURL=(.*)/).exec(currentScriptContent)[1];
  mapUri = new URL(mapUri, uri).href + uriQuery;

  const map = await (await fetch(mapUri)).json();

  sourceMaps[uri] = map;

  return map;
}

async function mapStackTrace(stack: string) {
  const stackLines = stack.split('\n');
  const mappedStack = [];

  for (const line of stackLines) {
    const match = RegExp(/(.*)(http:\/\/.*):(\d+):(\d+)/).exec(line);
    if (match == null) {
      mappedStack.push(line);
      continue;
    }

    const uri = match[2];
    const consumer = new SourceMapConsumer(await getSourceMapFromUri(uri));

    const originalPosition = consumer.originalPositionFor({
      line: parseInt(match[3]),
      column: parseInt(match[4]),
    });

    if (originalPosition.source == null || originalPosition.line == null || originalPosition.column == null) {
      mappedStack.push(line);
      continue;
    }

    mappedStack.push(`${originalPosition.source}:${originalPosition.line}:${originalPosition.column + 1}`);
  }

  return mappedStack.join('\n');
}

你也可以使用正常的source-map库,我不得不使用source-map-js,因为在我的特定环境中发生了一些错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接