{"version":3,"sources":["../../../packages/core/performance/performance-profile.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAKjC,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAqB5E;;GAEG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,MAAM,CAAC,WAAW,CAAwB;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAE5C,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,8BAA8B,CAAiC;IACvE,OAAO,CAAC,8BAA8B,CAAiC;IACvE,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmC;IAC3D,OAAO,CAAC,oCAAoC,CAAuC;IAEnF;;OAEG;IACH,WAAkB,OAAO,IAAI,kBAAkB,CAO9C;IAED,WAAkB,QAAQ,IAAI,0BAA0B,CAEvD;IAED;;OAEG;WACW,kBAAkB,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAYhC;;OAEG;WACW,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAW3C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAoBpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAoB7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAoB/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAmB1B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAiBrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAiB9B,OAAO,CAAC,MAAM,CAAC,aAAa;IA0B5B,OAAO,CAAC,MAAM,CAAC,MAAM;IAcrB,OAAO,CAAC,MAAM,CAAC,QAAQ;IA2EvB,OAAO,CAAC,MAAM,CAAC,UAAU;IAelB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAKtB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAK9B,OAAO,CAAC,uBAAuB;IAiBxB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IA4C3B,cAAc,IAAI,IAAI;IA0B7B,OAAO,CAAC,GAAG;IAwBX,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,YAAY;IAmEpB,OAAO,CAAC,wBAAwB;IAwChC,OAAO,CAAC,iBAAiB;IA+CzB,OAAO,CAAC,yBAAyB;CAgBpC","file":"performance-profile.d.ts","sourcesContent":["import { of, Subscription, throwError } from 'rxjs';\r\nimport { AjaxError, AjaxRequest, AjaxResponse } from 'rxjs/ajax';\r\nimport { filter, map, take } from 'rxjs/operators';\r\nimport { CimResultFormat, CimStream, CimStreamMonitorSetContext, CimStreamOptions, CimStreamRequestData } from '../data/cim-stream';\r\nimport { Http } from '../data/http';\r\nimport { Net } from '../data/net';\r\nimport { PowerShellCommand } from '../data/powershell';\r\nimport { PowerShellStream, PowerShellStreamMonitorSetContext, PowerShellStreamOptions } from '../data/powershell-stream';\r\nimport { WebsocketStreamDataRequestState } from '../data/websocket-stream';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { RpcObservablePerformanceClient } from '../rpc/performance/rpc-observable-performance-client';\r\nimport { RpcObservablePerformanceConfigClient } from '../rpc/performance/rpc-observable-performance-config-client';\r\nimport { RpcObservablePerformanceServer } from '../rpc/performance/rpc-observable-performance-server';\r\nimport { Rpc } from '../rpc/rpc';\r\nimport {\r\n    PerformanceProfileData, PerformanceProfileDataCim, PerformanceProfileDataPowerShell, PerformanceProfileXhrFetch\r\n} from './performance-profile-data';\r\nimport { PerformanceProfileDataType } from './performance-profile-data-type';\r\nimport { PerformanceProfileDatabase } from './performance-profile-database';\r\nimport { PerformanceProfileRecord } from './performance-profile-record';\r\n\r\ninterface PowerShellStreamContext {\r\n    id: number;\r\n    start: number;\r\n    progressStart: number;\r\n    progressEnd?: number;\r\n    count: number;\r\n    itemCount: number;\r\n}\r\n\r\ninterface CimStreamContext {\r\n    id: number;\r\n    start: number;\r\n    progressStart: number;\r\n    progressEnd?: number;\r\n    count: number;\r\n    itemCount: number;\r\n}\r\n\r\n/**\r\n * Performance measurement class.\r\n */\r\nexport class PerformanceProfile {\r\n    private static monitorName = 'PerformanceProfile';\r\n    private static instance: PerformanceProfile;\r\n\r\n    private database: PerformanceProfileDatabase = null;\r\n    private rpc: Rpc;\r\n    private rpcObservablePerformanceClient: RpcObservablePerformanceClient;\r\n    private rpcObservablePerformanceServer: RpcObservablePerformanceServer;\r\n    private subscription: Subscription;\r\n    private moduleVersionMap: { [index: string]: string } = {};\r\n    private rpcObservablePerformanceConfigClient: RpcObservablePerformanceConfigClient;\r\n\r\n    /**\r\n     * Gets the current PerformanceProfile instance.\r\n     */\r\n    public static get current(): PerformanceProfile {\r\n        if (PerformanceProfile.instance) {\r\n            return PerformanceProfile.instance;\r\n        }\r\n\r\n        PerformanceProfile.instance = new PerformanceProfile();\r\n        return PerformanceProfile.instance;\r\n    }\r\n\r\n    public static get database(): PerformanceProfileDatabase {\r\n        return PerformanceProfile.current.database;\r\n    }\r\n\r\n    /**\r\n     * Record Route navigation performance measurement.\r\n     */\r\n    public static logRouteNavigation(\r\n        source: string,\r\n        start: number,\r\n        end: number,\r\n        url: string,\r\n        target?: string,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start,\r\n            end,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.RouteNavigation,\r\n            routeNavigation: { url, target }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record Null packet.\r\n     */\r\n    public static logNull(source: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start: 0,\r\n            end: 0,\r\n            errorMessage: null,\r\n            type: PerformanceProfileDataType.Null\r\n        };\r\n        PerformanceProfile.current.logAnyway(data);\r\n    }\r\n\r\n    /**\r\n     * Record XHR or Fetch performance measurement for PowerShell.\r\n     */\r\n    private static logXhrFetchPowerShell(\r\n        source: string,\r\n        start: number,\r\n        end: number,\r\n        url: string,\r\n        method: string,\r\n        status: number,\r\n        powershell: PerformanceProfileDataPowerShell,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start,\r\n            end,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.XhrFetch,\r\n            xhrFetch: { url, method, status, powershell }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record XHR or Fetch performance measurement for CIM.\r\n     */\r\n    private static logXhrFetchCim(\r\n        source: string,\r\n        start: number,\r\n        end: number,\r\n        url: string,\r\n        method: string,\r\n        status: number,\r\n        cim: PerformanceProfileDataCim,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start,\r\n            end,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.XhrFetch,\r\n            xhrFetch: { url, method, status, cim }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record XHR or Fetch performance measurement for Batch.\r\n     */\r\n    private static logXhrFetchBatch(\r\n        source: string,\r\n        start: number,\r\n        end: number,\r\n        url: string,\r\n        method: string,\r\n        status: number,\r\n        batch: PerformanceProfileXhrFetch[],\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start,\r\n            end,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.XhrFetch,\r\n            xhrFetch: { url, method, status, batch }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record XHR or Fetch performance measurement for general.\r\n     */\r\n    private static logXhrFetch(\r\n        source: string,\r\n        start: number,\r\n        end: number,\r\n        url: string,\r\n        method: string,\r\n        status: number,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start,\r\n            end,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.XhrFetch,\r\n            xhrFetch: { url, method, status }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record WebSocket performance measurement.\r\n     */\r\n    private static logWebSocketPowerShell(\r\n        source: string,\r\n        nodeName: string,\r\n        command: string,\r\n        context: PowerShellStreamContext,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start: context.progressStart,\r\n            end: context.progressEnd,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.WebSocket,\r\n            webSocket: { nodeName, id: context.id, count: context.count, itemCount: context.itemCount, powershell: { command } }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    /**\r\n     * Record WebSocket performance measurement.\r\n     */\r\n    private static logWebSocketCim(\r\n        source: string,\r\n        nodeName: string,\r\n        cim: CimStreamRequestData,\r\n        context: CimStreamContext,\r\n        errorMessage?: string): void {\r\n        const data: PerformanceProfileData = {\r\n            source,\r\n            start: context.progressStart,\r\n            end: context.progressEnd,\r\n            errorMessage,\r\n            type: PerformanceProfileDataType.WebSocket,\r\n            webSocket: { nodeName, id: context.id, count: context.count, itemCount: context.itemCount, cim }\r\n        };\r\n        PerformanceProfile.current.log(data);\r\n    }\r\n\r\n    private static powershellApi(\r\n        url: string,\r\n        body: string,\r\n        response: { completed?: string, sessionId?: string; properties?: { completed: string; sessionId: string; }; }): PerformanceProfileDataPowerShell {\r\n        const powershell: { command?: string; sessionId?: string; completed?: string } = {};\r\n        if (body && body.indexOf('\\\"properties\\\"') > 0) {\r\n            powershell.command = PerformanceProfile.getBetween(body, ',\\\"command\\\":\\\"', '\\\",\\\"')\r\n                || PerformanceProfile.getBetween(body, '\\\"script\\\":\\\"##', '##:');\r\n        }\r\n\r\n        powershell.completed = response && response.completed;\r\n        if (!powershell.completed) {\r\n            powershell.completed = response && response.properties && response.properties.completed;\r\n        }\r\n\r\n        powershell.sessionId = response && response.sessionId;\r\n        if (!powershell.sessionId) {\r\n            powershell.sessionId = response && response.properties && response.properties.sessionId;\r\n            if (!powershell.sessionId) {\r\n                powershell.sessionId = PerformanceProfile.getBetween(url, '/pssessions/', '?');\r\n            }\r\n        }\r\n\r\n        return powershell;\r\n    }\r\n\r\n    private static cimApi(url: string, body: string): PerformanceProfileDataCim {\r\n        if (url.indexOf('/features/cim/query') > 0 || url.indexOf('/services/WinREST/CIM/query') > 0) {\r\n            try {\r\n                return JSON.parse(body);\r\n            } catch {\r\n                return null;\r\n            }\r\n        }\r\n\r\n        const namespaceName = PerformanceProfile.getBetween(url, '/namespaces/', '/classes/');\r\n        const className = PerformanceProfile.getBetween(url, '/classes/', '/instances');\r\n        return { namespace: namespaceName, className: className };\r\n    }\r\n\r\n    private static batchApi(body: string, response: string): PerformanceProfileXhrFetch[] {\r\n        const delimiter = '\\x0d\\x0a';\r\n        const batch: PerformanceProfileXhrFetch[] = [];\r\n        let last = body.indexOf(delimiter);\r\n        let separator = body.substring(0, last + 2);\r\n        const bodySegments = body.split(separator);\r\n        last = response.indexOf(delimiter);\r\n        separator = response.substring(0, last + 2);\r\n        const responseSegments = response.split(separator);\r\n        if (bodySegments.length === responseSegments.length && bodySegments.length > 1) {\r\n            let batchMethod: string;\r\n            let batchUrl: string;\r\n            let batchBody: string;\r\n            let batchStatus: number;\r\n            let batchResponse: any;\r\n            for (let i = 1; i < bodySegments.length; i++) {\r\n                const bodySegment = bodySegments[i];\r\n                const responseSegment = responseSegments[i];\r\n                const bodySegmentLines = bodySegment.split(delimiter);\r\n                let emptyLines = 0;\r\n                for (let j = 0; j < bodySegmentLines.length; j++) {\r\n                    const line = bodySegmentLines[j];\r\n                    if (line.length > 0) {\r\n                        if (emptyLines === 1 && !batchUrl) {\r\n                            // reached header segment.\r\n                            const query = line.split(' ');\r\n                            batchMethod = query[0];\r\n                            batchUrl = query[1];\r\n                        } else if (emptyLines >= 2 && !batchBody) {\r\n                            batchBody = line;\r\n                        }\r\n                    } else {\r\n                        emptyLines++;\r\n                    }\r\n                }\r\n\r\n                emptyLines = 0;\r\n                const responseSegmentLines = responseSegment.split(delimiter);\r\n                for (let j = 0; j < responseSegmentLines.length; j++) {\r\n                    const line = responseSegmentLines[j];\r\n                    if (line.length > 0) {\r\n                        if (emptyLines === 1 && !batchStatus) {\r\n                            // reached header segment.\r\n                            const query = line.split(' ');\r\n                            batchStatus = Number(query[1]);\r\n                        } else if (emptyLines >= 2 && !batchResponse) {\r\n                            try {\r\n                                batchResponse = JSON.parse(line);\r\n                            } catch {\r\n                                batchResponse = {};\r\n                            }\r\n                        }\r\n                    } else {\r\n                        emptyLines++;\r\n                    }\r\n                }\r\n\r\n                const batchItem: PerformanceProfileXhrFetch = {\r\n                    url: batchUrl,\r\n                    status: batchStatus,\r\n                    method: batchMethod\r\n                };\r\n                if (batchUrl.indexOf('/features/powershellApi/') > 0 || batchUrl.indexOf('/services/WinREST/PowerShell/') > 0) {\r\n                    batchItem.powershell = PerformanceProfile.powershellApi(batchUrl, batchBody, batchResponse);\r\n                } else if (batchUrl.includes('/features/cim/query') || batchUrl.includes('/services/WinREST/CIM/')) {\r\n                    batchItem.cim = PerformanceProfile.cimApi(batchUrl, batchBody);\r\n                }\r\n\r\n                batch.push(batchItem);\r\n            }\r\n        }\r\n\r\n        return batch;\r\n    }\r\n\r\n    private static getBetween(source: string, begin: string, end: string): string {\r\n        let index0 = source.indexOf(begin);\r\n        if (index0 < 0) {\r\n            return null;\r\n        }\r\n\r\n        index0 += begin.length;\r\n        const index1 = source.indexOf(end, index0);\r\n        if (index1 < 0) {\r\n            return null;\r\n        }\r\n\r\n        return source.substring(index0, index1);\r\n    }\r\n\r\n    public enable(rpc: Rpc): void {\r\n        MsftSme.setPerformanceProfile(true);\r\n        this.registerRpc(rpc);\r\n    }\r\n\r\n    public disable(rpc: Rpc): void {\r\n        MsftSme.setPerformanceProfile(false);\r\n        this.registerRpc(rpc);\r\n    }\r\n\r\n    private checkPerformanceProfile(): boolean {\r\n        if (!MsftSme.getPerformanceProfile()) {\r\n            if (this.database) {\r\n                this.database.close();\r\n                this.database = null;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        if (!this.database) {\r\n            this.database = new PerformanceProfileDatabase();\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    public registerRpc(rpc: Rpc): void {\r\n        if (!this.rpc) {\r\n            this.rpc = rpc;\r\n            if (MsftSme.isShell()) {\r\n                this.subscription = rpc.stateChanged\r\n                    .pipe(\r\n                        filter(active => active),\r\n                        take(1))\r\n                    .subscribe(() => {\r\n                        this.rpcObservablePerformanceConfigClient = new RpcObservablePerformanceConfigClient(this.rpc);\r\n                        this.rpcObservablePerformanceServer = new RpcObservablePerformanceServer(rpc);\r\n                        this.rpcObservablePerformanceServer.register(\r\n                            request => {\r\n                                if (request.type === PerformanceProfileDataType.Null) {\r\n                                    // The packet is null packet and retain only the version data.\r\n                                    if (request.sourceVersion === '0.2.0') {\r\n                                        // this version can support config command when on/off switch was used.\r\n                                        this.moduleVersionMap[request.sourceName] = request.sourceVersion;\r\n                                    }\r\n\r\n                                    return of(null);\r\n                                }\r\n\r\n                                if (!this.checkPerformanceProfile()) {\r\n                                    return of(null);\r\n                                }\r\n\r\n                                return this.database.write(request).pipe(map(() => null));\r\n                            });\r\n                    });\r\n            } else {\r\n                this.subscription = rpc.stateChanged\r\n                    .pipe(\r\n                        filter(active => active),\r\n                        take(1))\r\n                    .subscribe(() => {\r\n                        this.rpcObservablePerformanceClient = new RpcObservablePerformanceClient(rpc);\r\n                    });\r\n            }\r\n        }\r\n\r\n        this.updateMonitors();\r\n    }\r\n\r\n    public updateMonitors(): void {\r\n        const enabled = this.checkPerformanceProfile();\r\n        if (this.rpcObservablePerformanceConfigClient) {\r\n            // enable/disable the performance profile data collection to current modules.\r\n            // but these must be version 0.2.0.\r\n            const items = this.rpc.rpcManager.getCurrentRpcOutbound();\r\n            if (items) {\r\n                for (const item of items) {\r\n                    if (this.moduleVersionMap[item.name]) {\r\n                        this.rpcObservablePerformanceConfigClient.config({ enabled }, item).subscribe();\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        if (enabled) {\r\n            this.registerHttp();\r\n            this.registerPowerShellStream();\r\n            this.registerCimStream();\r\n        } else {\r\n            Http.unregisterMonitors(PerformanceProfile.monitorName);\r\n            PowerShellStream.unregisterMonitors(PerformanceProfile.monitorName);\r\n            CimStream.unregisterMonitors(PerformanceProfile.monitorName);\r\n        }\r\n    }\r\n\r\n    private log(message: PerformanceProfileData): void {\r\n        if (!this.checkPerformanceProfile()) {\r\n            return;\r\n        }\r\n\r\n        const self = MsftSme.self();\r\n        const record: PerformanceProfileRecord = {\r\n            ...message,\r\n            ...{ sessionId: self.Init.sessionId, timestamp: Date.now(), moduleName: self.Init.moduleName }\r\n        };\r\n\r\n        if (!record.errorMessage) {\r\n            delete record['errorMessage'];\r\n        }\r\n\r\n        if (this.rpc && this.rpc.stateActive && this.rpcObservablePerformanceClient) {\r\n            // send to shell.\r\n            this.rpcObservablePerformanceClient.log(record).subscribe();\r\n        } else {\r\n            // write to database.\r\n            this.database.write(record).subscribe();\r\n        }\r\n    }\r\n\r\n    private logAnyway(message: PerformanceProfileData): void {\r\n        const self = MsftSme.self();\r\n        const record: PerformanceProfileRecord = {\r\n            ...message,\r\n            ...{ sessionId: self.Init.sessionId, timestamp: Date.now(), moduleName: self.Init.moduleName }\r\n        };\r\n\r\n        if (!record.errorMessage) {\r\n            delete record['errorMessage'];\r\n        }\r\n\r\n        if (this.rpc && this.rpc.stateActive && this.rpcObservablePerformanceClient) {\r\n            // send to shell.\r\n            this.rpcObservablePerformanceClient.log(record).subscribe();\r\n        }\r\n    }\r\n\r\n    private registerHttp(): void {\r\n        const startPropertyName = '_start_';\r\n\r\n        Http.registerMonitorSet({\r\n            name: PerformanceProfile.monitorName,\r\n            preMonitor: (request: AjaxRequest) => {\r\n                if (!request) {\r\n                    Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxRequest object.');\r\n                    return of(request);\r\n                }\r\n\r\n                request[startPropertyName] = Date.now();\r\n                return of(request);\r\n            },\r\n            successMonitor: (response: AjaxResponse<any>) => {\r\n                if (!response || !response.request || !response.request.url) {\r\n                    Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxResponse object.');\r\n                    return of(response);\r\n                }\r\n\r\n                const request = response.request;\r\n                const url = request.url;\r\n                const method = request.method;\r\n                const end = Date.now();\r\n                const start = request[startPropertyName];\r\n                if (url.indexOf('/features/powershellApi/') > 0 || url.indexOf('/services/WinREST/PowerShell/') > 0){\r\n                    const powershell = PerformanceProfile.powershellApi(url, request.body, response.response);\r\n                    PerformanceProfile.logXhrFetchPowerShell('Http', start, end, url, method, response.status, powershell);\r\n                } else if (url.includes('/features/cim/') || url.includes('/services/WinREST/CIM')) {\r\n                    const cim = PerformanceProfile.cimApi(url, request.body);\r\n                    PerformanceProfile.logXhrFetchCim('Http', start, end, url, method, response.status, cim);\r\n                } else if (url.indexOf('/api/batch') > 0) {\r\n                    const batch = PerformanceProfile.batchApi(request.body, response.response);\r\n                    PerformanceProfile.logXhrFetchBatch('Http', start, end, url, method, response.status, batch);\r\n                } else {\r\n                    PerformanceProfile.logXhrFetch('Http', start, end, url, method, response.status);\r\n                }\r\n\r\n                return of(response);\r\n            },\r\n            errorMonitor: (error: AjaxError) => {\r\n                if (!error || !error.response || !error.request || !error.request.url) {\r\n                    Logging.logWarning('Http', 'Http performance profile measurement error to access the AjaxError object.');\r\n                    return throwError(() => error);\r\n                }\r\n\r\n                const request = error.request;\r\n                const url = request.url;\r\n                const method = request.method;\r\n                const end = Date.now();\r\n                const start = request[startPropertyName];\r\n                const message = Net.getErrorMessage(error);\r\n                if (url.indexOf('features/powershellApi') > 0 || url.indexOf('/services/WinREST/PowerShell/') > 0) {\r\n                    const powershell = PerformanceProfile.powershellApi(url, request.body, error.response);\r\n                    PerformanceProfile.logXhrFetchPowerShell('Http', start, end, url, method, error.status, powershell, message);\r\n                } else if (url.includes('/features/cim/') || url.includes('/services/WinREST/CIM/')) {\r\n                    const cim = PerformanceProfile.cimApi(url, request.body);\r\n                    PerformanceProfile.logXhrFetchCim('Http', start, end, url, method, error.status, cim, message);\r\n                } else {\r\n                    PerformanceProfile.logXhrFetch('Http', start, end, url, method, error.status, message);\r\n                }\r\n\r\n                return throwError(() => error);\r\n            }\r\n        });\r\n    }\r\n\r\n    private registerPowerShellStream(): void {\r\n        let masterId = 1;\r\n        PowerShellStream.registerMonitorSet({\r\n            name: PerformanceProfile.monitorName,\r\n            preMonitor: (nodeName: string, command: PowerShellCommand, options?: PowerShellStreamOptions) => {\r\n                const start = Date.now();\r\n                const id = masterId++;\r\n                const context: PowerShellStreamMonitorSetContext<PowerShellStreamContext> = {\r\n                    nodeName,\r\n                    command,\r\n                    options,\r\n                    data: { id, start, progressStart: start, count: 0, itemCount: 0 }\r\n                };\r\n                return of(context);\r\n            },\r\n            successMonitor: (response: any, context: PowerShellStreamMonitorSetContext<PowerShellStreamContext>) => {\r\n                context.data.progressEnd = Date.now();\r\n                context.data.count++;\r\n                context.data.itemCount += (response && response.results && response.results.length || 1);\r\n                PerformanceProfile.logWebSocketPowerShell(\r\n                    'PowerShellStream',\r\n                    context.nodeName,\r\n                    context.command.command,\r\n                    context.data);\r\n                context.data.progressStart = Date.now();\r\n                return of(response);\r\n            },\r\n            errorMonitor: (error: any, context: PowerShellStreamMonitorSetContext<PowerShellStreamContext>) => {\r\n                context.data.progressEnd = Date.now();\r\n                PerformanceProfile.logWebSocketPowerShell(\r\n                    'PowerShellStream',\r\n                    context.nodeName,\r\n                    context.command.command,\r\n                    context.data,\r\n                    Net.getErrorMessage(error));\r\n                return throwError(() => error);\r\n            }\r\n        });\r\n    }\r\n\r\n    private registerCimStream(): void {\r\n        let masterId = 1;\r\n        CimStream.registerMonitorSet({\r\n            name: PerformanceProfile.monitorName,\r\n            preMonitor: (\r\n                nodeName: string,\r\n                requestState: WebsocketStreamDataRequestState,\r\n                request: CimStreamRequestData,\r\n                format: CimResultFormat,\r\n                options?: CimStreamOptions) => {\r\n                const start = Date.now();\r\n                const id = masterId++;\r\n                const context: CimStreamMonitorSetContext<CimStreamContext> = {\r\n                    nodeName,\r\n                    requestState,\r\n                    request,\r\n                    format,\r\n                    options,\r\n                    data: { id, start, progressStart: start, count: 0, itemCount: 0 }\r\n                };\r\n                return of(context);\r\n            },\r\n            successMonitor: (response: any, context: CimStreamMonitorSetContext<CimStreamContext>) => {\r\n                context.data.progressEnd = Date.now();\r\n                context.data.count++;\r\n                context.data.itemCount += (response && response.results && response.results.length || 1);\r\n                PerformanceProfile.logWebSocketCim(\r\n                    'CimStream',\r\n                    context.nodeName,\r\n                    this.removeCimStreamDetailData(context.request),\r\n                    context.data);\r\n                context.data.progressStart = Date.now();\r\n                return of(response);\r\n            },\r\n            errorMonitor: (error: any, context: CimStreamMonitorSetContext<CimStreamContext>) => {\r\n                context.data.progressEnd = Date.now();\r\n                PerformanceProfile.logWebSocketCim(\r\n                    'CimStream',\r\n                    context.nodeName,\r\n                    this.removeCimStreamDetailData(context.request),\r\n                    context.data,\r\n                    Net.getErrorMessage(error));\r\n                return throwError(() => error);\r\n            }\r\n        });\r\n    }\r\n\r\n    private removeCimStreamDetailData(request: CimStreamRequestData): CimStreamRequestData {\r\n        const skipKeys = ['data', 'keyProperties'];\r\n        const requestRaw: any = request;\r\n        const keys = Object.keys(requestRaw);\r\n        const trimmedKeys = keys.filter(key => skipKeys.indexOf(key) < 0);\r\n        if (keys.length !== trimmedKeys.length) {\r\n            const copy: any = {};\r\n            for (const key of trimmedKeys) {\r\n                copy[key] = requestRaw[key];\r\n            }\r\n\r\n            return copy;\r\n        }\r\n\r\n        return request;\r\n    }\r\n}\r\n"]}