import { Breadcrumb , BreadcrumbHint , Client , Event , EventHint , Hub as HubInterface , Integration , IntegrationClass , Span , SpanContext , Transaction , TransactionContext } from '../types' ; import { consoleSandbox , getGlobalObject , logger , timestampWithMs , uuid4 } from '../utils' ; import { Carrier , Layer } from './interfaces' ; import { Scope } from './scope' ; /**
 * 默认添加event最大长度的面包屑。能被覆盖
 * with  Options . maxBreadcrumbs .
  const DEFAULT_BREADCRUMBS = 100 ; /**
 * 最大的面包屑长度
 */ const MAX_BREADCRUMBS = 100 ; inheritDoc export class Hub implements HubInterface { /** 包含client和scope的实例的堆栈 */ private readonly _stack : Layer [ ] = [ ] ; /** 最后上报event的uuid4 */ private _lastEventId ? : string ; param client param scope public constructor ( client ? , scope = new Scope ( ) ) { this . _stack . push ( { client , scope } ) ; this . bindClient ( client ) ; } /**
     * 绑定client到_stack
     */ public bindClient ( client ? ) { const top = this . getStackTop ( ) ; top . client = client ; if ( client && client . setupIntegrations ) { client . setupIntegrations ( ) ; } } /**
     * scope入栈
     */ public pushScope ( ) { const stack = this . getStack ( ) ; const parentScope = stack . length > 0 ? stack [ stack . length - 1 ] . scope : undefined ; const scope = Scope . clone ( parentScope ) ; this . getStack ( ) . push ( { client : this . getClient ( ) , scope , } ) ; return scope ; } /**
     * scope出栈
     */ public popScope ( ) { return this . getStack ( ) . pop ( ) !== undefined ; } /**
     * 接受scope匿名回调,复制scope不会改变挂载在全局的scope实例
     */ public withScope ( callback ) { const scope = this . pushScope ( ) ; try { callback ( scope ) ; } finally { this . popScope ( ) ; } } /** 返回顶层的client实例 */ public getClient < C extends Client > ( ) { return this . getStackTop ( ) . client as C ; } /** 返回顶层的scope实例 */ public getScope ( ) { return this . getStackTop ( ) . scope ; } /** 返回_stack  */ public getStack ( ) { return this . _stack ; } /** 返回堆栈最后的stack */ public getStackTop ( ) { return this . _stack [ this . _stack . length - 1 ] ; } /**
     * captureException上报
     */ public captureException ( exception , hint ? ) { const eventId = ( this . _lastEventId = uuid4 ( ) ) ; let finalHint = hint ; if ( ! hint ) { let syntheticException ; try { throw new Error ( 'Beidou syntheticException' ) ; } catch ( exception ) { syntheticException = exception as Error ; } finalHint = { originalException : exception , syntheticException , } ; } this . _invokeClient ( 'captureException' , exception , { timestamp : Date . now ( ) , event_id : eventId , ... finalHint , } ) ; return eventId ; } /**
     * 一次event上报
     */ public captureEvent ( event , hint ? ) { const eventId = ( this . _lastEventId = uuid4 ( ) ) ; this . _invokeClient ( 'captureEvent' , event , { timestamp : Date . now ( ) , event_id : eventId , ... hint , } ) ; return eventId ; } /**
     * 获取eventId
     */ public lastEventId ( ) { return this . _lastEventId ; } inheritDoc public addBreadcrumb ( breadcrumb , hint ? ) { const top = this . getStackTop ( ) ; if ( ! top . scope || ! top . client ) { return ; } const { beforeBreadcrumb = null , maxBreadcrumbs = DEFAULT_BREADCRUMBS } = ( top . client . getOptions && top . client . getOptions ( ) ) || { } ; if ( maxBreadcrumbs <= 0 ) { return ; } const timestamp = timestampWithMs ( ) ; const mergedBreadcrumb = { timestamp , ... breadcrumb } ; const finalBreadcrumb = beforeBreadcrumb ? ( consoleSandbox ( ( ) => beforeBreadcrumb ( mergedBreadcrumb , hint ) ) as Breadcrumb | null ) : mergedBreadcrumb ; if ( finalBreadcrumb === null ) { return ; } top . scope . addBreadcrumb ( finalBreadcrumb , Math . min ( maxBreadcrumbs , MAX_BREADCRUMBS ) ) ; } public setContext ( name , context ) { const top = this . getStackTop ( ) ; if ( ! top . scope ) { return ; } top . scope . setContext ( name , context ) ; } /**
     * 接受scope的处理回调， 接受scope匿名回调, 会改变挂载在全局的scope实例
     */ public configureScope ( callback ) { const top = this . getStackTop ( ) ; if ( top . scope && top . client ) { callback ( top . scope ) ; } } /**
     * 判断integration是否在初始化被注入
     */ public getIntegration < T extends Integration > ( integration ) { const client = this . getClient ( ) ; if ( ! client ) { return null ; } try { return client . getIntegration ( integration ) ; } catch ( _oO ) { logger . warn ( `Cannot retrieve integration ${ integration . id } from the current Hub` ) ; return null ; } } /**
     * 性能处理, 待确认
     */ public startSpan ( context ) { return this . _callExtensionMethod ( 'startSpan' , context ) ; } /**
     * 性能处理, 待确认
     */ public startTransaction ( context ) { return this . _callExtensionMethod ( 'startTransaction' , context ) ; } param method param args private _invokeClient < M extends keyof Client > ( method , ... args ) { const top = this . getStackTop ( ) ; if ( top && top . client && top . client [ method ] ) { ( top . client as any ) [ method ] ( ... args , top . scope ) ; } } /**
     * 全局global extension方法调用
     */ private _callExtensionMethod < T > ( method , ... args ) { const carrier = getMainCarrier ( ) ; const beidou = carrier . __BEIDOU__ ; if ( beidou && beidou . extensions && typeof beidou . extensions [ method ] === 'function' ) { return beidou . extensions [ method ] . apply ( this , args ) ; } logger . warn ( `Extension method ${ method } couldn't be found, doing nothing.` ) ; } } /** 返回挂载全局的垫片属性. */ export function getMainCarrier ( ) { const carrier = getGlobalObject ( ) ; carrier . __BEIDOU__ = carrier . __BEIDOU__ || { extensions : { } , hub : undefined , } ; return carrier ; } /**
 * 返回挂载的hub实例
 */ export function getCurrentHub ( ) { const registry = getMainCarrier ( ) ; if ( ! hasHubOnCarrier ( registry ) ) { setHubOnCarrier ( registry , new Hub ( ) ) ; } return getHubFromCarrier ( registry ) ; } param carrier function hasHubOnCarrier ( carrier ) { if ( carrier && carrier . __BEIDOU__ && carrier . __BEIDOU__ . hub ) { return true ; } return false ; } param carrier hidden export function getHubFromCarrier ( carrier ) { if ( carrier && carrier . __BEIDOU__ && carrier . __BEIDOU__ . hub ) { return carrier . __BEIDOU__ . hub ; } carrier . __BEIDOU__ = carrier . __BEIDOU__ || { } ; carrier . __BEIDOU__ . hub = new Hub ( ) ; return carrier . __BEIDOU__ . hub ; } param carrier param hub export function setHubOnCarrier ( carrier , hub ) { if ( ! carrier ) { return false ; } carrier . __BEIDOU__ = carrier . __BEIDOU__ || { } ; carrier . __BEIDOU__ . hub = hub ; return true ; }