UNPKG

azurite

Version:

An open source Azure Storage API compatible server

329 lines 17.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AzuriteTelemetryClient = void 0; const tslib_1 = require("tslib"); const Context_1 = tslib_1.__importDefault(require("../blob/generated/Context")); const Context_2 = tslib_1.__importDefault(require("../queue/generated/Context")); const Context_3 = tslib_1.__importDefault(require("../table/generated/Context")); const operation_1 = require("../blob/generated/artifacts/operation"); const operation_2 = require("../queue/generated/artifacts/operation"); const operation_3 = require("../table/generated/artifacts/operation"); const crypto_1 = require("crypto"); const fs = tslib_1.__importStar(require("fs")); const uuid_1 = tslib_1.__importDefault(require("uuid")); const path_1 = require("path"); const Logger_1 = tslib_1.__importDefault(require("./Logger")); const constants_1 = require("../blob/utils/constants"); const constants_2 = require("../queue/utils/constants"); const constants_3 = require("../table/utils/constants"); class AzuriteTelemetryClient { static init(location, enableTelemetry, env, isVSC = false) { try { AzuriteTelemetryClient.enableTelemetry = enableTelemetry; if (enableTelemetry !== false && AzuriteTelemetryClient.initialized != true) { AzuriteTelemetryClient.isVSC = isVSC; AzuriteTelemetryClient.location = location; AzuriteTelemetryClient.instanceID = AzuriteTelemetryClient.GetInstanceID(typeof env?.inMemoryPersistence === "function" && env?.inMemoryPersistence()); Logger_1.default.info(`InstaceID ${AzuriteTelemetryClient.instanceID}, SessionID ${AzuriteTelemetryClient.sessionID}.`); AzuriteTelemetryClient.enableTelemetry = enableTelemetry; AzuriteTelemetryClient.env = env; if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient === undefined) { // for start/stop event, will collect 100%, and send asap this.eventClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, 100, 0); } if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient === undefined) { this.requestClient = AzuriteTelemetryClient.createAppInsigntClient(AzuriteTelemetryClient.cloudRole, AzuriteTelemetryClient.requestCollectPercentage, AzuriteTelemetryClient.requestMaxBatchSize); } AzuriteTelemetryClient.appInsights.start(); AzuriteTelemetryClient.initialized = true; Logger_1.default.info('Telemetry initialize successfully.'); } else { Logger_1.default.info('Don\'t need initialize Telemetry. enableTelemetry: ' + enableTelemetry + ", initialized: " + AzuriteTelemetryClient.initialized); } } catch (e) { Logger_1.default.warn('Fail to init telemetry, error: ' + e.message); } } static removeRoleInstance(envelope) { // per privacy review, will not collect roleInstance name envelope.tags["ai.cloud.roleInstance"] = (0, crypto_1.createHash)('sha256').update(envelope.tags["ai.cloud.roleInstance"]).digest('hex'); // per privacy review, we will not collect operation name as it contains request path envelope.tags["ai.operation.name"] = ""; return true; } static createAppInsigntClient(cloudRole, samplingPercentage, maxBatchSize) { const ConnectionString = 'InstrumentationKey=feb4ae36-1db7-4808-abaa-e0b94996d665;IngestionEndpoint=https://eastus2-3.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus2.livediagnostics.monitor.azure.com/;ApplicationId=9af871a3-75b5-417c-8a2f-7f2eb1ba6a6c'; // disable default logging let appConfig = AzuriteTelemetryClient.appInsights.setup(ConnectionString); appConfig.setAutoCollectRequests(false) .setAutoCollectPerformance(false) .setAutoCollectExceptions(false) .setAutoCollectDependencies(false) .setAutoCollectConsole(false) .setAutoCollectHeartbeat(false) .setAutoCollectConsole(false); // Remove some default telemetry item in the telemetry envelope let telemetryClient = new AzuriteTelemetryClient.appInsights.TelemetryClient(ConnectionString); telemetryClient.addTelemetryProcessor(AzuriteTelemetryClient.removeRoleInstance); if (telemetryClient !== undefined) { telemetryClient.context.tags[telemetryClient.context.keys.cloudRole] = AzuriteTelemetryClient.cloudRole; } telemetryClient.config.samplingPercentage = samplingPercentage ?? 1; // Enable AppInsight log, should enable in develoipment only if (AzuriteTelemetryClient.enableAppInsightLog) { appConfig.setInternalLogging(true, true); } if (maxBatchSize !== undefined) { telemetryClient.config.maxBatchSize = maxBatchSize ?? 0; } return telemetryClient; } static TraceRequest(context) { let serviceType = ""; let totalReqs = 0; let reqName = ""; try { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.requestClient !== undefined) { if (context instanceof Context_1.default) { serviceType = "Blob"; AzuriteTelemetryClient._totalBlobRequestCount++; totalReqs = AzuriteTelemetryClient._totalBlobRequestCount; reqName = "B_" + operation_1.Operation[context.operation ?? 0]; } else if (context instanceof Context_2.default) { serviceType = "Queue"; AzuriteTelemetryClient._totalQueueRequestCount++; totalReqs = AzuriteTelemetryClient._totalQueueRequestCount; reqName = "Q_" + operation_2.Operation[context.operation ?? 0]; } else if (context instanceof Context_3.default) { serviceType = "Table"; AzuriteTelemetryClient._totalTableRequestCount++; totalReqs = AzuriteTelemetryClient._totalTableRequestCount; reqName = "T_" + operation_3.Operation[context.operation ?? 0]; } let requestProperties = { apiVersion: "v" + context.request?.getHeader("x-ms-version"), authorization: context.request !== undefined ? AzuriteTelemetryClient.GetRequestAuthentication(context.request.getHeader("authorization"), context.request.getQuery("sig")) : "", instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, ReqNo: totalReqs, }; const ingress = context.request?.getHeader("content-length"); if (ingress !== undefined) { if (ingress && parseInt(ingress)) { requestProperties["ingress"] = ingress; this._totalIngressSize += parseInt(ingress); } } // When body is xml or json, "content-length" header won't return even has body, so currently can't be caculated into egress in telemetry. // Head request don't has body but can has "content-length" header, like in GetBlobProperties "content-length" header means the blob length but not body length if (context.request?.getMethod() !== "HEAD") { const egress = context.response?.getHeader("content-length"); if (egress !== undefined) { if (egress && parseInt(egress)) { requestProperties["egress"] = egress; this._totalEgressSize += parseInt(egress); } } } AzuriteTelemetryClient.requestClient.trackRequest({ name: reqName, url: context.request !== undefined ? AzuriteTelemetryClient.GetRequestUri(context.request.getEndpoint()) : "", duration: context.startTime ? ((new Date()).getTime() - context.startTime?.getTime()) : 0, resultCode: context.response?.getStatusCode() ?? 0, success: (context.response?.getStatusCode() ?? 500) <= 399, id: context.contextId, // Request ID source: context.request?.getHeader("user-agent"), // User Agent properties: requestProperties, contextObjects: { operationId: "", operationParentId: "", operationName: "test", operation_Name: "test", appName: "" } }); Logger_1.default.verbose(`Send ${serviceType} telemetry: ` + reqName, context.contextId === undefined ? context.contextID : context.contextId); } } catch (e) { Logger_1.default.warn(`Fail to telemetry a ${serviceType} request, error: ` + e.message); } } static async TraceStartEvent(serviceType = "") { try { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { AzuriteTelemetryClient.eventClient.trackEvent({ name: 'Azurite Start' + (serviceType === "" ? "" : ": " + serviceType), properties: { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, parameters: await AzuriteTelemetryClient.GetAllParameterString() } }); Logger_1.default.verbose('Send start telemetry'); } } catch (e) { Logger_1.default.warn('Fail to send start telemetry, error: ' + e.message); } } static TraceStopEvent(serviceType = "") { try { if (AzuriteTelemetryClient.enableTelemetry && AzuriteTelemetryClient.eventClient !== undefined) { AzuriteTelemetryClient.eventClient.trackEvent({ name: 'Azurite Stop' + (serviceType === "" ? "" : ": " + serviceType), properties: { instanceID: AzuriteTelemetryClient.instanceID, sessionID: AzuriteTelemetryClient.sessionID, blobRequest: AzuriteTelemetryClient._totalBlobRequestCount, queueRequest: AzuriteTelemetryClient._totalQueueRequestCount, tableRequest: AzuriteTelemetryClient._totalTableRequestCount, totalIngress: AzuriteTelemetryClient._totalIngressSize, totalEgress: AzuriteTelemetryClient._totalEgressSize, } }); Logger_1.default.verbose('Send stop telemetry'); } } catch (e) { Logger_1.default.warn('Fail to send stop telemetry, error: ' + e.message); } } static GetRequestUri(endpoint) { //From privacy review, won't return the whole Uri let uri = new URL(endpoint); let knownHosts = ["127.0.0.1", "localhost", "host.docker.internal"]; if (uri.hostname.toLowerCase() in knownHosts) { return endpoint.replace(uri.hostname, "[hidden]"); } else { return endpoint; } } static GetInstanceID(inMemoryPersistence = false) { const configFilePath = (0, path_1.join)(AzuriteTelemetryClient.location, AzuriteTelemetryClient.configFileName); let instaceID = ""; if (inMemoryPersistence) { return (0, uuid_1.default)(); } try { if (!fs.existsSync(configFilePath)) { instaceID = (0, uuid_1.default)(); fs.writeFileSync(configFilePath, `{"instaceID":"${instaceID}"}`); } else { try { let data = fs.readFileSync(configFilePath, 'utf8'); instaceID = JSON.parse(data.toString()).instaceID; } catch (e) { Logger_1.default.warn(`Failed to read instaceID from file ${configFilePath} and will regenerate instanceID, error: ` + e.message); } if (instaceID === undefined || instaceID === "") { instaceID = (0, uuid_1.default)(); fs.writeFileSync(configFilePath, `{"instaceID":"${instaceID}"}`); } } return instaceID; } catch (e) { Logger_1.default.warn(`Failed to read or generate/save instaceID, will use instaceID "${instaceID}", error: ` + e.message); return instaceID; } } static GetRequestAuthentication(authorizationHeader, sigQuery) { let auth = authorizationHeader?.split(" ")[0]; if (auth !== undefined && auth !== "") { if (sigQuery !== undefined) { auth = auth + ",Sas"; } //else auth in head is already retrived, no need to add more } else // no auth header { if (sigQuery !== undefined) { auth = "Sas"; } else { auth = "Anonymous"; } } return auth; } static async GetAllParameterString() { let parameters = ""; if (process.env.AZURITE_ACCOUNTS) { parameters += "AZURITE_ACCOUNTS,"; } if (process.env.AZURITE_DB) { parameters += "AZURITE_DB,"; } let longParameters = ["blobHost", "queueHost", "tableHost", "blobPort", "queuePort", "tablePort", "blobKeepAliveTimeout", "queueKeepAliveTimeout", "tableKeepAliveTimeout", "location", "cert", "key", "pwd", "oauth", "extentMemoryLimit", "debug", "silent", "loose", "skipApiVersionCheck", "disableProductStyleUrl", "inMemoryPersistence", "disableTelemetry"]; let shortParameters = { "d": "debug", "l": "location", "L": "loose", "s": "silent" }; if (AzuriteTelemetryClient.isVSC) // VSC { if (AzuriteTelemetryClient.env === undefined) { return parameters; } let workspaceConfiguration = AzuriteTelemetryClient.env; if (workspaceConfiguration === undefined) { return parameters; } else { longParameters.forEach((flag) => { let value = workspaceConfiguration.get(flag); if (value !== undefined && value !== "" && value !== false && value !== null && !(flag.endsWith("Host") && value === constants_1.DEFAULT_BLOB_SERVER_HOST_NAME) && !(flag.endsWith("KeepAliveTimeout") && value === constants_1.DEFAULT_BLOB_KEEP_ALIVE_TIMEOUT) && !(flag == "blobPort" && value === constants_1.DEFAULT_BLOB_LISTENING_PORT) && !(flag == "queuePort" && value === constants_2.DEFAULT_QUEUE_LISTENING_PORT) && !(flag == "tablePort" && value === constants_3.DEFAULT_TABLE_LISTENING_PORT)) { parameters += flag + ","; } }); } } else // npm (exe, docker) { process.argv.forEach((val, index) => { if (val.startsWith("--")) { longParameters.forEach((flag) => { if (val.toLowerCase() === (`--${flag}`).toLowerCase()) { parameters += flag + ","; } }); } else if (val.startsWith("-")) { if (shortParameters[val.substring(1)] !== undefined) { parameters += shortParameters[val.substring(1)] + ","; } } }); } return parameters.endsWith(",") ? parameters.substring(0, parameters.length - 1) : parameters; } } exports.AzuriteTelemetryClient = AzuriteTelemetryClient; AzuriteTelemetryClient.enableTelemetry = true; AzuriteTelemetryClient.configFileName = "AzuriteConfig"; AzuriteTelemetryClient._totalIngressSize = 0; AzuriteTelemetryClient._totalEgressSize = 0; AzuriteTelemetryClient._totalBlobRequestCount = 0; AzuriteTelemetryClient._totalQueueRequestCount = 0; AzuriteTelemetryClient._totalTableRequestCount = 0; AzuriteTelemetryClient.sessionID = (0, uuid_1.default)(); AzuriteTelemetryClient.instanceID = ""; AzuriteTelemetryClient.initialized = false; AzuriteTelemetryClient.env = undefined; AzuriteTelemetryClient.isVSC = false; // Debug options AzuriteTelemetryClient.isDebug = false; // false in production, true in development AzuriteTelemetryClient.requestCollectPercentage = AzuriteTelemetryClient.isDebug ? 100 : 1; AzuriteTelemetryClient.enableAppInsightLog = AzuriteTelemetryClient.isDebug ? true : false; AzuriteTelemetryClient.cloudRole = AzuriteTelemetryClient.isDebug ? "AzuriteTest" : "Azurite_V1.0"; // 0 means send as soon as it's collected, use it in both debug and release mode, since set any other value will make Azurite exist slower AzuriteTelemetryClient.requestMaxBatchSize = AzuriteTelemetryClient.isDebug ? 0 : 0; AzuriteTelemetryClient.appInsights = require('applicationinsights'); //# sourceMappingURL=Telemetry.js.map