UNPKG

@azure/core-rest-pipeline

Version:

Isomorphic client library for making HTTP requests in node.js and browser.

136 lines 5.37 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.tracingPolicyName = void 0; exports.tracingPolicy = tracingPolicy; const core_tracing_1 = require("@azure/core-tracing"); const constants_js_1 = require("../constants.js"); const userAgent_js_1 = require("../util/userAgent.js"); const log_js_1 = require("../log.js"); const core_util_1 = require("@azure/core-util"); const restError_js_1 = require("../restError.js"); const sanitizer_js_1 = require("../util/sanitizer.js"); /** * The programmatic identifier of the tracingPolicy. */ exports.tracingPolicyName = "tracingPolicy"; /** * A simple policy to create OpenTelemetry Spans for each request made by the pipeline * that has SpanOptions with a parent. * Requests made without a parent Span will not be recorded. * @param options - Options to configure the telemetry logged by the tracing policy. */ function tracingPolicy(options = {}) { const userAgentPromise = (0, userAgent_js_1.getUserAgentValue)(options.userAgentPrefix); const sanitizer = new sanitizer_js_1.Sanitizer({ additionalAllowedQueryParameters: options.additionalAllowedQueryParameters, }); const tracingClient = tryCreateTracingClient(); return { name: exports.tracingPolicyName, async sendRequest(request, next) { var _a; if (!tracingClient) { return next(request); } const userAgent = await userAgentPromise; const spanAttributes = { "http.url": sanitizer.sanitizeUrl(request.url), "http.method": request.method, "http.user_agent": userAgent, requestId: request.requestId, }; if (userAgent) { spanAttributes["http.user_agent"] = userAgent; } const { span, tracingContext } = (_a = tryCreateSpan(tracingClient, request, spanAttributes)) !== null && _a !== void 0 ? _a : {}; if (!span || !tracingContext) { return next(request); } try { const response = await tracingClient.withContext(tracingContext, next, request); tryProcessResponse(span, response); return response; } catch (err) { tryProcessError(span, err); throw err; } }, }; } function tryCreateTracingClient() { try { return (0, core_tracing_1.createTracingClient)({ namespace: "", packageName: "@azure/core-rest-pipeline", packageVersion: constants_js_1.SDK_VERSION, }); } catch (e) { log_js_1.logger.warning(`Error when creating the TracingClient: ${(0, core_util_1.getErrorMessage)(e)}`); return undefined; } } function tryCreateSpan(tracingClient, request, spanAttributes) { try { // As per spec, we do not need to differentiate between HTTP and HTTPS in span name. const { span, updatedOptions } = tracingClient.startSpan(`HTTP ${request.method}`, { tracingOptions: request.tracingOptions }, { spanKind: "client", spanAttributes, }); // If the span is not recording, don't do any more work. if (!span.isRecording()) { span.end(); return undefined; } // set headers const headers = tracingClient.createRequestHeaders(updatedOptions.tracingOptions.tracingContext); for (const [key, value] of Object.entries(headers)) { request.headers.set(key, value); } return { span, tracingContext: updatedOptions.tracingOptions.tracingContext }; } catch (e) { log_js_1.logger.warning(`Skipping creating a tracing span due to an error: ${(0, core_util_1.getErrorMessage)(e)}`); return undefined; } } function tryProcessError(span, error) { try { span.setStatus({ status: "error", error: (0, core_util_1.isError)(error) ? error : undefined, }); if ((0, restError_js_1.isRestError)(error) && error.statusCode) { span.setAttribute("http.status_code", error.statusCode); } span.end(); } catch (e) { log_js_1.logger.warning(`Skipping tracing span processing due to an error: ${(0, core_util_1.getErrorMessage)(e)}`); } } function tryProcessResponse(span, response) { try { span.setAttribute("http.status_code", response.status); const serviceRequestId = response.headers.get("x-ms-request-id"); if (serviceRequestId) { span.setAttribute("serviceRequestId", serviceRequestId); } // Per semantic conventions, only set the status to error if the status code is 4xx or 5xx. // Otherwise, the status MUST remain unset. // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status if (response.status >= 400) { span.setStatus({ status: "error", }); } span.end(); } catch (e) { log_js_1.logger.warning(`Skipping tracing span processing due to an error: ${(0, core_util_1.getErrorMessage)(e)}`); } } //# sourceMappingURL=tracingPolicy.js.map