UNPKG

@google-cloud/spanner

Version:
159 lines 5.64 kB
"use strict"; /** * Copyright 2025 Google LLC. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.randIdForProcess = exports.X_GOOG_SPANNER_REQUEST_ID_SPAN_ATTR = exports.X_GOOG_SPANNER_REQUEST_ID_HEADER = exports.X_GOOG_REQ_ID_REGEX = exports.AtomicCounter = void 0; exports.resetNthClientId = resetNthClientId; exports.attributeXGoogSpannerRequestIdToActiveSpan = attributeXGoogSpannerRequestIdToActiveSpan; exports.craftRequestId = craftRequestId; exports.injectRequestIDIntoError = injectRequestIDIntoError; exports.injectRequestIDIntoHeaders = injectRequestIDIntoHeaders; exports.nextNthRequest = nextNthRequest; exports.nextSpannerClientId = nextSpannerClientId; exports.newAtomicCounter = newAtomicCounter; const crypto_1 = require("crypto"); const instrument_1 = require("./instrument"); const randIdForProcess = (0, crypto_1.randomBytes)(8) .readUint32LE(0) .toString(16) .padStart(8, '0'); exports.randIdForProcess = randIdForProcess; const X_GOOG_SPANNER_REQUEST_ID_HEADER = 'x-goog-spanner-request-id'; exports.X_GOOG_SPANNER_REQUEST_ID_HEADER = X_GOOG_SPANNER_REQUEST_ID_HEADER; class AtomicCounter { backingBuffer; constructor(initialValue) { this.backingBuffer = new Uint32Array(new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT)); if (initialValue) { this.increment(initialValue); } } increment(n) { if (!n) { n = 1; } Atomics.add(this.backingBuffer, 0, n); return this.value(); } value() { return Atomics.load(this.backingBuffer, 0); } toString() { return `${this.value()}`; } reset() { Atomics.store(this.backingBuffer, 0, 0); } } exports.AtomicCounter = AtomicCounter; const REQUEST_HEADER_VERSION = 1; function craftRequestId(nthClientId, channelId, nthRequest, attempt) { return `${REQUEST_HEADER_VERSION}.${randIdForProcess}.${nthClientId}.${channelId}.${nthRequest}.${attempt}`; } const nthClientId = new AtomicCounter(); // Only exported for deterministic testing. function resetNthClientId() { nthClientId.reset(); } /* * nextSpannerClientId increments the internal * counter for created SpannerClients, for use * with x-goog-spanner-request-id. */ function nextSpannerClientId() { nthClientId.increment(1); return nthClientId.value(); } function newAtomicCounter(n) { return new AtomicCounter(n); } function extractRequestID(config) { if (!config) { return ''; } const hdrs = config; if (hdrs && hdrs.headers) { return hdrs.headers[X_GOOG_SPANNER_REQUEST_ID_HEADER]; } return ''; } function injectRequestIDIntoError(config, err) { if (!err) { return; } // Inject that RequestID into the actual // error object regardless of the type. const requestID = extractRequestID(config); if (requestID) { Object.assign(err, { requestID: requestID }); } } function injectRequestIDIntoHeaders(headers, session, nthRequest, attempt) { if (!session) { return headers; } if (!nthRequest) { const database = session.parent; if (!(database && typeof database._nextNthRequest === 'function')) { return headers; } nthRequest = database._nextNthRequest(); } attempt = attempt || 1; return _metadataWithRequestId(session, nthRequest, attempt, headers); } function _metadataWithRequestId(session, nthRequest, attempt, priorMetadata) { if (!priorMetadata) { priorMetadata = {}; } const withReqId = { ...priorMetadata, }; const database = session.parent; let clientId = 1; let channelId = 1; if (database) { clientId = database._nthClientId || 1; channelId = database._channelId || 1; } withReqId[X_GOOG_SPANNER_REQUEST_ID_HEADER] = craftRequestId(clientId, channelId, nthRequest, attempt); return withReqId; } function nextNthRequest(database) { if (!(database && typeof database._nextNthRequest === 'function')) { return 1; } return database._nextNthRequest(); } const X_GOOG_SPANNER_REQUEST_ID_SPAN_ATTR = 'x_goog_spanner_request_id'; exports.X_GOOG_SPANNER_REQUEST_ID_SPAN_ATTR = X_GOOG_SPANNER_REQUEST_ID_SPAN_ATTR; /* * attributeXGoogSpannerRequestIdToActiveSpan extracts the x-goog-spanner-request-id * from config, if possible and then adds it as an attribute to the current/active span. * Since x-goog-spanner-request-id is associated with RPC invoking methods, it is invoked * long after tracing has been performed. */ function attributeXGoogSpannerRequestIdToActiveSpan(config) { const reqId = extractRequestID(config); if (!(reqId && reqId.length > 0)) { return; } const span = (0, instrument_1.getActiveOrNoopSpan)(); span.setAttribute(X_GOOG_SPANNER_REQUEST_ID_SPAN_ATTR, reqId); } const X_GOOG_REQ_ID_REGEX = /^1\.[0-9A-Fa-f]{8}(\.\d+){3}\.\d+/; exports.X_GOOG_REQ_ID_REGEX = X_GOOG_REQ_ID_REGEX; //# sourceMappingURL=request_id_header.js.map