Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions handwritten/spanner/src/instrument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
context,
trace,
INVALID_SPAN_CONTEXT,
ROOT_CONTEXT,
SpanAttributes,
TimeInput,
TracerProvider,
Expand Down Expand Up @@ -97,23 +96,27 @@ const {
AsyncHooksContextManager,
} = require('@opentelemetry/context-async-hooks');

let contextManagerInstallAttempted = false;

/*
* This function ensures that async/await works correctly by
* checking if context.active() returns an invalid/unset context
* and if so, sets a global AsyncHooksContextManager otherwise
* spans resulting from async/await invocations won't be correctly
* associated in their respective hierarchies.
* If no global ContextManager is registered, install an AsyncHooksContextManager
* so that async/await trace context propagation works for apps that haven't
* configured OpenTelemetry themselves. If the host app has already installed a
* ContextManager, leave it alone — tearing down a working manager breaks the
* host's baggage and span parentage on the next gRPC call.
*
* setGlobalContextManager() returns false when a manager is already registered,
* which is the documented signal that we shouldn't replace it. The
* `contextManagerInstallAttempted` latch makes the call idempotent so we don't
* allocate a new AsyncHooksContextManager on each Spanner client construction.
*/
function ensureInitialContextManagerSet() {
if (!context['_contextManager'] || context.active() === ROOT_CONTEXT) {
// If no context manager is currently set, or if the active context is the ROOT_CONTEXT,
// trace context propagation cannot
// function correctly with async/await for OpenTelemetry
// See {@link https://opentelemetry.io/docs/languages/js/context/#active-context}
context.disable(); // Disable any prior contextManager.
const contextManager = new AsyncHooksContextManager();
contextManager.enable();
context.setGlobalContextManager(contextManager);
if (contextManagerInstallAttempted) return;
contextManagerInstallAttempted = true;
const contextManager = new AsyncHooksContextManager();
contextManager.enable();
if (!context.setGlobalContextManager(contextManager)) {
contextManager.disable();
}
}
Comment thread
jcalem-rogo marked this conversation as resolved.

Expand Down
Loading