Axios HTTP 后端调用生成与父 span 不相关的 Opentelemetry span

问题描述 投票:0回答:1

我正在尝试使用 opentelemetry 在 NodeJs (v18.16.1) 中执行手动检测。该场景非常简单,我正在对虚拟 JSON API 进行 axios HTTP 调用,并且我想收集生成的跟踪。

依赖关系:

  "@opentelemetry/api": "^1.3.0",
  "@opentelemetry/auto-instrumentations-node": "^0.38.0",
  "@opentelemetry/context-async-hooks": "^1.15.0",
  "@opentelemetry/instrumentation": "^0.41.0",
  "@opentelemetry/instrumentation-http": "^0.35.1",
  "@opentelemetry/resources": "^1.9.1",
  "@opentelemetry/sdk-metrics": "^1.9.1",
  "@opentelemetry/sdk-node": "^0.35.1",
  "@opentelemetry/sdk-trace-base": "^1.9.1",
  "@opentelemetry/sdk-trace-node": "^1.9.1",
  "@opentelemetry/semantic-conventions": "^1.9.1",
  "axios": "^1.4.0"

设置如下:

otel/tracing.js
文件:

const opentelemetry = require('@opentelemetry/api')
const { Resource } = require("@opentelemetry/resources");
const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions");
const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
const { registerInstrumentations } = require("@opentelemetry/instrumentation");
const { ConsoleSpanExporter, SimpleSpanProcessor} = require("@opentelemetry/sdk-trace-base");
const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks');
const {
    HttpInstrumentation,
} = require("@opentelemetry/instrumentation-http");


const contextManager = new AsyncHooksContextManager();

contextManager.enable()

opentelemetry.context.setGlobalContextManager(contextManager)


registerInstrumentations({
    instrumentations: [new HttpInstrumentation()],
});

const resource =
    Resource.default().merge(
        new Resource({
            [SemanticResourceAttributes.SERVICE_NAME]: 'poc-otel-tracing',
            [SemanticResourceAttributes.SERVICE_VERSION]: "0.1.0",
        })
    );

const provider = new NodeTracerProvider({
    resource: resource
});

const exporter = new ConsoleSpanExporter();
const processor = new SimpleSpanProcessor(exporter);


provider.addSpanProcessor(processor);

provider.register();

// process.on('exit', function() {
//     void exporter.shutdown()
// });

src/index.ts
文件

import axios from "axios";

import opentelemetry, {Span} from "@opentelemetry/api";
const tracer = opentelemetry.trace.getTracer('poc-otel-tracing');

const API_BASE_URL = 'https://jsonplaceholder.typicode.com/posts';

const func = async() => {

    const rootSpan = tracer.startSpan('root-span')
    await apiCall(rootSpan)
    rootSpan.end()
}

const apiCall = async (parentSpan: Span) => {

    const ctx = opentelemetry.trace.setSpan(opentelemetry.context.active(), parentSpan)

    const childSpan = tracer.startSpan('api-call', undefined, ctx)

    try {
        await axios.get(API_BASE_URL);
    } catch (e) {
        childSpan.recordException(e);
    }

    childSpan.end()
}

void func()

请注意,我使用的是 typescript,并且我使用

npm run build && node --require "./otel/tracing.js" dist/index.js
来运行已编译的 JS 并需要 otel/tracing.js 脚本。

控制台输出如下:

{
  traceId: '15b261f7332feb1fdc79cff5a280529b',
  parentId: undefined,
  traceState: undefined,
  name: 'HTTPS GET',
  id: '477643c3a9536749',
  kind: 2,
  timestamp: 1690206903281000,
  duration: 128485,
  attributes: {
    'http.url': 'https://jsonplaceholder.typicode.com/posts',
    'http.method': 'GET',
    'http.target': '/posts',
    'net.peer.name': 'jsonplaceholder.typicode.com',
    'http.host': 'jsonplaceholder.typicode.com:443',
    'net.peer.ip': '172.64.162.6',
    'net.peer.port': 443,
    'http.status_code': 200,
    'http.status_text': 'OK',
    'http.flavor': '1.1',
    'net.transport': 'ip_tcp'
  },
  status: { code: 0 },
  events: [],
  links: []
}
{
  traceId: 'ba35dbc454728c2bbc5b30a435dec3bb',
  parentId: 'a3897743fb82276c',
  traceState: undefined,
  name: 'api-call',
  id: 'ec3d00cb4ad95d26',
  kind: 0,
  timestamp: 1690206903278000,
  duration: 136158,
  attributes: {},
  status: { code: 0 },
  events: [],
  links: []
}
{
  traceId: 'ba35dbc454728c2bbc5b30a435dec3bb',
  parentId: undefined,
  traceState: undefined,
  name: 'root-span',
  id: 'a3897743fb82276c',
  kind: 0,
  timestamp: 1690206903278000,
  duration: 136633,
  attributes: {},
  status: { code: 0 },
  events: [],
  links: []
}

我不明白为什么为 axios http 调用创建的跨度与“api-call”跨度不相关(即 axios 生成的跨度应该以“api-call”作为父跨度)并且应该是相同的痕迹。

这是我期望的输出:

{
  traceId: 'ba35dbc454728c2bbc5b30a435dec3bb',
  parentId: 'a3897743fb82276c',
  traceState: undefined,
  name: 'HTTPS GET',
  id: '477643c3a9536749',
  kind: 2,
  timestamp: 1690206903281000,
  duration: 128485,
  attributes: {
    'http.url': 'https://jsonplaceholder.typicode.com/posts',
    'http.method': 'GET',
    'http.target': '/posts',
    'net.peer.name': 'jsonplaceholder.typicode.com',
    'http.host': 'jsonplaceholder.typicode.com:443',
    'net.peer.ip': '172.64.162.6',
    'net.peer.port': 443,
    'http.status_code': 200,
    'http.status_text': 'OK',
    'http.flavor': '1.1',
    'net.transport': 'ip_tcp'
  },
  status: { code: 0 },
  events: [],
  links: []
}
{
  traceId: 'ba35dbc454728c2bbc5b30a435dec3bb',
  parentId: 'a3897743fb82276c',
  traceState: undefined,
  name: 'api-call',
  id: 'ec3d00cb4ad95d26',
  kind: 0,
  timestamp: 1690206903278000,
  duration: 136158,
  attributes: {},
  status: { code: 0 },
  events: [],
  links: []
}
{
  traceId: 'ba35dbc454728c2bbc5b30a435dec3bb',
  parentId: undefined,
  traceState: undefined,
  name: 'root-span',
  id: 'a3897743fb82276c',
  kind: 0,
  timestamp: 1690206903278000,
  duration: 136633,
  attributes: {},
  status: { code: 0 },
  events: [],
  links: []
}

有人可以帮助我理解我做错了什么吗? 预先感谢!

node.js axios instrumentation open-telemetry observability
1个回答
0
投票

原因:跟踪信息未传播到请求(在您的情况下通过 axios)

修复: 从上下文中提取跟踪信息,并将其注入请求标头

const traceHeaders = {};
// inject context to trace headers for propagtion to the next service
propagation.inject(context.active(), traceHeaders);
// pass the trace headers to your request
const config = {
  headers: traceHeaders
};
await axios.get(API_BASE_URL, config);

希望它对你有用。 如果您需要,我在here记录了详细的设置,并提供了完整源代码的链接

© www.soinside.com 2019 - 2024. All rights reserved.