{"version":3,"sources":["../../../packages/core/diagnostics/logging.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAkB,MAAM,4BAA4B,CAAC;AAO/E,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAIjC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAqCrD;;;GAGG;AACH,qBAAa,OAAO;IAChB,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAM;IACvC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAAO;IAC9C,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAS;IAC9C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAU;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAU;IACjC,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAwC;IAC1E,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAyC;IAC7E,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAwC;IACzE,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAiB;IAErD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,sBAAsB,CAA4B;IAC1D,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,YAAY,CAAgC;IAEpD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;;;;OAKG;WACW,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC;IAIlD;;;;;;;OAOG;WACW,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAItF;;;;;;;OAOG;WACW,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAInF;;;;;;;OAOG;WACW,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAIrF;;;;;;;OAOG;WACW,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAIrF;;;;;;;OAOG;WACW,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAI3F;;;;;;;OAOG;WACW,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAIrF;;;;;;;OAOG;WACW,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAInF;;;;;OAKG;WACW,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC;IAI1D;;;;;OAKG;WACW,eAAe,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAStD;;;;;;;;;OASG;WACW,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAItH;;;;;;;;;OASG;WACW,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIhI;;;;;;;;;IASA;WACc,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAI/H;;;;;;;;;;OAUG;WACW,YAAY,CACtB,WAAW,EAAE,oBAAoB,EACjC,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,GAAG,EACpB,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAiBpC;;;;;;;;;;OAUG;WACW,iBAAiB,CAC3B,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAgBpC;;;;;;;;;;OAUG;WACW,iBAAiB,CAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAgBpC;;;;;;;;;;;;OAYG;WACW,gBAAgB,CAC1B,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,EACvC,cAAc,CAAC,EAAE,GAAG,EACpB,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAkBpC;;OAEG;WACW,KAAK,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI;IAMtC;;;;;OAKG;WACW,YAAY,CAAC,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,GAAG,IAAI;IAK1F;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAoB/B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAQjC;;OAEG;IACH,IAAW,eAAe,IAAI,QAAQ,CAGrC;IAED;;OAEG;IACH,OAAO,KAAK,SAAS,GAGpB;IAED;;OAEG;IACH,OAAO,KAAK,YAAY,GAGvB;IAED;;OAEG;;IAeH;;OAEG;IACH,WAAkB,OAAO,IAAI,OAAO,CAOnC;IAED;;OAEG;WACW,SAAS;IAIvB;;OAEG;WACW,cAAc;IAI5B;;;;OAIG;IACI,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IA2B9D;;OAEG;IACI,OAAO,IAAI,IAAI;IAKtB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IA+EnB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAOlB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAclB;;OAEG;IACH,OAAO,CAAC,KAAK;IAMb;;OAEG;IACH,OAAO,CAAC,aAAa;CAcxB","file":"logging.d.ts","sourcesContent":["/* eslint-disable no-console */\r\nimport { Subscription } from 'rxjs';\r\nimport { filter, take } from 'rxjs/operators';\r\nimport { GatewayConnection, GatewayRequest } from '../data/gateway-connection';\r\nimport { Http } from '../data/http';\r\nimport { Net } from '../data/net';\r\nimport { Strings } from '../generated/strings';\r\nimport { RpcLogClient } from '../rpc/log/rpc-log-client';\r\nimport { RpcLogRecord } from '../rpc/log/rpc-log-model';\r\nimport { RpcLogSubjectServer } from '../rpc/log/rpc-log-subject-server';\r\nimport { Rpc } from '../rpc/rpc';\r\nimport { RpcTelemetryClient } from '../rpc/telemetry/rpc-telemetry-client';\r\nimport { RpcTelemetryRecord } from '../rpc/telemetry/rpc-telemetry-model';\r\nimport { RpcTelemetrySubjectServer } from '../rpc/telemetry/rpc-telemetry-subject-server';\r\nimport { LogLevel } from './log-level';\r\nimport { LogRecord } from './log-record';\r\nimport { LoggingConstants } from './logging-constants';\r\nimport { TelemetryControlType } from './telemetry-control-type';\r\nimport { TelemetryRecord } from './telemetry-record';\r\n\r\n/**\r\n * Logger set for log and telemetry.\r\n */\r\ninterface LoggerSet<T> {\r\n    /**\r\n     * Max record to send to gateway. If it reaches then sends to gateway.\r\n     */\r\n    maxRecordLength: number;\r\n\r\n    /**\r\n     * Max wait time milliseconds. If it reaches then sends to gateway.\r\n     */\r\n    maxWaitTimeMs: number;\r\n\r\n    /**\r\n     * The api url.\r\n     */\r\n    api: string;\r\n\r\n    /**\r\n     * Subscription to rpc channel observable.\r\n     */\r\n    rpcSubscription?: Subscription;\r\n\r\n    /**\r\n     * Buffer.\r\n     */\r\n    buffer?: T[];\r\n\r\n    /**\r\n     * Timer object.\r\n     */\r\n    timer?: any;\r\n}\r\n\r\n/**\r\n * Logging class.\r\n * @dynamic\r\n */\r\nexport class Logging {\r\n    private static logMaxRecordLength = 20;\r\n    private static logMaxWaitTimeMs = 30000;\r\n    private static telemetryMaxRecordLength = 100;\r\n    private static telemetryMaxWaitTimeMs = 60000;\r\n    private static testMode = 'test';\r\n    private static instance: Logging;\r\n    private static errorLogHeaderStyle = 'font-weight: bold; color: #E81123;';\r\n    private static warnLogHeaderStyle = 'font-weight: bold; color: #FF8C00;';\r\n    private static successLogHeaderStyle = 'font-weight: bold; color: ##288928;';\r\n    private static infoLogHeaderStyle = 'font-weight: bold; color: #0078D7;';\r\n    private static verboseLogHeaderStyle = 'color: #999';\r\n\r\n    private logSubjectServer: RpcLogSubjectServer;\r\n    private telemetrySubjectServer: RpcTelemetrySubjectServer;\r\n    private gateway: GatewayConnection;\r\n    private http: Http;\r\n    private rpc: Rpc;\r\n    private logSet: LoggerSet<RpcLogRecord>;\r\n    private telemetrySet: LoggerSet<RpcTelemetryRecord>;\r\n\r\n    private thresholdOfLogLevel: LogLevel = LogLevel.Informational;\r\n    private verboseTelemetry = false;\r\n\r\n    /**\r\n     * Log a logging event.\r\n     *\r\n     * @param record the log record to send the gateway.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static log(record: LogRecord): Promise<any> {\r\n        return Logging.current.logInternal(record);\r\n    }\r\n\r\n    /**\r\n     * Log a critical logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logCritical(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Critical, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log an error logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logError(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Error, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log a warning logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logWarning(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Warning, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log a success logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logSuccess(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Success, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log a informational logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logInformational(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Informational, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log a verbose logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logVerbose(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Verbose, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Log a debug logging event.\r\n     *\r\n     * @param source The record originator of event within a module.\r\n     * @param message The message of event.\r\n     * @param params The parameters object which will be serialized.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static logDebug(source: string, message: string, params?: any): Promise<any> {\r\n        return Logging.current.logInternal({ level: LogLevel.Debug, source, message, params: params });\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event.\r\n     *\r\n     * @param record the telemetry record to send the gateway.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static trace(record: TelemetryRecord): Promise<any> {\r\n        return Logging.current.telemetryInternal(record);\r\n    }\r\n\r\n    /**\r\n     * Trace a user action telemetry event.\r\n     *\r\n     * @param data additional data.\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceUserAction(data: any): Promise<any> {\r\n        return Logging.trace({\r\n            view: LoggingConstants.views.smeUIControl,\r\n            instance: LoggingConstants.empty,\r\n            action: LoggingConstants.actions.click,\r\n            data: data\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event for a button click.\r\n     *\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceButton(controlName: string, controlId?: string, nodeName?: string, nodeType?: string): Promise<any> {\r\n        return Logging.traceButtonClick(TelemetryControlType.Button, controlName, controlId, nodeName, nodeType);\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event for a action pane button click.\r\n     *\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceActionPaneButton(controlName: string, controlId?: string, nodeName?: string, nodeType?: string): Promise<any> {\r\n        return Logging.traceButtonClick(TelemetryControlType.ActionPaneButton, controlName, controlId, nodeName, nodeType);\r\n    }\r\n\r\n    /**\r\n  * Trace a telemetry event for a action bar button click.\r\n  *\r\n  * @param controlName Describes which control was used.\r\n  * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n  * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n  * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n  * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n  * @return Promise<any> settle to resolve if buffered.\r\n  */\r\n    public static traceActionBarButton(controlName: string, controlId?: string, nodeName?: string, nodeType?: string): Promise<any> {\r\n        return Logging.traceButtonClick(TelemetryControlType.ActionBarButton, controlName, controlId, nodeName, nodeType);\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event on a sme control.\r\n     *\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param additionalData Additional key value pairs that can be sent to telemetry.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceControl(\r\n        controlType: TelemetryControlType,\r\n        controlName: string,\r\n        controlId?: string,\r\n        additionalData?: any,\r\n        nodeName?: string,\r\n        nodeType?: string): Promise<any> {\r\n        let data = {};\r\n\r\n        if (additionalData) {\r\n            data = additionalData;\r\n        }\r\n        data[controlType] = controlType;\r\n        data[controlName] = controlName;\r\n        data[controlId] = controlId;\r\n        const nodeId = Logging.getFormattedNodeId(nodeName, nodeType);\r\n        if (nodeId) {\r\n            data[LoggingConstants.dataFields.nodeId] = nodeId;\r\n        }\r\n\r\n        return Logging.traceUserAction(data);\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event on click of an external link.\r\n     *\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param url External link that was clicked.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceExternalLink(\r\n        controlName: string,\r\n        url: string,\r\n        controlId?: string,\r\n        nodeName?: string,\r\n        nodeType?: string): Promise<any> {\r\n        const data = {\r\n            controlType: TelemetryControlType.ExternalLink,\r\n            controlName: controlName,\r\n            controlId: controlId,\r\n            url: url\r\n        };\r\n\r\n        const nodeId = Logging.getFormattedNodeId(nodeName, nodeType);\r\n        if (nodeId) {\r\n            data[LoggingConstants.dataFields.nodeId] = nodeId;\r\n        }\r\n\r\n        return Logging.traceUserAction(data);\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event on click of an internal link.\r\n     *\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param route rpc route.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceInternalLink(\r\n        controlName: string,\r\n        route: string,\r\n        controlId?: string,\r\n        nodeName?: string,\r\n        nodeType?: string): Promise<any> {\r\n        const data =  {\r\n            controlType: TelemetryControlType.InternalLink,\r\n            controlName: controlName,\r\n            controlId: controlId,\r\n            route: route\r\n        };\r\n\r\n        const nodeId = Logging.getFormattedNodeId(nodeName, nodeType);\r\n        if (nodeId) {\r\n            data[LoggingConstants.dataFields.nodeId] = nodeId;\r\n        }\r\n\r\n        return Logging.traceUserAction(data);\r\n    }\r\n\r\n    /**\r\n     * Trace a telemetry event when an async task returns.\r\n     *\r\n     * @param eventLocation UI location of the event being recorded.\r\n     * ex) createVmForm, RegisterAadDialog, stopServiceConfirmationDialog...\r\n     * @param eventLabel Description of what event is being logged.\r\n     * ex) 'Registered with Azure', 'Added a connection', 'Failed Azure backup'\r\n     * @param result Result of event.\r\n     * @param additionalData Additional key value pairs that can be sent to telemetry.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    public static traceAsyncResult(\r\n        eventLocation: string,\r\n        eventLabel: string,\r\n        result: 'Success' | 'Error' | 'Failure',\r\n        additionalData?: any,\r\n        nodeName?: string,\r\n        nodeType?: string): Promise<any> {\r\n        let data = {};\r\n        if (additionalData) {\r\n                data = additionalData;\r\n        }\r\n\r\n        data[LoggingConstants.dataFields.eventLocation] = eventLocation;\r\n        data[LoggingConstants.dataFields.eventLabel] = eventLabel;\r\n        data[LoggingConstants.dataFields.result] = result;\r\n\r\n        const nodeId = Logging.getFormattedNodeId(nodeName, nodeType);\r\n        if (nodeId) {\r\n            data[LoggingConstants.dataFields.nodeId] = nodeId;\r\n        }\r\n\r\n        return Logging.traceUserAction(data);\r\n    }\r\n\r\n    /**\r\n     * Log a raw object into the console at debug level of mode.\r\n     */\r\n    public static debug(object: any): void {\r\n        if (Logging.current.consoleLogLevel >= LogLevel.Debug) {\r\n            console.log(object);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Configure logging mode.\r\n     *\r\n     * @param thresholdOfLogLevel the log level for gateway.\r\n     * @param verboseTelemetry if true, optional telemerty will be collected.\r\n     */\r\n    public static configureLog(thresholdOfLogLevel: LogLevel, verboseTelemetry: boolean): void {\r\n        Logging.current.thresholdOfLogLevel = thresholdOfLogLevel;\r\n        Logging.current.verboseTelemetry = verboseTelemetry;\r\n    }\r\n\r\n    /**\r\n     * Wrapper method for tracing a telemetry event for a button click.\r\n     *\r\n     * @param controlType Type of button that is being recorded\r\n     * @param controlName Describes which control was used.\r\n     * ex) For a button that says 'Set up' the control name can be 'Set up' to distinguish that from a cancel button.\r\n     * @param controlId Unique identifier when a control appears more than once. Specific to how implementation handles uniqueness.\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return Promise<any> settle to resolve if buffered.\r\n     */\r\n    private static traceButtonClick(\r\n        controlType: TelemetryControlType.ActionBarButton | TelemetryControlType.ActionPaneButton | TelemetryControlType.Button,\r\n        controlName: string,\r\n        controlId?: string,\r\n        nodeName?: string,\r\n        nodeType?: string): Promise<any> {\r\n        const data = {\r\n            controlType: controlType,\r\n            controlName: controlName,\r\n            controlId: controlId\r\n        };\r\n\r\n        const nodeId = Logging.getFormattedNodeId(nodeName, nodeType);\r\n        if (nodeId) {\r\n            data[LoggingConstants.dataFields.nodeId] = nodeId;\r\n        }\r\n\r\n        return Logging.traceUserAction(data);\r\n    }\r\n\r\n    /**\r\n     * Format node information for telemetry\r\n     *\r\n     * @param nodeName the name of the node currently connected to (this.appContextService.activeConnection.nodeName)\r\n     * @param nodeType the type of node currently connected to (this.appContextService.connectionManager.activeConnection.type)\r\n     * @return string\r\n     */\r\n    private static getFormattedNodeId(nodeName?: string, nodeType?: string): string {\r\n        if (nodeType && nodeName) {\r\n            return nodeType + '!' + nodeName;\r\n        } else {\r\n            return null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Gets the level of current logging.\r\n     */\r\n    public get consoleLogLevel(): LogLevel {\r\n        const global: MsftSme.SMEWindow = <any>window;\r\n        return <LogLevel>(global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.logLevel) || LogLevel.Warning;\r\n    }\r\n\r\n    /**\r\n     * Gets the session Id of shell.\r\n     */\r\n    private get sessionId(): string {\r\n        const global: MsftSme.SMEWindow = <any>window;\r\n        return global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.sessionId || Logging.testMode;\r\n    }\r\n\r\n    /**\r\n     * Gets the name of current shell or module.\r\n     */\r\n    private get nameOfModule(): string {\r\n        const global: MsftSme.SMEWindow = <any>window;\r\n        return global.MsftSme && global.MsftSme.Init && global.MsftSme.Init.moduleName || Logging.testMode;\r\n    }\r\n\r\n    /**\r\n     * Initializes a new instance of the Logging class.\r\n     */\r\n    constructor() {\r\n        this.http = new Http();\r\n        this.logSet = {\r\n            maxWaitTimeMs: Logging.logMaxWaitTimeMs,\r\n            maxRecordLength: Logging.logMaxRecordLength,\r\n            api: '/log'\r\n        };\r\n        this.telemetrySet = {\r\n            maxWaitTimeMs: Logging.telemetryMaxWaitTimeMs,\r\n            maxRecordLength: Logging.telemetryMaxRecordLength,\r\n            api: '/telemetry'\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Gets the current logging instance.\r\n     */\r\n    public static get current(): Logging {\r\n        if (Logging.instance) {\r\n            return Logging.instance;\r\n        }\r\n\r\n        Logging.instance = new Logging();\r\n        return Logging.instance;\r\n    }\r\n\r\n    /**\r\n     * Flush the regular log set, immediately submitting the logs to the gateway\r\n     */\r\n    public static flushLogs() {\r\n        Logging.current.flush(Logging.current.logSet);\r\n    }\r\n\r\n    /**\r\n     * Flush the telemetry log set, immediately submitting the logs to the gateway\r\n     */\r\n    public static flushTelemetry() {\r\n        Logging.current.flush(Logging.current.telemetrySet);\r\n    }\r\n\r\n    /**\r\n     * Register Rpc object to logging instance.\r\n     *\r\n     * @param rpc the rpc instance.\r\n     */\r\n    public registerRpc(rpc: Rpc, gateway: GatewayConnection): void {\r\n        this.rpc = rpc;\r\n        this.gateway = gateway;\r\n\r\n        // start subscribing once after the rpc is ready on the shell.\r\n        this.rpc.stateChanged\r\n            .pipe(\r\n                filter(active => active),\r\n                take(1))\r\n            .subscribe(() => {\r\n                if (this.rpc.isShell) {\r\n                    this.logSubjectServer = new RpcLogSubjectServer(this.rpc);\r\n                    this.logSet.rpcSubscription = this.logSubjectServer.subject\r\n                        .subscribe(data => {\r\n                            this.logGateway<RpcLogRecord>(this.logSet, data.data);\r\n                            data.deferred.resolve();\r\n                        });\r\n                    this.telemetrySubjectServer = new RpcTelemetrySubjectServer(this.rpc);\r\n                    this.telemetrySet.rpcSubscription = this.telemetrySubjectServer.subject\r\n                        .subscribe(data => {\r\n                            this.logGateway<RpcTelemetryRecord>(this.telemetrySet, data.data);\r\n                            data.deferred.resolve();\r\n                        });\r\n                }\r\n            });\r\n    }\r\n\r\n    /**\r\n     * Dispose the set of rpc forwarding pipes.\r\n     */\r\n    public dispose(): void {\r\n        this.disposeSet<RpcLogRecord>(this.logSet);\r\n        this.disposeSet<RpcTelemetryRecord>(this.telemetrySet);\r\n    }\r\n\r\n    /**\r\n     * Log a record.\r\n     *\r\n     * @param record the log record.\r\n     * @return Promise<any> the promise object.\r\n     */\r\n    private logInternal(record: LogRecord): Promise<any> {\r\n        const now = new Date();\r\n        if (record.level <= this.consoleLogLevel) {\r\n            let headerStyle = Logging.verboseLogHeaderStyle;\r\n            if (record.level <= LogLevel.Error) {\r\n                headerStyle = Logging.errorLogHeaderStyle;\r\n            } else if (record.level <= LogLevel.Warning) {\r\n                headerStyle = Logging.warnLogHeaderStyle;\r\n            } else if (record.level <= LogLevel.Success) {\r\n                headerStyle = Logging.successLogHeaderStyle;\r\n            } else if (record.level <= LogLevel.Informational) {\r\n                headerStyle = Logging.infoLogHeaderStyle;\r\n            }\r\n\r\n            const logSeparator = '--';\r\n            const customHeader = record.consoleGroupHeader ? ` ${logSeparator} ${record.consoleGroupHeader}` : '';\r\n            if (MsftSme.isEdge() || MsftSme.isInternetExplorer()) {\r\n                // Microsoft Edge and IE don't support styles in group headers. so remove if running on Microsoft Edge\r\n                // Since there is no color support, also log the severity\r\n                console.groupCollapsed(\r\n                    `${LogLevel[record.level]} ${logSeparator} ${this.nameOfModule} ${logSeparator} ${record.source}${customHeader}`\r\n                );\r\n            } else {\r\n                console.groupCollapsed(`%c${this.nameOfModule} ${logSeparator} ${record.source}${customHeader}`, headerStyle);\r\n            }\r\n\r\n            console.log(`logLevel: ${LogLevel[record.level]}`);\r\n            console.log(`timestamp: ${now.toISOString()}`);\r\n            if (record.message) {\r\n                if (MsftSme.isObject(record.message)) {\r\n                    console.log('message:');\r\n                    console.log({ ...record.message });\r\n                } else {\r\n                    console.log(`message: ${record.message}`);\r\n                }\r\n            }\r\n\r\n            if (record.params) {\r\n                console.group('params');\r\n                console.log({ ...record.params });\r\n                console.groupEnd();\r\n            }\r\n\r\n            if (record.localParams) {\r\n                console.group('params');\r\n                console.log({ ...record.localParams });\r\n                console.groupEnd();\r\n                delete record['localParams'];\r\n            }\r\n\r\n            if (record.stack) {\r\n                console.group('stack');\r\n                console.log(record.stack);\r\n                console.groupEnd();\r\n            }\r\n\r\n            console.groupEnd();\r\n        }\r\n\r\n        if (record.level <= this.thresholdOfLogLevel && this.sessionId !== Logging.testMode) {\r\n            if (MsftSme.isObject(record.message)) {\r\n                // ensure message is a string.\r\n                record.message = JSON.stringify(record.message);\r\n            }\r\n\r\n            const rpcRecord: RpcLogRecord = {\r\n                ...record,\r\n                ...{ sessionId: this.sessionId, timestamp: now.getTime(), sourceName: this.nameOfModule }\r\n            };\r\n            if (this.rpc && this.rpc.stateActive && !this.rpc.isShell) {\r\n                return RpcLogClient.log(this.rpc, rpcRecord);\r\n            }\r\n\r\n            this.logGateway<RpcLogRecord>(this.logSet, rpcRecord);\r\n        }\r\n\r\n        return Promise.resolve();\r\n    }\r\n\r\n    /**\r\n     * Log a telemerty record.\r\n     *\r\n     * @param record the telemetry record.\r\n     * @return Promise<any> the promise object.\r\n     */\r\n    private telemetryInternal(record: TelemetryRecord): Promise<any> {\r\n        if (((!this.verboseTelemetry && !record.optional) || this.verboseTelemetry) && this.sessionId !== Logging.testMode) {\r\n            const rpcRecord = { ...record, ...{ sessionId: this.sessionId, timestamp: Date.now(), sourceName: this.nameOfModule } };\r\n            if (this.rpc && this.rpc.stateActive && !this.rpc.isShell) {\r\n                return RpcTelemetryClient.telemetry(this.rpc, rpcRecord);\r\n            }\r\n\r\n            this.logGateway<RpcTelemetryRecord>(this.telemetrySet, rpcRecord);\r\n        }\r\n\r\n        return Promise.resolve();\r\n    }\r\n\r\n    /**\r\n     * Dispose the set.\r\n     *\r\n     * @param set the logger set.\r\n     */\r\n    private disposeSet<T>(set: LoggerSet<T>): void {\r\n        if (set.rpcSubscription) {\r\n            set.rpcSubscription.unsubscribe();\r\n            set.rpcSubscription = null;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Log to the gateway.\r\n     *\r\n     * @param set the logger set.\r\n     * @param data the record data.\r\n     */\r\n    private logGateway<T>(set: LoggerSet<T>, data: T): void {\r\n        if (set.timer == null) {\r\n            set.buffer = [];\r\n            set.timer = setTimeout(() => this.submitRecords<T>(set), set.maxWaitTimeMs);\r\n        }\r\n\r\n        set.buffer.push(data);\r\n        if (set.buffer.length >= set.maxRecordLength) {\r\n            clearTimeout(set.timer);\r\n            this.submitRecords(set);\r\n            set.timer = setTimeout(() => this.submitRecords<T>(set), set.maxWaitTimeMs);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Flush a log set, immediately submitting the logs to the gateway\r\n     */\r\n    private flush<T>(set: LoggerSet<T>) {\r\n        if (set && set.buffer && set.buffer.length > 0) {\r\n            this.submitRecords(set);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Submit records to the gateway.\r\n     */\r\n    private submitRecords<T>(set: LoggerSet<T>): void {\r\n        // Disabled gateway can't log anything in gateway.\r\n        if (set.buffer.length > 0 && this.gateway && !this.gateway.disabled) {\r\n            this.gateway.post(set.api, set.buffer, <GatewayRequest>{ maxRetryCount: 0 }).subscribe({\r\n                error: error => {\r\n                    const message = MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.LoggingUnableSubmit.message;\r\n                    console.error(message.format(Net.getErrorMessage(error)));\r\n                }\r\n            });\r\n        }\r\n\r\n        set.timer = null;\r\n        set.buffer = [];\r\n    }\r\n}\r\n"]}