UNPKG

@azure/monitor-opentelemetry

Version:
229 lines 9.7 kB
import { SpanStatusCode } from "@opentelemetry/api"; import { SEMATTRS_PEER_SERVICE, SEMATTRS_EXCEPTION_MESSAGE, SEMATTRS_EXCEPTION_TYPE, DBSYSTEMVALUES_DB2, DBSYSTEMVALUES_DERBY, DBSYSTEMVALUES_MARIADB, DBSYSTEMVALUES_MSSQL, DBSYSTEMVALUES_ORACLE, DBSYSTEMVALUES_SQLITE, DBSYSTEMVALUES_OTHER_SQL, DBSYSTEMVALUES_HSQLDB, DBSYSTEMVALUES_H2, SEMRESATTRS_K8S_DEPLOYMENT_NAME, SEMRESATTRS_K8S_REPLICASET_NAME, SEMRESATTRS_K8S_STATEFULSET_NAME, SEMRESATTRS_K8S_JOB_NAME, SEMRESATTRS_K8S_CRONJOB_NAME, SEMRESATTRS_K8S_DAEMONSET_NAME, SEMRESATTRS_K8S_POD_NAME, SEMRESATTRS_SERVICE_INSTANCE_ID, SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_NAMESPACE, } from "@opentelemetry/semantic-conventions"; import { StandardMetricIds, StandardMetricPropertyNames } from "./types.js"; import { getHttpStatusCode, getNetHostPort, getNetPeerName, getUserAgent, } from "./quickpulse/utils.js"; import { Logger } from "../shared/logging/logger.js"; import os from "node:os"; import process from "node:process"; export function getRequestDimensions(span) { const dimensions = getBaseDimensions(span.resource); dimensions.metricId = StandardMetricIds.REQUEST_DURATION; const statusCode = String(getHttpStatusCode(span.attributes)); dimensions.requestResultCode = statusCode; // OTel treats 4xx request responses as UNSET SpanStatusCode, but we should count them as failed dimensions.requestSuccess = span.status.code !== SpanStatusCode.ERROR && (Number(statusCode) || 0) < 400 ? "True" : "False"; if (isSyntheticLoad(span)) { dimensions.operationSynthetic = "True"; } return convertDimensions(dimensions); } export function getDependencyDimensions(span) { const dimensions = getBaseDimensions(span.resource); dimensions.metricId = StandardMetricIds.DEPENDENCIES_DURATION; const statusCode = String(getHttpStatusCode(span.attributes)); dimensions.dependencyTarget = getDependencyTarget(span.attributes); dimensions.dependencyResultCode = statusCode; dimensions.dependencyType = "http"; dimensions.dependencySuccess = span.status.code !== SpanStatusCode.ERROR ? "True" : "False"; if (isSyntheticLoad(span)) { dimensions.operationSynthetic = "True"; } return convertDimensions(dimensions); } export function getExceptionDimensions(resource) { const dimensions = getBaseDimensions(resource); dimensions.metricId = StandardMetricIds.EXCEPTIONS_COUNT; return dimensions; } export function getTraceDimensions(resource) { const dimensions = getBaseDimensions(resource); dimensions.metricId = StandardMetricIds.TRACES_COUNT; return dimensions; } export function getBaseDimensions(resource) { const dimensions = {}; dimensions.IsAutocollected = "True"; if (resource) { dimensions.cloudRoleName = getCloudRole(resource); dimensions.cloudRoleInstance = getCloudRoleInstance(resource); } return dimensions; } // Get metric dependency target, avoiding high cardinality. export function getDependencyTarget(attributes) { if (!attributes) { return ""; } const peerService = attributes[SEMATTRS_PEER_SERVICE]; const hostPort = getNetHostPort(attributes); const netPeerName = getNetPeerName(attributes); if (peerService) { return String(peerService); } else if (hostPort && netPeerName) { return `${netPeerName}:${hostPort}`; } else if (netPeerName) { return String(netPeerName); } return ""; } export function isSqlDB(dbSystem) { return (dbSystem === DBSYSTEMVALUES_DB2 || dbSystem === DBSYSTEMVALUES_DERBY || dbSystem === DBSYSTEMVALUES_MARIADB || dbSystem === DBSYSTEMVALUES_MSSQL || dbSystem === DBSYSTEMVALUES_ORACLE || dbSystem === DBSYSTEMVALUES_SQLITE || dbSystem === DBSYSTEMVALUES_OTHER_SQL || dbSystem === DBSYSTEMVALUES_HSQLDB || dbSystem === DBSYSTEMVALUES_H2); } export function isExceptionTelemetry(logRecord) { const baseType = logRecord.attributes["_MS.baseType"]; // If Application Insights Legacy logs if (baseType && baseType === "ExceptionData") { return true; } else if (logRecord.attributes[SEMATTRS_EXCEPTION_MESSAGE] || logRecord.attributes[SEMATTRS_EXCEPTION_TYPE]) { return true; } return false; } export function isTraceTelemetry(logRecord) { const baseType = logRecord.attributes["_MS.baseType"]; // If Application Insights Legacy logs if (baseType && baseType === "MessageData") { return true; } else if (!logRecord.attributes[SEMATTRS_EXCEPTION_MESSAGE] && !logRecord.attributes[SEMATTRS_EXCEPTION_TYPE]) { return true; } return false; } export function isSyntheticLoad(record) { const userAgent = String(getUserAgent(record.attributes)); return userAgent !== null && userAgent.includes("AlwaysOn") ? true : false; } export function convertDimensions(dimensions) { const convertedDimensions = {}; for (const dim in dimensions) { convertedDimensions[StandardMetricPropertyNames[dim]] = dimensions[dim]; } return convertedDimensions; } // to get physical memory bytes export function getPhysicalMemory() { if (process?.memoryUsage) { return process.memoryUsage.rss(); } else { Logger.getInstance().debug("process.memoryUsage is not available"); return 0; } } // This function can get the normalized cpu, but it assumes that after this function is called, // that the process.hrtime.bigint() & process.cpuUsage() are called/stored to be used as the // parameters for the next call. export function getProcessorTimeNormalized(lastHrTime, lastCpuUsage) { let numCpus = os.cpus().length; const usageDif = process.cpuUsage(lastCpuUsage); const elapsedTimeNs = process.hrtime.bigint() - lastHrTime; const usageDifMs = (usageDif.user + usageDif.system) / 1000.0; const elapsedTimeMs = elapsedTimeNs === BigInt(0) ? 1 : Number(elapsedTimeNs) / 1000000.0; // just for division safety, don't know a case in which this would actually happen numCpus = numCpus === 0 ? 1 : numCpus; return (usageDifMs / elapsedTimeMs / numCpus) * 100; } // This function can get the cpu %, but it assumes that after this function is called, // that the process.hrtime.bigint() & process.cpuUsage() are called/stored to be used as the // parameters for the next call. export function getProcessorTime(lastHrTime, lastCpuUsage) { if (process?.cpuUsage) { const usageDif = process.cpuUsage(lastCpuUsage); const elapsedTimeNs = process.hrtime.bigint() - lastHrTime; const usageDifMs = (usageDif.user + usageDif.system) / 1000.0; const elapsedTimeMs = elapsedTimeNs === BigInt(0) ? 1 : Number(elapsedTimeNs) / 1000000.0; return (usageDifMs / elapsedTimeMs) * 100; } else { Logger.getInstance().debug("process.cpuUsage is not available"); return 0; } } /** * Gets the cloud role name based on the resource attributes */ export function getCloudRole(resource) { let cloudRole = ""; // Service attributes const serviceName = resource.attributes[SEMRESATTRS_SERVICE_NAME]; const serviceNamespace = resource.attributes[SEMRESATTRS_SERVICE_NAMESPACE]; if (serviceName) { // Custom Service name provided by customer is highest precedence if (!String(serviceName).startsWith("unknown_service")) { if (serviceNamespace) { return `${serviceNamespace}.${serviceName}`; } else { return String(serviceName); } } else { // Service attributes will be only used if K8S attributes are not present if (serviceNamespace) { cloudRole = `${serviceNamespace}.${serviceName}`; } else { cloudRole = String(serviceName); } } } // Kubernetes attributes should take precedence const kubernetesDeploymentName = resource.attributes[SEMRESATTRS_K8S_DEPLOYMENT_NAME]; if (kubernetesDeploymentName) { return String(kubernetesDeploymentName); } const kuberneteReplicasetName = resource.attributes[SEMRESATTRS_K8S_REPLICASET_NAME]; if (kuberneteReplicasetName) { return String(kuberneteReplicasetName); } const kubernetesStatefulSetName = resource.attributes[SEMRESATTRS_K8S_STATEFULSET_NAME]; if (kubernetesStatefulSetName) { return String(kubernetesStatefulSetName); } const kubernetesJobName = resource.attributes[SEMRESATTRS_K8S_JOB_NAME]; if (kubernetesJobName) { return String(kubernetesJobName); } const kubernetesCronjobName = resource.attributes[SEMRESATTRS_K8S_CRONJOB_NAME]; if (kubernetesCronjobName) { return String(kubernetesCronjobName); } const kubernetesDaemonsetName = resource.attributes[SEMRESATTRS_K8S_DAEMONSET_NAME]; if (kubernetesDaemonsetName) { return String(kubernetesDaemonsetName); } return cloudRole; } /** * Gets the cloud role instance based on the resource attributes */ export function getCloudRoleInstance(resource) { // Kubernetes attributes should take precedence const kubernetesPodName = resource.attributes[SEMRESATTRS_K8S_POD_NAME]; if (kubernetesPodName) { return String(kubernetesPodName); } // Service attributes const serviceInstanceId = resource.attributes[SEMRESATTRS_SERVICE_INSTANCE_ID]; if (serviceInstanceId) { return String(serviceInstanceId); } // Default return os && os.hostname(); } //# sourceMappingURL=utils.js.map