@sdc-monitor/demo
Version:
<div align="center"> <a href="#" target="_blank"> <img src="https://i.loli.net/2021/07/28/EvPwd4NjVH3tBfO.jpg" alt="mito-logo" height="90"> </a> <p>A Lightweight SDK For Monitor Web</p>
125 lines (119 loc) • 4.43 kB
text/typescript
import { BREADCRUMBCATEGORYS, BrowserBreadcrumbTypes, BrowserEventTypes, ErrorTypes, globalVar, HttpTypes, HTTP_CODE } from '@sdc-monitor/shared'
import {
getTimestamp,
replaceOld,
Severity,
_global,
variableTypeDetection,
on,
fromHttpStatus,
SpanStatus,
getLocationHref,
getRealPath
} from '@sdc-monitor/utils'
import { BasePluginType, HttpCollectedType, HttpTransformedType, MITOXMLHttpRequest, voidFun } from '@sdc-monitor/types'
import { BrowserClient } from '../browserClient'
import { addBreadcrumbInBrowser } from '../utils'
const xhrPlugin: BasePluginType<BrowserEventTypes, BrowserClient> = {
name: BrowserEventTypes.XHR,
monitor(notify) {
monitorXhr.call(this, notify)
},
transform(collectedData: HttpCollectedType) {
return httpTransform(collectedData)
},
consumer(transformedData: HttpTransformedType) {
httpTransformedDataConsumer.call(this, transformedData)
}
}
function monitorXhr(this: BrowserClient, notify: (eventName: BrowserEventTypes, data: any) => void) {
const { options, transport } = this
if (!('XMLHttpRequest' in _global)) {
return
}
const originalXhrProto = XMLHttpRequest.prototype
replaceOld(originalXhrProto, 'open', (originalOpen: voidFun): voidFun => {
return function (this: MITOXMLHttpRequest, ...args: any[]): void {
this.httpCollect = {
request: {
httpType: HttpTypes.XHR,
method: variableTypeDetection.isString(args[0]) ? args[0].toUpperCase() : args[0],
url: args[1]
},
response: {},
time: getTimestamp()
}
originalOpen.apply(this, args)
}
})
replaceOld(originalXhrProto, 'send', (originalSend: voidFun): voidFun => {
return function (this: MITOXMLHttpRequest, ...args: any[]): void {
const { request } = this.httpCollect
const { method, url } = request
options.setTraceId(url, (headerFieldName: string, traceId: string) => {
request.traceId = traceId
this.setRequestHeader(headerFieldName, traceId)
})
options.beforeAppAjaxSend && options.beforeAppAjaxSend({ method, url }, this)
on(this, 'loadend', function (this: MITOXMLHttpRequest) {
const isBlock = transport.isSelfDsn(url) || options.isFilterHttpUrl(url)
if (isBlock) return
const { responseType, response, status } = this
request.data = args[0]
const eTime = getTimestamp()
if (['', 'json', 'text'].indexOf(responseType) !== -1) {
this.httpCollect.response.data = typeof response === 'object' ? JSON.stringify(response) : response
}
this.httpCollect.response.status = status
this.httpCollect.elapsedTime = eTime - this.httpCollect.time
notify(BrowserEventTypes.XHR, this.httpCollect)
})
originalSend.apply(this, args)
}
})
}
export function httpTransform(httpCollectedData: HttpCollectedType): HttpTransformedType {
let message = ''
const {
request: { httpType, method, url },
response: { status },
elapsedTime
} = httpCollectedData
const name = `${httpType}--${method}`
if (status === 0) {
message =
elapsedTime <= globalVar.crossOriginThreshold ? 'http请求失败,失败原因:跨域限制或域名不存在' : 'http请求失败,失败原因:超时'
} else {
message = fromHttpStatus(status)
}
message = message === SpanStatus.Ok ? message : `${message} ${getRealPath(url)}`
return {
...httpCollectedData,
type: ErrorTypes.HTTP,
url: getLocationHref(),
level: Severity.Low,
message,
name
}
}
export function httpTransformedDataConsumer(this: BrowserClient, transformedData: HttpTransformedType) {
const type = transformedData.request.httpType === HttpTypes.FETCH ? BrowserBreadcrumbTypes.FETCH : BrowserBreadcrumbTypes.XHR
// time 是为了保持顺序,紧跟在点击事件后面
const {
response: { status },
time
} = transformedData
const isError = status === 0 || status === HTTP_CODE.BAD_REQUEST || status > HTTP_CODE.UNAUTHORIZED
addBreadcrumbInBrowser.call(this, transformedData, type, Severity.Info, { time })
if (isError) {
const breadcrumStack = this.breadcrumb.push({
type,
category: BREADCRUMBCATEGORYS.EXCEPTION,
data: transformedData,
level: Severity.Error,
time
})
this.transport.send(transformedData, breadcrumStack)
}
}
export default xhrPlugin