源码分析Sentry用户行为记录实现过程

今日介绍前端异常监控利器Sentry平台中用户行为记录的源码实现过程,为什么使用Sentry,可以看以前的文章【
前端异常监控平台对比】。,在日常排查问题过程中,用户的行为操作记录能给到我们很大的参考及排查方向。目前市面上有的平台还不能记录用户的行为记录,Sentry提供了很好的行为记录查询,如下图所示。从用户跳转页面,到点击元素请求接口,发生异常,如图所示,极大可能是因为接口相应的数据没有达到预期导致页面发送错误,本文将探讨Sentry JS SDK中是如何记录用户的操作行为记录。,源码分析Sentry用户行为记录实现过程,SDK初始化时会调用
init方法,最终
init方法的
initAndBind 指向
getCurrentHub().bindClient(),这里调用了默认的集成
client.setupIntegrations(),最终指向
@sentry/core/integration.js,这里的 options 即 sdk 初始化时传入并处理后的 options。,setupIntegration 调用
setupOnce 初始化拦截,这里的
setupOnce 是每个集成功能都有的能力。,breadcrumbs面包屑的setupOnce函数,@sentry/broswer/integrations/breadcrumbs.js
setupOnce 函数,可以看到对console,dom事件,网络请求,页面变化都做了拦截处理。,addInstrumentationHandler 出自
@sentry/utils/instrument.js,最终调用了
instrument方法,此方法实现了每种拦截类型的具体捕获逻辑。,再看针对日志打印的具体拦截捕获回调函数,所有捕获的回调函数最终都会调用
getCurrentHub().addBreadcrumb 添加行为记录,只是不同类型的行为记录会传入不同的处理参数。,getCurrentHub().addBreadcrumb 最终调用于
@sentry/hub/scope.js,在这里增加了时间的记录,以及最大记录条数的处理,最终将行为记录保存在
this._breadcrumbs(Scope)数组中。,在控制台打印全局注入的
__SENTRY__对象可以在
hub 对象中的
_breadcrumbs 看到以下格式的数据。,源码分析Sentry用户行为记录实现过程,最终在发起异常上报时,通过调用
this.getStackTop()获取到当前
scope中的数据一起上报,这里的
this.getStackTop().scope 即包括上述的
_breadcrumbs 行为数据,除此之前还有
_user 用户信息,
_tags 标签数据,
_extra 额外数据等。,最终异常上报的数据格式,如下图所示。
源码分析Sentry用户行为记录实现过程,源码分析Sentry用户行为记录实现过程,整体源码分析就到这里了,Sentry是一款功能强大的前端异常监控平台,涉及的功能及数据分析很多,有兴趣的同学可以尝试看看,看我觉得有用记得点个赞再走吧,收藏起来说不定哪天就需要了。,整体源码分析就到这里了,Sentry是一款功能强大的前端异常监控平台,涉及的功能及数据分析很多,有兴趣的同学可以尝试看看,看我觉得有用记得点个赞再走吧,收藏起来说不定哪天就需要了。,

今日介绍前端异常监控利器Sentry平台中用户行为记录的源码实现过程,为什么使用Sentry,可以看以前的文章【前端异常监控平台对比】。

前言

在日常排查问题过程中,用户的行为操作记录能给到我们很大的参考及排查方向。目前市面上有的平台还不能记录用户的行为记录,Sentry提供了很好的行为记录查询,如下图所示。从用户跳转页面,到点击元素请求接口,发生异常,如图所示,极大可能是因为接口相应的数据没有达到预期导致页面发送错误,本文将探讨Sentry JS SDK中是如何记录用户的操作行为记录。

源码分析Sentry用户行为记录实现过程

源码实现

SDK初始化时会调用init方法,最终init方法的 initAndBind 指向 getCurrentHub().bindClient()

Hub.prototype.bindClient = function (client) {
    // 获取最后一个
    var top = this.getStackTop();
    // 把 new BrowerClient() 实例 绑定到top上
    top.client = client;
    if (client && client.setupIntegrations) {
        client.setupIntegrations();
    }
};

这里调用了默认的集成 client.setupIntegrations(),最终指向 @sentry/core/integration.js,这里的 options 即 sdk 初始化时传入并处理后的 options。

export function setupIntegrations(options) {
    var integrations = {};
    getIntegrationsToSetup(options).forEach(function (integration) {
        integrations[integration.name] = integration;
        setupIntegration(integration);
    });
    return integrations;
}

setupIntegration 调用 setupOnce 初始化拦截,这里的 setupOnce 是每个集成功能都有的能力。

export function setupIntegration(integration) {
    if (installedIntegrations.indexOf(integration.name) !== -1) {
        return;
    }
    integration.setupOnce(addGlobalEventProcessor, getCurrentHub);
    installedIntegrations.push(integration.name);
    logger.log("Integration installed: " + integration.name);
}

breadcrumbs面包屑的setupOnce函数

@sentry/broswer/integrations/breadcrumbs.jssetupOnce 函数,可以看到对console,dom事件,网络请求,页面变化都做了拦截处理。

Breadcrumbs.prototype.setupOnce = function () {
       var _this = this;
       if (this._options.console) {
           addInstrumentationHandler({
               callback: function () {
                   var args = [];
                   for (var _i = 0; _i < arguments.length; _i++) {
                       args[_i] = arguments[_i];
                   }
                   _this._consoleBreadcrumb.apply(_this, __spread(args));
               },
               type: 'console',
           });
       }
       if (this._options.dom) {
           addInstrumentationHandler({
               ...,
               type: 'dom',
           });
       }
       if (this._options.xhr) {
           addInstrumentationHandler({
               ..,
               type: 'xhr',
           });
       }
       if (this._options.fetch) {
           addInstrumentationHandler({
               ...,
               type: 'fetch',
           });
       }
       if (this._options.history) {
           addInstrumentationHandler({
               ...,
               type: 'history',
           });
       }
   };

addInstrumentationHandler 出自 @sentry/utils/instrument.js,最终调用了instrument方法,此方法实现了每种拦截类型的具体捕获逻辑。


function instrument(type) {
    if (instrumented[type]) {
        return;
    }
    instrumented[type] = true;
    switch (type) {
        case 'console':
            instrumentConsole();
            break;
        case 'dom':
            instrumentDOM();
            break;
        case 'xhr':
            instrumentXHR();
            break;
        case 'fetch':
            instrumentFetch();
            break;
        case 'history':
            instrumentHistory();
            break;
        case 'error':
            instrumentError();
            break;
        case 'unhandledrejection':
            instrumentUnhandledRejection();
            break;
        default:
            logger.warn('unknown instrumentation type:', type);
    }
}

再看针对日志打印的具体拦截捕获回调函数,所有捕获的回调函数最终都会调用 getCurrentHub().addBreadcrumb 添加行为记录,只是不同类型的行为记录会传入不同的处理参数。

Breadcrumbs.prototype._consoleBreadcrumb = function (handlerData) {
    var breadcrumb = {
        category: 'console',
        data: {
            arguments: handlerData.args,
            logger: 'console',
        },
        level: Severity.fromString(handlerData.level),
        message: safeJoin(handlerData.args, ' '),
    };
    if (handlerData.level === 'assert') {
        if (handlerData.args[0] === false) {
            breadcrumb.message = "Assertion failed: " + (safeJoin(handlerData.args.slice(1), ' ') || 'console.assert');
            breadcrumb.data.arguments = handlerData.args.slice(1);
        }
        else {
            // Don't capture a breadcrumb for passed assertions
            return;
        }
    }
    getCurrentHub().addBreadcrumb(breadcrumb, {
        input: handlerData.args,
        level: handlerData.level,
    });
}

getCurrentHub().addBreadcrumb 最终调用于 @sentry/hub/scope.js,在这里增加了时间的记录,以及最大记录条数的处理,最终将行为记录保存在 this._breadcrumbs(Scope)数组中。

Scope.prototype.addBreadcrumb = function (breadcrumb, maxBreadcrumbs) {
    var mergedBreadcrumb = __assign({ timestamp: dateTimestampInSeconds() }, breadcrumb);
    this._breadcrumbs =
        maxBreadcrumbs !== undefined && maxBreadcrumbs >= 0
            ? __spread(this._breadcrumbs, [mergedBreadcrumb]).slice(-maxBreadcrumbs)
            : __spread(this._breadcrumbs, [mergedBreadcrumb]);
    this._notifyScopeListeners();
    return this;
};

在控制台打印全局注入的__SENTRY__对象可以在 hub 对象中的 _breadcrumbs 看到以下格式的数据。

源码分析Sentry用户行为记录实现过程

最终在发起异常上报时,通过调用this.getStackTop()获取到当前scope中的数据一起上报,这里的 this.getStackTop().scope 即包括上述的 _breadcrumbs 行为数据,除此之前还有 _user 用户信息, _tags 标签数据, _extra 额外数据等。

Hub.prototype._invokeClient = function (method) {
    var _a;
    var args = [];
    for (var _i = 1; _i < arguments.length; _i++) {
        args[_i - 1] = arguments[_i];
    }
    var top = this.getStackTop();
    if (top && top.client && top.client[method]) {
        (_a = top.client)[method].apply(_a, __spread(args, [top.scope]));
    }
};

最终异常上报的数据格式,如下图所示。 源码分析Sentry用户行为记录实现过程

整体流程图

源码分析Sentry用户行为记录实现过程

最后

整体源码分析就到这里了,Sentry是一款功能强大的前端异常监控平台,涉及的功能及数据分析很多,有兴趣的同学可以尝试看看,看我觉得有用记得点个赞再走吧,收藏起来说不定哪天就需要了。

文章版权声明

 1 原创文章作者:Young,如若转载,请注明出处: https://www.52hwl.com/36654.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年7月15日 下午4:50
下一篇 2023年7月15日 下午4:50