上下文

OpenTelemetry JavaScript 上下文 API 文档

为了使 OpenTelemetry 正常工作,它必须存储和传播重要的遥测数据。例如,当接收到一个请求并开始一个 span 时,它必须对一个创建其子 span 的组件可用。为了解决这个问题,OpenTelemetry 在上下文中存储 span。本文档描述了 JavaScript 上下文 API,并说明了它的使用方式。

更多信息:

上下文管理器

上下文 API 依赖于一个上下文管理器来工作。本文档中的示例假设您已经配置好了一个上下文管理器。通常,上下文管理器是由您的 SDK 提供的,但也可以直接注册一个上下文管理器,如下所示:

import * as api from '@opentelemetry/api';
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';

const contextManager = new AsyncHooksContextManager();
contextManager.enable();
api.context.setGlobalContextManager(contextManager);

根上下文

ROOT_CONTEXT 是空的上下文。如果没有活动的上下文,那么ROOT_CONTEXT 是活动的。活动上下文的说明如下所示活动上下文

上下文键

上下文的条目是键值对。可以通过调用api.createContextKey(description)来创建键。

import * as api from '@opentelemetry/api';

const key1 = api.createContextKey('我的第一个键');
const key2 = api.createContextKey('我的第二个键');

基本操作

获取条目

可以使用context.getValue(key)方法来访问条目。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('某个键');
// ROOT_CONTEXT 是空的上下文
const ctx = api.ROOT_CONTEXT;

const value = ctx.getValue(key);

设置条目

可以使用context.setValue(key, value)方法来创建条目。设置上下文条目将创建一个新的上下文,该上下文包含前一个上下文的所有条目,但具有新的条目。设置上下文条目不会修改前一个上下文。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('某个键');
const ctx = api.ROOT_CONTEXT;

// 添加一个新条目
const ctx2 = ctx.setValue(key, '上下文 2');

// ctx2 包含新的条目
console.log(ctx2.getValue(key)); // "上下文 2"

// ctx 未改变
console.log(ctx.getValue(key)); // undefined

删除条目

可以调用context.deleteValue(key)来删除条目。删除上下文条目将创建一个新的上下文,该上下文包含前一个上下文的所有条目,但不包含由键标识的条目。删除上下文条目不会修改前一个上下文。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('某个键');
const ctx = api.ROOT_CONTEXT;
const ctx2 = ctx.setValue(key, '上下文 2');

// 移除条目
const ctx3 = ctx.deleteValue(key);

// ctx3 不包含该条目
console.log(ctx3.getValue(key)); // undefined

// ctx2 未改变
console.log(ctx2.getValue(key)); // "上下文 2"
// ctx 未改变
console.log(ctx.getValue(key)); // undefined

活动上下文

重要提示:这需要您配置上下文管理器。如果没有配置上下文管理器,api.context.active()将_始终_返回ROOT_CONTEXT

活动上下文是通过api.context.active()返回的上下文。上下文对象包含条目,允许跟踪正在追踪单个执行线程的组件进行通信,并确保成功创建追踪。例如,当创建一个 span 时,可以将其添加到上下文中。之后,当创建另一个 span 时,可以使用上下文中的 span 作为父 span。这是通过使用诸如async_hooksAsyncLocalStorage在 Node.js 中,或在 Web 上使用zone.js来传播上下文的机制实现的。如果没有活动的上下文,则返回ROOT_CONTEXT,即空的上下文对象。

获取活动上下文

活动上下文通过api.context.active()返回。

import * as api from '@opentelemetry/api';

// 返回活动上下文
// 如果没有活动上下文,则返回 ROOT_CONTEXT
const ctx = api.context.active();

设置活动上下文

可以使用api.context.with(ctx, callback)将一个上下文设置为活动上下文。在callback的执行过程中,with传递给它的上下文将会被context.active返回。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('存储值的键');
const ctx = api.context.active();

api.context.with(ctx.setValue(key, '上下文 2'), async () => {
  // "上下文 2" 是活动的
  console.log(api.context.active().getValue(key)); // "上下文 2"
});

api.context.with(context, callback)的返回值是回调的返回值。回调总是同步调用。

import * as api from '@opentelemetry/api';

const name = await api.context.with(api.context.active(), async () => {
  const row = await db.getSomeValue();
  return row['name'];
});

console.log(name); // 由数据库返回的姓名

活动上下文的执行可以是嵌套的。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('存储值的键');
const ctx = api.context.active();

// 没有活动上下文
console.log(api.context.active().getValue(key)); // undefined

api.context.with(ctx.setValue(key, '上下文 2'), () => {
  // "上下文 2" 是活动的
  console.log(api.context.active().getValue(key)); // "上下文 2"
  api.context.with(ctx.setValue(key, '上下文 3'), () => {
    // "上下文 3" 是活动的
    console.log(api.context.active().getValue(key)); // "上下文 3"
  });
  // "上下文 2" 是活动的
  console.log(api.context.active().getValue(key)); // "上下文 2"
});

// 没有活动上下文
console.log(api.context.active().getValue(key)); // undefined

示例

这个更复杂的示例演示了上下文是如何不被修改,而是创建新的上下文对象的。

import * as api from '@opentelemetry/api';

const key = api.createContextKey('存储值的键');

const ctx = api.context.active(); // 没有活动上下文时返回 ROOT_CONTEXT
const ctx2 = ctx.setValue(key, '上下文 2'); // 不修改 ctx

console.log(ctx.getValue(key)); //? undefined
console.log(ctx2.getValue(key)); //? "上下文 2"

const ret = api.context.with(ctx2, () => {
  const ctx3 = api.context.active().setValue(key, '上下文 3');

  console.log(api.context.active().getValue(key)); //? "上下文 2"
  console.log(ctx.getValue(key)); //? undefined
  console.log(ctx2.getValue(key)); //? "上下文 2"
  console.log(ctx3.getValue(key)); //? "上下文 3"

  api.context.with(ctx3, () => {
    console.log(api.context.active().getValue(key)); //? "上下文 3"
  });
  console.log(api.context.active().getValue(key)); //? "上下文 2"

  return '返回值';
});

// 回调的返回值将返回给调用方
console.log(ret); //? "返回值"
最后修改 December 10, 2023: translate (a4350d6e)