UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

132 lines • 6.74 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module RpcInterface */ import { BentleyStatus, Logger } from "@itwin/core-bentley"; import { CommonLoggerCategory } from "../../CommonLoggerCategory"; import { IModelError } from "../../IModelError"; import { RpcProtocolEvent } from "../core/RpcConstants"; import { RpcInvocation } from "../core/RpcInvocation"; import { WebAppRpcRequest } from "./WebAppRpcRequest"; /* eslint-disable @typescript-eslint/no-deprecated */ /** @internal */ const BACKEND = Symbol.for("@itwin.WebAppRpcLogging.Backend"); const FRONTEND = Symbol.for("@itwin.WebAppRpcLogging.Frontend"); /** @internal */ export class WebAppRpcLogging { static initializeBackend(instance) { globalThis[BACKEND] = instance; } static initializeFrontend(instance) { globalThis[FRONTEND] = instance; } static get backend() { const instance = globalThis[BACKEND]; if (typeof (instance) === "undefined") { throw new IModelError(BentleyStatus.ERROR, "Backend logging is not initialized."); } return instance; } static get frontend() { const instance = globalThis[FRONTEND]; if (typeof (instance) === "undefined") { throw new IModelError(BentleyStatus.ERROR, "Frontend logging is not initialized."); } return instance; } static async logProtocolEvent(event, object) { if (object instanceof WebAppRpcRequest) { await WebAppRpcLogging.frontend.logProtocolEvent(event, object); } else if (object instanceof RpcInvocation) { await WebAppRpcLogging.backend.logProtocolEvent(event, object); } } getRpcInterfaceName(g) { return (typeof g === "string") ? g : g.interfaceName; } findPathIds(path) { let iTwinId = ""; let iModelId = ""; const tokens = path.split("/"); for (let i = 0; i !== tokens.length; ++i) { // For backwards compatibility, find old "context" or current "iTwin" terminology if ((/^context$/i).test(tokens[i]) || (/^itwin$/i).test(tokens[i])) { iTwinId = tokens[i + 1] || ""; } if ((/^imodel$/i).test(tokens[i])) { iModelId = tokens[i + 1] || ""; } } return { iTwinId, iModelId }; } buildOperationDescriptor(operation) { if (!operation) { return "unknown.unknown"; } const interfaceName = typeof (operation.interfaceDefinition) === "string" ? operation.interfaceDefinition : operation.interfaceDefinition.interfaceName; const operationName = operation.operationName; return `${interfaceName}.${operationName}`; } logRequest(loggerCategory, message, object) { const operationDescriptor = this.buildOperationDescriptor(object.operation); const pathIds = this.findPathIds(object.path); Logger.logTrace(loggerCategory, `${message}.${operationDescriptor}`, () => ({ method: object.method, path: object.path, operation: object.operation.operationName, rpcInterface: this.getRpcInterfaceName(object.operation.interfaceDefinition), // Alert! The following properties are required by Bentley DevOps standards. Do not change their names! ActivityId: object.id, // eslint-disable-line @typescript-eslint/naming-convention TimeElapsed: ("elapsed" in object) ? object.elapsed : 0, // eslint-disable-line @typescript-eslint/naming-convention MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention ...pathIds, })); } logResponse(loggerCategory, message, object, status, elapsed) { const operationDescriptor = this.buildOperationDescriptor(object.operation); const pathIds = this.findPathIds(object.path); Logger.logTrace(loggerCategory, `${message}.${operationDescriptor}`, () => ({ method: object.method, path: object.path, operation: object.operation.operationName, rpcInterface: this.getRpcInterfaceName(object.operation.interfaceDefinition), status, // Alert! The following properties are required by Bentley DevOps standards. Do not change their names! ActivityId: object.id, // eslint-disable-line @typescript-eslint/naming-convention TimeElapsed: elapsed, // eslint-disable-line @typescript-eslint/naming-convention MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention ...pathIds, })); } } class WebAppRpcLoggingFrontend extends WebAppRpcLogging { async logProtocolEvent(event, object) { switch (event) { case RpcProtocolEvent.RequestCreated: return this.logRequest(CommonLoggerCategory.RpcInterfaceFrontend, "RpcInterface.frontend.request", object); case RpcProtocolEvent.ResponseLoaded: return this.logResponse(CommonLoggerCategory.RpcInterfaceFrontend, "RpcInterface.frontend.response", object, object.metadata.status, object.elapsed); case RpcProtocolEvent.ConnectionErrorReceived: return this.logErrorFrontend("RpcInterface.frontend.connectionError", object); case RpcProtocolEvent.ConnectionAborted: return this.logErrorFrontend("RpcInterface.frontend.connectionAborted", object); } } getHostname() { return globalThis.window?.location?.host ?? "imodeljs-mobile"; } logErrorFrontend(message, request) { const operationDescriptor = this.buildOperationDescriptor(request.operation); const pathIds = this.findPathIds(request.path); Logger.logInfo(CommonLoggerCategory.RpcInterfaceFrontend, `${message}.${operationDescriptor}`, () => ({ method: request.method, path: request.path, // Alert! The following properties are required by Bentley DevOps standards. Do not change their names! ActivityId: request.id, // eslint-disable-line @typescript-eslint/naming-convention MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention ...pathIds, })); } } WebAppRpcLogging.initializeFrontend(new WebAppRpcLoggingFrontend()); //# sourceMappingURL=WebAppRpcLogging.js.map