Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 22 additions & 12 deletions packages/instrumentation-net/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]` 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

Expand Down
3 changes: 2 additions & 1 deletion packages/instrumentation-net/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
87 changes: 63 additions & 24 deletions packages/instrumentation-net/src/instrumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -33,16 +44,27 @@ 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';
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[] {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
22 changes: 11 additions & 11 deletions packages/instrumentation-net/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Loading
Loading