diff --git a/package-lock.json b/package-lock.json index 458ce3b64a..f51ac860b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38531,7 +38531,8 @@ "version": "0.52.0", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.208.0" + "@opentelemetry/instrumentation": "^0.208.0", + "@opentelemetry/semantic-conventions": "^1.33.0" }, "devDependencies": { "@opentelemetry/api": "^1.3.0", diff --git a/packages/instrumentation-net/README.md b/packages/instrumentation-net/README.md index 34a79082d8..e1a5a1a2ba 100644 --- a/packages/instrumentation-net/README.md +++ b/packages/instrumentation-net/README.md @@ -41,18 +41,28 @@ registerInstrumentations({ ## Semantic Conventions -This package uses `@opentelemetry/semantic-conventions` version `1.22+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) - -Attributes added to `connect` spans: - -| Attribute | Short Description | -| ------------------------- | ------------------------------------------------------------------------ | -| `net.transport` | `IP.TCP`, `pipe` or `Unix` | -| `net.peer.name` | Host name or the IPC file path | -| `net.peer.ip` (for TCP) | Remote address of the peer (dotted decimal for IPv4 or RFC5952 for IPv6) | -| `net.peer.port` (for TCP) | Remote port number | -| `net.host.ip` (for TCP) | Like net.peer.ip but for the host IP. Useful in case of a multi-IP host | -| `net.host.port` (for TCP) | Like net.peer.port but for the host port | +This instrumentation implements Semantic Conventions (semconv) v1.7.0. Since then, many networking-related semantic conventions (in semconv v1.21.0 and v1.23.1) were stabilized. As of `@opentelemetry/instrumentation-net@0.53.0` support has been added for migrating to the stable semantic conventions using the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable as follows: + +1. Upgrade to the latest version of this instrumentation package. +2. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http/dup` to emit both old and stable semantic conventions. (The [`http` token is used to control the `net.*` attributes](https://github.com/open-telemetry/opentelemetry-js/issues/5663#issuecomment-3349204546).) +3. Modify alerts, dashboards, metrics, and other processes in your Observability system to use the stable semantic conventions. +4. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http` to emit only the stable semantic conventions. + +By default, if `OTEL_SEMCONV_STABILITY_OPT_IN` is not set or does not include `http`, then the old v1.7.0 semconv is used. +The intent is to provide an approximate 6 month time window for users of this instrumentation to migrate to the new networking semconv, after which a new minor version will use the new semconv by default and drop support for the old semconv. +See [the HTTP migration guide](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/) and [deprecated network attributes](https://opentelemetry.io/docs/specs/semconv/registry/attributes/network/#deprecated-network-attributes) for details. + +Attributes collected: + +| Old semconv | Stable semconv | Description | +| --------------- | ----------------------- | --------------------------------------------------------------------------------- | +| `net.transport` | `network.transport` | One of `pipe`, `unix`, `ip_tcp` (old) or `tcp` (stable) | +| `net.peer.name` | `server.address` | Host name or the IPC file path | +| `net.peer.port` | `server.port` | Remote port number | +| `net.peer.ip` | `network.peer.address` | Peer address of the network connection - IP address or Unix domain socket name. | +| `net.host.ip` | `network.local.address` | Local address of the network connection - IP address or Unix domain socket name. | +| `net.host.port` | `network.local.port` | Local port number of the network connection. | + ## Useful links diff --git a/packages/instrumentation-net/package.json b/packages/instrumentation-net/package.json index 680e245adf..638e084ad3 100644 --- a/packages/instrumentation-net/package.json +++ b/packages/instrumentation-net/package.json @@ -51,7 +51,8 @@ "@opentelemetry/sdk-trace-node": "^2.0.0" }, "dependencies": { - "@opentelemetry/instrumentation": "^0.208.0" + "@opentelemetry/instrumentation": "^0.208.0", + "@opentelemetry/semantic-conventions": "^1.33.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-net#readme" } diff --git a/packages/instrumentation-net/src/instrumentation.ts b/packages/instrumentation-net/src/instrumentation.ts index e7743a251e..5e20f6baa2 100644 --- a/packages/instrumentation-net/src/instrumentation.ts +++ b/packages/instrumentation-net/src/instrumentation.ts @@ -14,14 +14,25 @@ * limitations under the License. */ -import { Span, SpanStatusCode, context, trace } from '@opentelemetry/api'; +import { Span, SpanStatusCode, context, trace, type Attributes } from '@opentelemetry/api'; import { InstrumentationBase, InstrumentationConfig, InstrumentationNodeModuleDefinition, isWrapped, safeExecuteInTheMiddle, + SemconvStability, + semconvStabilityFromStr, } from '@opentelemetry/instrumentation'; +import { + ATTR_NETWORK_LOCAL_ADDRESS, + ATTR_NETWORK_LOCAL_PORT, + ATTR_NETWORK_PEER_ADDRESS, + ATTR_NETWORK_TRANSPORT, + ATTR_SERVER_ADDRESS, + ATTR_SERVER_PORT, + NETWORK_TRANSPORT_VALUE_TCP, +} from '@opentelemetry/semantic-conventions'; import { ATTR_NET_HOST_IP, ATTR_NET_HOST_PORT, @@ -33,7 +44,7 @@ import { } from './semconv'; import { TLSAttributes } from './types'; import { NormalizedOptions, SocketEvent } from './internal-types'; -import { getNormalizedArgs, IPC_TRANSPORT } from './utils'; +import { getNormalizedArgs, OLD_IPC_TRANSPORT_VALUE, STABLE_IPC_TRANSPORT_VALUE } from './utils'; /** @knipignore */ import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; import { Socket } from 'net'; @@ -41,8 +52,19 @@ import { TLSSocket } from 'tls'; import type * as net from 'net'; export class NetInstrumentation extends InstrumentationBase { + private _netSemconvStability!: SemconvStability; + constructor(config: InstrumentationConfig = {}) { super(PACKAGE_NAME, PACKAGE_VERSION, config); + this._setSemconvStabilityFromEnv(); + } + + // Used for testing. + private _setSemconvStabilityFromEnv() { + this._netSemconvStability = semconvStabilityFromStr( + 'http', + process.env.OTEL_SEMCONV_STABILITY_OPT_IN + ); } init(): InstrumentationNodeModuleDefinition[] { @@ -182,34 +204,43 @@ export class NetInstrumentation extends InstrumentationBase { private _startGenericSpan(socket: Socket) { const span = this.tracer.startSpan('connect'); - registerListeners(socket, span); + registerListeners(socket, span, false, this._netSemconvStability); return span; } private _startIpcSpan(options: NormalizedOptions, socket: Socket) { - const span = this.tracer.startSpan('ipc.connect', { - attributes: { - [ATTR_NET_TRANSPORT]: IPC_TRANSPORT, - [ATTR_NET_PEER_NAME]: options.path, - }, - }); + const attributes: Attributes = {}; + if (this._netSemconvStability & SemconvStability.OLD) { + attributes[ATTR_NET_TRANSPORT] = OLD_IPC_TRANSPORT_VALUE; + attributes[ATTR_NET_PEER_NAME] = options.path; + } + if (this._netSemconvStability & SemconvStability.STABLE) { + attributes[ATTR_NETWORK_TRANSPORT] = STABLE_IPC_TRANSPORT_VALUE; + attributes[ATTR_SERVER_ADDRESS] = options.path; + } + const span = this.tracer.startSpan('ipc.connect', { attributes }); - registerListeners(socket, span); + registerListeners(socket, span, false, this._netSemconvStability); return span; } private _startTcpSpan(options: NormalizedOptions, socket: Socket) { - const span = this.tracer.startSpan('tcp.connect', { - attributes: { - [ATTR_NET_TRANSPORT]: NET_TRANSPORT_VALUE_IP_TCP, - [ATTR_NET_PEER_NAME]: options.host, - [ATTR_NET_PEER_PORT]: options.port, - }, - }); + const attributes: Attributes = {}; + if (this._netSemconvStability & SemconvStability.OLD) { + attributes[ATTR_NET_TRANSPORT] = NET_TRANSPORT_VALUE_IP_TCP; + attributes[ATTR_NET_PEER_NAME] = options.host; + attributes[ATTR_NET_PEER_PORT] = options.port; + } + if (this._netSemconvStability & SemconvStability.STABLE) { + attributes[ATTR_NETWORK_TRANSPORT] = NETWORK_TRANSPORT_VALUE_TCP; + attributes[ATTR_SERVER_ADDRESS] = options.host; + attributes[ATTR_SERVER_PORT] = options.port; + } + const span = this.tracer.startSpan('tcp.connect', { attributes }); - registerListeners(socket, span, { hostAttributes: true }); + registerListeners(socket, span, true, this._netSemconvStability); return span; } @@ -239,17 +270,25 @@ function spanErrorHandler(span: Span) { function registerListeners( socket: Socket, span: Span, - { hostAttributes = false }: { hostAttributes?: boolean } = {} + hostAttributes: boolean, + netSemconvStability: SemconvStability, ) { const setSpanError = spanErrorHandler(span); const setSpanEnd = spanEndHandler(span); const setHostAttributes = () => { - span.setAttributes({ - [ATTR_NET_PEER_IP]: socket.remoteAddress, - [ATTR_NET_HOST_IP]: socket.localAddress, - [ATTR_NET_HOST_PORT]: socket.localPort, - }); + const attributes: Attributes = {}; + if (netSemconvStability & SemconvStability.OLD) { + attributes[ATTR_NET_PEER_IP] = socket.remoteAddress; + attributes[ATTR_NET_HOST_IP] = socket.localAddress; + attributes[ATTR_NET_HOST_PORT] = socket.localPort; + } + if (netSemconvStability & SemconvStability.STABLE) { + attributes[ATTR_NETWORK_PEER_ADDRESS] = socket.remoteAddress; + attributes[ATTR_NETWORK_LOCAL_ADDRESS] = socket.localAddress; + attributes[ATTR_NETWORK_LOCAL_PORT] = socket.localPort; + } + span.setAttributes(attributes); }; socket.once(SocketEvent.ERROR, setSpanError); diff --git a/packages/instrumentation-net/src/utils.ts b/packages/instrumentation-net/src/utils.ts index 24533d1f29..e5d2557a44 100644 --- a/packages/instrumentation-net/src/utils.ts +++ b/packages/instrumentation-net/src/utils.ts @@ -14,21 +14,21 @@ * limitations under the License. */ +import { platform } from 'os'; +import { + NETWORK_TRANSPORT_VALUE_PIPE, + NETWORK_TRANSPORT_VALUE_UNIX, +} from '@opentelemetry/semantic-conventions'; import { NormalizedOptions } from './internal-types'; import { NET_TRANSPORT_VALUE_PIPE } from './semconv'; -import { platform } from 'os'; -// Currently the `IPC_TRANSPORT` values are for 'net.transport'. In semconv -// v1.21.0 a breaking change (https://github.com/open-telemetry/opentelemetry-specification/pull/3426) -// replaced 'net.transport' with 'network.transport'. The deprecated -// 'net.transport' *removed* the 'unix' value (not sure if intentional). As a -// result, the JS `@opentelemetry/semantic-conventions` package does not export -// a `NET_TRANSPORT_VALUE_UNIX`. -// -// (TODO: update instrumentation-net (per PR-3426) to use 'network.transport', -// then the `NETWORK_TRANSPORT_VALUE_UNIX` constant can be used.) -export const IPC_TRANSPORT = +// There is no `NET_TRANSPORT_VALUE_UNIX` because breaking change +// https://github.com/open-telemetry/opentelemetry-specification/pull/3426 +// *removed* it. This was from before semconv got more careful of removals. +export const OLD_IPC_TRANSPORT_VALUE = platform() === 'win32' ? NET_TRANSPORT_VALUE_PIPE : 'unix'; +export const STABLE_IPC_TRANSPORT_VALUE = + platform() === 'win32' ? NETWORK_TRANSPORT_VALUE_PIPE : NETWORK_TRANSPORT_VALUE_UNIX; function getHost(args: unknown[]) { return typeof args[1] === 'string' ? args[1] : 'localhost'; diff --git a/packages/instrumentation-net/test/connect.test.ts b/packages/instrumentation-net/test/connect.test.ts index d69703ef79..4843076b72 100644 --- a/packages/instrumentation-net/test/connect.test.ts +++ b/packages/instrumentation-net/test/connect.test.ts @@ -19,14 +19,19 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/sdk-trace-base'; -import { ATTR_NET_TRANSPORT } from '../src/semconv'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { SemconvStability } from '@opentelemetry/instrumentation'; import * as net from 'net'; import * as assert from 'assert'; import { NetInstrumentation } from '../src'; import { SocketEvent } from '../src/internal-types'; import { assertIpcSpan, assertTcpSpan, IPC_PATH, HOST, PORT } from './utils'; +// By default tests run with both old and stable semconv. Some test cases +// specifically test the various values of OTEL_SEMCONV_STABILITY_OPT_IN. +process.env.OTEL_SEMCONV_STABILITY_OPT_IN = 'http/dup'; +const DEFAULT_NET_SEMCONV_STABILITY = SemconvStability.DUPLICATE; + const memoryExporter = new InMemorySpanExporter(); const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(memoryExporter)], @@ -79,14 +84,14 @@ describe('NetInstrumentation', () => { describe('successful net.connect produces a span', () => { it('should produce a span given port and host', done => { socket = net.connect(PORT, HOST, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); it('should produce a span for IPC', done => { socket = net.connect(IPC_PATH, () => { - assertIpcSpan(getSpan()); + assertIpcSpan(getSpan(), DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); @@ -98,7 +103,7 @@ describe('NetInstrumentation', () => { host: HOST, }, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); } ); @@ -108,14 +113,14 @@ describe('NetInstrumentation', () => { describe('successful net.createConnection produces a span', () => { it('should produce a span given port and host', done => { socket = net.createConnection(PORT, HOST, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); it('should produce a span for IPC', done => { socket = net.createConnection(IPC_PATH, () => { - assertIpcSpan(getSpan()); + assertIpcSpan(getSpan(), DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); @@ -127,7 +132,7 @@ describe('NetInstrumentation', () => { host: HOST, }, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); } ); @@ -137,21 +142,21 @@ describe('NetInstrumentation', () => { describe('successful Socket.connect produces a span', () => { it('should produce a span given port and host', done => { socket.connect(PORT, HOST, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); it('should produce a span for IPC', done => { socket.connect(IPC_PATH, () => { - assertIpcSpan(getSpan()); + assertIpcSpan(getSpan(), DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); it('should create a tcp span when port is given as string', done => { socket = socket.connect(String(PORT) as unknown as number, HOST, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); @@ -163,7 +168,7 @@ describe('NetInstrumentation', () => { host: HOST, }, () => { - assertTcpSpan(getSpan(), socket); + assertTcpSpan(getSpan(), socket, DEFAULT_NET_SEMCONV_STABILITY); done(); } ); @@ -186,7 +191,7 @@ describe('NetInstrumentation', () => { const assertSpan = () => { try { const span = getSpan(); - assert.strictEqual(span.attributes[ATTR_NET_TRANSPORT], undefined); + assert.deepEqual(span.attributes, {}); assert.strictEqual(span.status.code, SpanStatusCode.ERROR); done(); } catch (e) { @@ -209,6 +214,58 @@ describe('NetInstrumentation', () => { }); }); + describe('various values of OTEL_SEMCONV_STABILITY_OPT_IN', () => { + const _origOptInEnv = process.env.OTEL_SEMCONV_STABILITY_OPT_IN; + after(() => { + process.env.OTEL_SEMCONV_STABILITY_OPT_IN = _origOptInEnv; + (instrumentation as any)._setSemconvStabilityFromEnv(); + }); + + it('tcp with OTEL_SEMCONV_STABILITY_OPT_IN=(empty)', (done) => { + process.env.OTEL_SEMCONV_STABILITY_OPT_IN = ''; + (instrumentation as any)._setSemconvStabilityFromEnv(); + memoryExporter.reset(); + + socket = net.connect(PORT, HOST, () => { + assertTcpSpan(getSpan(), socket, SemconvStability.OLD); + done(); + }); + }); + + it('tcp with OTEL_SEMCONV_STABILITY_OPT_IN=http', (done) => { + process.env.OTEL_SEMCONV_STABILITY_OPT_IN = 'http'; + (instrumentation as any)._setSemconvStabilityFromEnv(); + memoryExporter.reset(); + + socket = net.connect(PORT, HOST, () => { + assertTcpSpan(getSpan(), socket, SemconvStability.STABLE); + done(); + }); + }); + + it('ipc with OTEL_SEMCONV_STABILITY_OPT_IN=(empty)', (done) => { + process.env.OTEL_SEMCONV_STABILITY_OPT_IN = ''; + (instrumentation as any)._setSemconvStabilityFromEnv(); + memoryExporter.reset(); + + socket.connect(IPC_PATH, () => { + assertIpcSpan(getSpan(), SemconvStability.OLD); + done(); + }); + }); + + it('ipc with OTEL_SEMCONV_STABILITY_OPT_IN=http', (done) => { + process.env.OTEL_SEMCONV_STABILITY_OPT_IN = 'http'; + (instrumentation as any)._setSemconvStabilityFromEnv(); + memoryExporter.reset(); + + socket.connect(IPC_PATH, () => { + assertIpcSpan(getSpan(), SemconvStability.STABLE); + done(); + }); + }); + }); + describe('cleanup', () => { function assertNoDanglingListeners() { const events = new Set(socket.eventNames()); diff --git a/packages/instrumentation-net/test/tls.test.ts b/packages/instrumentation-net/test/tls.test.ts index 65ea58e0ac..daa50855ac 100644 --- a/packages/instrumentation-net/test/tls.test.ts +++ b/packages/instrumentation-net/test/tls.test.ts @@ -21,6 +21,7 @@ import { } from '@opentelemetry/sdk-trace-base'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { SemconvStability } from '@opentelemetry/instrumentation'; import * as assert from 'assert'; import * as tls from 'tls'; import { NetInstrumentation } from '../src'; @@ -33,6 +34,10 @@ import { PORT, } from './utils'; +// By default tests run with both old and stable semconv. +process.env.OTEL_SEMCONV_STABILITY_OPT_IN = 'http/dup'; +const DEFAULT_NET_SEMCONV_STABILITY = SemconvStability.DUPLICATE; + const memoryExporter = new InMemorySpanExporter(); const provider = new NodeTracerProvider({ spanProcessors: [new SimpleSpanProcessor(memoryExporter)], @@ -95,7 +100,7 @@ describe('NetInstrumentation', () => { }, }, () => { - assertTLSSpan(getTLSSpans(), tlsSocket); + assertTLSSpan(getTLSSpans(), tlsSocket, DEFAULT_NET_SEMCONV_STABILITY); done(); } ); @@ -112,7 +117,7 @@ describe('NetInstrumentation', () => { c.end(); }); tlsSocket.once('end', () => { - assertTLSSpan(getTLSSpans(), tlsSocket); + assertTLSSpan(getTLSSpans(), tlsSocket, DEFAULT_NET_SEMCONV_STABILITY); done(); }); }); @@ -128,7 +133,7 @@ describe('NetInstrumentation', () => { }, }, () => { - assertTLSSpan(getTLSSpans(), tlsSocket); + assertTLSSpan(getTLSSpans(), tlsSocket, DEFAULT_NET_SEMCONV_STABILITY); done(); } ); diff --git a/packages/instrumentation-net/test/utils.ts b/packages/instrumentation-net/test/utils.ts index 48498cc08c..bd1860129e 100644 --- a/packages/instrumentation-net/test/utils.ts +++ b/packages/instrumentation-net/test/utils.ts @@ -14,11 +14,14 @@ * limitations under the License. */ -import { SpanKind } from '@opentelemetry/api'; +import { SpanKind, type Attributes } from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; +import { SemconvStability } from '@opentelemetry/instrumentation'; +import { ATTR_NETWORK_LOCAL_ADDRESS, ATTR_NETWORK_LOCAL_PORT, ATTR_NETWORK_PEER_ADDRESS, ATTR_NETWORK_TRANSPORT, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, NETWORK_TRANSPORT_VALUE_TCP } from '@opentelemetry/semantic-conventions'; import { ATTR_NET_HOST_IP, ATTR_NET_HOST_PORT, + ATTR_NET_PEER_IP, ATTR_NET_PEER_NAME, ATTR_NET_PEER_PORT, ATTR_NET_TRANSPORT, @@ -28,7 +31,7 @@ import * as assert from 'assert'; import * as path from 'path'; import * as os from 'os'; import { Socket } from 'net'; -import { IPC_TRANSPORT } from '../src/utils'; +import { OLD_IPC_TRANSPORT_VALUE, STABLE_IPC_TRANSPORT_VALUE } from '../src/utils'; import { TLSAttributes } from '../src/types'; import * as fs from 'fs'; @@ -39,34 +42,65 @@ export const IPC_PATH = ? path.join(os.tmpdir(), 'otel-js-net-test-ipc') : '\\\\.\\pipe\\otel-js-net-test-ipc'; -export function assertTcpSpan(span: ReadableSpan, socket: Socket) { +export function assertTcpSpan(span: ReadableSpan, socket: Socket, netSemconvStability: SemconvStability) { assertSpanKind(span); - assertAttrib(span, ATTR_NET_TRANSPORT, NET_TRANSPORT_VALUE_IP_TCP); - assertAttrib(span, ATTR_NET_PEER_NAME, HOST); - assertAttrib(span, ATTR_NET_PEER_PORT, PORT); - assertAttrib(span, ATTR_NET_HOST_IP, socket.localAddress); - assertAttrib(span, ATTR_NET_HOST_PORT, socket.localPort); + + const attributes: Attributes = {}; + if (netSemconvStability & SemconvStability.OLD) { + attributes[ATTR_NET_TRANSPORT] = NET_TRANSPORT_VALUE_IP_TCP; + attributes[ATTR_NET_PEER_NAME] = HOST; + attributes[ATTR_NET_PEER_PORT] = PORT; + attributes[ATTR_NET_PEER_IP] = socket.remoteAddress; + attributes[ATTR_NET_HOST_IP] = socket.localAddress; + attributes[ATTR_NET_HOST_PORT] = socket.localPort; + } + if (netSemconvStability & SemconvStability.STABLE) { + attributes[ATTR_NETWORK_TRANSPORT] = NETWORK_TRANSPORT_VALUE_TCP; + attributes[ATTR_SERVER_ADDRESS] = HOST; + attributes[ATTR_SERVER_PORT] = PORT; + attributes[ATTR_NETWORK_PEER_ADDRESS] = socket.remoteAddress; + attributes[ATTR_NETWORK_LOCAL_ADDRESS] = socket.localAddress; + attributes[ATTR_NETWORK_LOCAL_PORT] = socket.localPort; + } + assert.deepEqual(span.attributes, attributes); } -export function assertIpcSpan(span: ReadableSpan) { +export function assertIpcSpan(span: ReadableSpan, netSemconvStability: SemconvStability) { assertSpanKind(span); - assertAttrib(span, ATTR_NET_TRANSPORT, IPC_TRANSPORT); - assertAttrib(span, ATTR_NET_PEER_NAME, IPC_PATH); + const attributes: Attributes = {}; + if (netSemconvStability & SemconvStability.OLD) { + attributes[ATTR_NET_TRANSPORT] = OLD_IPC_TRANSPORT_VALUE; + attributes[ATTR_NET_PEER_NAME] = IPC_PATH; + } + if (netSemconvStability & SemconvStability.STABLE) { + attributes[ATTR_NETWORK_TRANSPORT] = STABLE_IPC_TRANSPORT_VALUE; + attributes[ATTR_SERVER_ADDRESS] = IPC_PATH; + } + assert.deepEqual(span.attributes, attributes); } export function assertTLSSpan( { netSpan, tlsSpan }: { netSpan: ReadableSpan; tlsSpan: ReadableSpan }, - socket: Socket + _socket: Socket, + netSemconvStability: SemconvStability, ) { assertParentChild(tlsSpan, netSpan); assertSpanKind(netSpan); - assertAttrib(netSpan, ATTR_NET_TRANSPORT, NET_TRANSPORT_VALUE_IP_TCP); - assertAttrib(netSpan, ATTR_NET_PEER_NAME, HOST); - assertAttrib(netSpan, ATTR_NET_PEER_PORT, PORT); - // Node.JS 10 sets socket.localAddress & socket.localPort to "undefined" when a connection is - // ended, so one of the tests fails, so we skip them for TLS - // assertAttrib(span, ATTR_NET_HOST_IP, socket.localAddress); - //assertAttrib(netSpan, ATTR_NET_HOST_PORT, socket.localPort); + + if (netSemconvStability & SemconvStability.OLD) { + assertAttrib(netSpan, ATTR_NET_TRANSPORT, NET_TRANSPORT_VALUE_IP_TCP); + assertAttrib(netSpan, ATTR_NET_PEER_NAME, HOST); + assertAttrib(netSpan, ATTR_NET_PEER_PORT, PORT); + // Node.JS 10 sets socket.localAddress & socket.localPort to "undefined" when a connection is + // ended, so one of the tests fails, so we skip them for TLS + // assertAttrib(span, ATTR_NET_HOST_IP, socket.localAddress); + //assertAttrib(netSpan, ATTR_NET_HOST_PORT, socket.localPort); + } + if (netSemconvStability & SemconvStability.STABLE) { + assertAttrib(netSpan, ATTR_NETWORK_TRANSPORT, NETWORK_TRANSPORT_VALUE_TCP); + assertAttrib(netSpan, ATTR_SERVER_ADDRESS, HOST); + assertAttrib(netSpan, ATTR_SERVER_PORT, PORT); + } assertAttrib(tlsSpan, TLSAttributes.PROTOCOL, 'TLSv1.2'); assertAttrib(tlsSpan, TLSAttributes.AUTHORIZED, 'true');