Skip to content

Commit

Permalink
feat(otel): ability to propagate otel context
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Jan 18, 2024
1 parent c7c5f5e commit 5c8a3a2
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/yellow-countries-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@envelop/opentelemetry': patch
---

Ability to propagate otel context
117 changes: 79 additions & 38 deletions packages/plugins/opentelemetry/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ type PluginContext = {
[tracingSpanSymbol]: opentelemetry.Span;
};

export const otelContextMap = new WeakMap<any, opentelemetry.Context>();

export function getCurrentOtelContext(graphqlContext: any): opentelemetry.Context {
let otelContext = otelContextMap.get(graphqlContext);

if (!otelContext) {
otelContext = opentelemetry.context.active();
otelContextMap.set(graphqlContext, otelContext);
}

return otelContext;
}

export function setCurrentOtelContext(graphqlContext: any, otelContext: opentelemetry.Context) {
otelContextMap.set(graphqlContext, otelContext);
return otelContext;
}

export const useOpenTelemetry = (
options: TracingOptions,
tracingProvider?: TracerProvider,
Expand All @@ -70,7 +88,7 @@ export const useOpenTelemetry = (
useOnResolve(({ info, context, args }) => {
const parentSpan = spanByContext.get(context);
if (parentSpan) {
const ctx = opentelemetry.trace.setSpan(opentelemetry.context.active(), parentSpan);
const ctx = opentelemetry.trace.setSpan(getCurrentOtelContext(context), parentSpan);
const { fieldName, returnType, parentType } = info;

const resolverSpan = tracer.startSpan(
Expand Down Expand Up @@ -103,7 +121,12 @@ export const useOpenTelemetry = (
);
}
},
onExecute({ args }) {
onExecute({ args, executeFn, setExecuteFn }) {
setExecuteFn(function wrappedExecuteFnWithOtelCtx(args) {
return opentelemetry.context.with(getCurrentOtelContext(args.contextValue), () =>
executeFn(args),
);
});
const operationAst = getOperationAST(args.document, args.operationName);
if (!operationAst) {
return;
Expand All @@ -122,24 +145,29 @@ export const useOpenTelemetry = (
isDocumentLoggable = false;
}
const operationName = operationAst.name?.value || 'anonymous';
const executionSpan = tracer.startSpan(`${spanPrefix}${operationType}.${operationName}`, {
kind: spanKind,
attributes: {
...spanAdditionalAttributes,
[AttributeName.EXECUTION_OPERATION_NAME]: operationName,
[AttributeName.EXECUTION_OPERATION_TYPE]: operationType,
[AttributeName.EXECUTION_OPERATION_DOCUMENT]: isDocumentLoggable
? getDocumentString(args.document, print)
: undefined,
...(options.variables
? { [AttributeName.EXECUTION_VARIABLES]: JSON.stringify(args.variableValues ?? {}) }
: {}),
const currOtelContext = getCurrentOtelContext(args.contextValue);
const executionSpan = tracer.startSpan(
`${spanPrefix}${operationType}.${operationName}`,
{
kind: spanKind,
attributes: {
...spanAdditionalAttributes,
[AttributeName.EXECUTION_OPERATION_NAME]: operationName,
[AttributeName.EXECUTION_OPERATION_TYPE]: operationType,
[AttributeName.EXECUTION_OPERATION_DOCUMENT]: isDocumentLoggable
? getDocumentString(args.document, print)
: undefined,
...(options.variables
? { [AttributeName.EXECUTION_VARIABLES]: JSON.stringify(args.variableValues ?? {}) }
: {}),
},
},
});
currOtelContext,
);

const otelContext = opentelemetry.trace.setSpan(
opentelemetry.context.active(),
executionSpan,
setCurrentOtelContext(
args.contextValue,
opentelemetry.trace.setSpan(currOtelContext, executionSpan),
);

const resultCbs: OnExecuteHookResult<PluginContext> = {
Expand All @@ -149,7 +177,8 @@ export const useOpenTelemetry = (
executionSpan.setAttribute(AttributeName.EXECUTION_RESULT, JSON.stringify(result));
}
if (options.traceIdInResult) {
setResult(addTraceIdToResult(otelContext, result, options.traceIdInResult));
const currOtelContext = getCurrentOtelContext(args.contextValue);
setResult(addTraceIdToResult(currOtelContext, result, options.traceIdInResult));
}
markError(executionSpan, result);
executionSpan.end();
Expand All @@ -159,7 +188,8 @@ export const useOpenTelemetry = (
// handles async iterator
onNext: ({ result, setResult }) => {
if (options.traceIdInResult) {
setResult(addTraceIdToResult(otelContext, result, options.traceIdInResult));
const currOtelContext = getCurrentOtelContext(args.contextValue);
setResult(addTraceIdToResult(currOtelContext, result, options.traceIdInResult));
}
markError(executionSpan, result);
},
Expand All @@ -176,7 +206,12 @@ export const useOpenTelemetry = (

return resultCbs;
},
onSubscribe({ args }) {
onSubscribe({ args, subscribeFn, setSubscribeFn }) {
setSubscribeFn(function wrappedSubscribeFnWithOtelCtx(args) {
return opentelemetry.context.with(getCurrentOtelContext(args.contextValue), () =>
subscribeFn(args),
);
});
const operationAst = getOperationAST(args.document, args.operationName);
if (!operationAst) {
return;
Expand All @@ -190,25 +225,30 @@ export const useOpenTelemetry = (
} else {
isDocumentLoggable = false;
}
const currOtelContext = getCurrentOtelContext(args.contextValue);
const operationName = operationAst.name?.value || 'anonymous';
const subscriptionSpan = tracer.startSpan(`${operationType}.${operationName}`, {
kind: spanKind,
attributes: {
...spanAdditionalAttributes,
[AttributeName.EXECUTION_OPERATION_NAME]: operationName,
[AttributeName.EXECUTION_OPERATION_TYPE]: operationType,
[AttributeName.EXECUTION_OPERATION_DOCUMENT]: isDocumentLoggable
? getDocumentString(args.document, print)
: undefined,
...(options.variables
? { [AttributeName.EXECUTION_VARIABLES]: JSON.stringify(args.variableValues ?? {}) }
: {}),
const subscriptionSpan = tracer.startSpan(
`${operationType}.${operationName}`,
{
kind: spanKind,
attributes: {
...spanAdditionalAttributes,
[AttributeName.EXECUTION_OPERATION_NAME]: operationName,
[AttributeName.EXECUTION_OPERATION_TYPE]: operationType,
[AttributeName.EXECUTION_OPERATION_DOCUMENT]: isDocumentLoggable
? getDocumentString(args.document, print)
: undefined,
...(options.variables
? { [AttributeName.EXECUTION_VARIABLES]: JSON.stringify(args.variableValues ?? {}) }
: {}),
},
},
});
currOtelContext,
);

const otelContext = opentelemetry.trace.setSpan(
opentelemetry.context.active(),
subscriptionSpan,
setCurrentOtelContext(
args.contextValue,
opentelemetry.trace.setSpan(currOtelContext, subscriptionSpan),
);

const resultCbs: OnSubscribeHookResult<PluginContext> = {
Expand All @@ -220,7 +260,8 @@ export const useOpenTelemetry = (
// handles async iterator
onNext: ({ result, setResult }) => {
if (options.traceIdInResult) {
setResult(addTraceIdToResult(otelContext, result, options.traceIdInResult));
const currOtelContext = getCurrentOtelContext(args.contextValue);
setResult(addTraceIdToResult(currOtelContext, result, options.traceIdInResult));
}
markError(subscriptionSpan, result);
},
Expand Down

0 comments on commit 5c8a3a2

Please sign in to comment.