wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
{
  "version": 3,
  "sources": ["/mnt/vss/_work/1/s/sdk/core/core-rest-pipeline/src/policies/tracingPolicy.ts"],
  "sourcesContent": ["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport {\n  type TracingClient,\n  type TracingContext,\n  type TracingSpan,\n  createTracingClient,\n} from \"@azure/core-tracing\";\nimport { SDK_VERSION } from \"../constants.js\";\nimport type { PipelineRequest, PipelineResponse, SendRequest } from \"../interfaces.js\";\nimport type { PipelinePolicy } from \"../pipeline.js\";\nimport { getUserAgentValue } from \"../util/userAgent.js\";\nimport { logger } from \"../log.js\";\nimport { getErrorMessage, isError } from \"@azure/core-util\";\nimport { isRestError } from \"../restError.js\";\nimport { Sanitizer } from \"@typespec/ts-http-runtime/internal/util\";\n\n/**\n * The programmatic identifier of the tracingPolicy.\n */\nexport const tracingPolicyName = \"tracingPolicy\";\n\n/**\n * Options to configure the tracing policy.\n */\nexport interface TracingPolicyOptions {\n  /**\n   * String prefix to add to the user agent logged as metadata\n   * on the generated Span.\n   * Defaults to an empty string.\n   */\n  userAgentPrefix?: string;\n  /**\n   * Query string names whose values will be logged when logging is enabled. By default no\n   * query string values are logged.\n   */\n  additionalAllowedQueryParameters?: string[];\n}\n\n/**\n * A simple policy to create OpenTelemetry Spans for each request made by the pipeline\n * that has SpanOptions with a parent.\n * Requests made without a parent Span will not be recorded.\n * @param options - Options to configure the telemetry logged by the tracing policy.\n */\nexport function tracingPolicy(options: TracingPolicyOptions = {}): PipelinePolicy {\n  const userAgentPromise = getUserAgentValue(options.userAgentPrefix);\n  const sanitizer = new Sanitizer({\n    additionalAllowedQueryParameters: options.additionalAllowedQueryParameters,\n  });\n  const tracingClient = tryCreateTracingClient();\n\n  return {\n    name: tracingPolicyName,\n    async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n      if (!tracingClient) {\n        return next(request);\n      }\n\n      const userAgent = await userAgentPromise;\n\n      const spanAttributes = {\n        \"http.url\": sanitizer.sanitizeUrl(request.url),\n        \"http.method\": request.method,\n        \"http.user_agent\": userAgent,\n        requestId: request.requestId,\n      };\n      if (userAgent) {\n        spanAttributes[\"http.user_agent\"] = userAgent;\n      }\n\n      const { span, tracingContext } = tryCreateSpan(tracingClient, request, spanAttributes) ?? {};\n\n      if (!span || !tracingContext) {\n        return next(request);\n      }\n\n      try {\n        const response = await tracingClient.withContext(tracingContext, next, request);\n        tryProcessResponse(span, response);\n        return response;\n      } catch (err: any) {\n        tryProcessError(span, err);\n        throw err;\n      }\n    },\n  };\n}\n\nfunction tryCreateTracingClient(): TracingClient | undefined {\n  try {\n    return createTracingClient({\n      namespace: \"\",\n      packageName: \"@azure/core-rest-pipeline\",\n      packageVersion: SDK_VERSION,\n    });\n  } catch (e: unknown) {\n    logger.warning(`Error when creating the TracingClient: ${getErrorMessage(e)}`);\n    return undefined;\n  }\n}\n\nfunction tryCreateSpan(\n  tracingClient: TracingClient,\n  request: PipelineRequest,\n  spanAttributes: Record<string, unknown>,\n): { span: TracingSpan; tracingContext: TracingContext } | undefined {\n  try {\n    // As per spec, we do not need to differentiate between HTTP and HTTPS in span name.\n    const { span, updatedOptions } = tracingClient.startSpan(\n      `HTTP ${request.method}`,\n      { tracingOptions: request.tracingOptions },\n      {\n        spanKind: \"client\",\n        spanAttributes,\n      },\n    );\n\n    // If the span is not recording, don't do any more work.\n    if (!span.isRecording()) {\n      span.end();\n      return undefined;\n    }\n\n    // set headers\n    const headers = tracingClient.createRequestHeaders(\n      updatedOptions.tracingOptions.tracingContext,\n    );\n    for (const [key, value] of Object.entries(headers)) {\n      request.headers.set(key, value);\n    }\n    return { span, tracingContext: updatedOptions.tracingOptions.tracingContext };\n  } catch (e: any) {\n    logger.warning(`Skipping creating a tracing span due to an error: ${getErrorMessage(e)}`);\n    return undefined;\n  }\n}\n\nfunction tryProcessError(span: TracingSpan, error: unknown): void {\n  try {\n    span.setStatus({\n      status: \"error\",\n      error: isError(error) ? error : undefined,\n    });\n    if (isRestError(error) && error.statusCode) {\n      span.setAttribute(\"http.status_code\", error.statusCode);\n    }\n    span.end();\n  } catch (e: any) {\n    logger.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`);\n  }\n}\n\nfunction tryProcessResponse(span: TracingSpan, response: PipelineResponse): void {\n  try {\n    span.setAttribute(\"http.status_code\", response.status);\n    const serviceRequestId = response.headers.get(\"x-ms-request-id\");\n    if (serviceRequestId) {\n      span.setAttribute(\"serviceRequestId\", serviceRequestId);\n    }\n    // Per semantic conventions, only set the status to error if the status code is 4xx or 5xx.\n    // Otherwise, the status MUST remain unset.\n    // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status\n    if (response.status >= 400) {\n      span.setStatus({\n        status: \"error\",\n      });\n    }\n    span.end();\n  } catch (e: any) {\n    logger.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`);\n  }\n}\n"],
  "mappings": "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",
  "names": []
}