azurite
Version:
An open source Azure Storage API compatible server
329 lines • 17.8 kB
JavaScript
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
;