Skip to content

Commit ba03a94

Browse files
feat(instr-cassandra-driver): support net.* and db semconv migration (#3302)
1 parent 66935ac commit ba03a94

File tree

6 files changed

+221
-88
lines changed

6 files changed

+221
-88
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/instrumentation-cassandra-driver/README.md

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,27 @@ await client.execute('select * from foo');
5151

5252
## Semantic Conventions
5353

54-
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)
55-
56-
Attributes collected:
57-
58-
| Attribute | Short Description |
59-
| ----------------------- | ------------------------------------------------------------------------------ |
60-
| `db.name` | This attribute is used to report the name of the database being accessed. |
61-
| `db.statement` | The database statement being executed. |
62-
| `db.system` | An identifier for the database management system (DBMS) product being used. |
63-
| `db.user` | Username for accessing the database. |
64-
| `net.peer.name` | Remote hostname or similar. |
65-
| `net.peer.port` | Remote port number. |
54+
This instrumentation implements Semantic Conventions (semconv) v1.7.0. Since then, networking (in semconv v1.23.1) and database (in semconv v1.33.0) semantic conventions 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:
55+
56+
1. Upgrade to the latest version of this instrumentation package.
57+
2. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http/dup,database/dup` to emit both old and stable semantic conventions. (The `http` token is used to control the `net.*` attributes, the `database` token to control the `db.*` attributes.)
58+
3. Modify alerts, dashboards, metrics, and other processes in your Observability system to use the stable semantic conventions.
59+
4. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http,database` to emit only the stable semantic conventions.
60+
61+
By default, if `OTEL_SEMCONV_STABILITY_OPT_IN` includes neither of the above tokens, 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 database and networking semconv, after which a new minor version will use the new semconv by default and drop support for the old semconv.
62+
63+
See [the HTTP migration guide](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/) and the [database migration guide](https://opentelemetry.io/docs/specs/semconv/non-normative/db-migration/) for details.
64+
65+
### Attributes
66+
67+
| Old semconv | Stable semconv | Description |
68+
| --------------- | ---------------- | --------------------------------------- |
69+
| `db.system` | `db.system.name` | Database system identifier (cassandra). |
70+
| `db.statement` | `db.query.text` | The database query being executed. |
71+
| `db.name` | `db.namespace` | The keyspace being accessed. |
72+
| `db.user` | _(removed)_ | Username for accessing the database. |
73+
| `net.peer.name` | `server.address` | Remote hostname or similar. |
74+
| `net.peer.port` | `server.port` | Remote port number. |
6675

6776
## Useful links
6877

packages/instrumentation-cassandra-driver/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@
5555
"@opentelemetry/contrib-test-utils": "^0.56.0",
5656
"@opentelemetry/sdk-trace-base": "^2.0.0",
5757
"@opentelemetry/sdk-trace-node": "^2.0.0",
58-
"@opentelemetry/semantic-conventions": "^1.37.0",
5958
"cassandra-driver": "4.6.4"
6059
},
6160
"dependencies": {
62-
"@opentelemetry/instrumentation": "^0.208.0"
61+
"@opentelemetry/instrumentation": "^0.208.0",
62+
"@opentelemetry/semantic-conventions": "^1.37.0"
6363
},
6464
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-cassandra-driver#readme"
6565
}

packages/instrumentation-cassandra-driver/src/instrumentation.ts

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
InstrumentationNodeModuleFile,
2929
isWrapped,
3030
safeExecuteInTheMiddle,
31+
SemconvStability,
32+
semconvStabilityFromStr,
3133
} from '@opentelemetry/instrumentation';
3234
import { CassandraDriverInstrumentationConfig, ResultSet } from './types';
3335
import {
@@ -38,7 +40,15 @@ import {
3840
ATTR_DB_USER,
3941
ATTR_NET_PEER_NAME,
4042
ATTR_NET_PEER_PORT,
43+
DB_SYSTEM_NAME_VALUE_CASSANDRA,
4144
} from './semconv';
45+
import {
46+
ATTR_DB_NAMESPACE,
47+
ATTR_DB_QUERY_TEXT,
48+
ATTR_DB_SYSTEM_NAME,
49+
ATTR_SERVER_ADDRESS,
50+
ATTR_SERVER_PORT,
51+
} from '@opentelemetry/semantic-conventions';
4252
/** @knipignore */
4353
import { PACKAGE_NAME, PACKAGE_VERSION } from './version';
4454
import { EventEmitter } from 'events';
@@ -47,8 +57,23 @@ import type * as CassandraDriver from 'cassandra-driver';
4757
const supportedVersions = ['>=4.4.0 <5'];
4858

4959
export class CassandraDriverInstrumentation extends InstrumentationBase<CassandraDriverInstrumentationConfig> {
60+
private _netSemconvStability!: SemconvStability;
61+
private _dbSemconvStability!: SemconvStability;
62+
5063
constructor(config: CassandraDriverInstrumentationConfig = {}) {
5164
super(PACKAGE_NAME, PACKAGE_VERSION, config);
65+
this._setSemconvStabilityFromEnv();
66+
}
67+
68+
private _setSemconvStabilityFromEnv() {
69+
this._netSemconvStability = semconvStabilityFromStr(
70+
'http',
71+
process.env.OTEL_SEMCONV_STABILITY_OPT_IN
72+
);
73+
this._dbSemconvStability = semconvStabilityFromStr(
74+
'database',
75+
process.env.OTEL_SEMCONV_STABILITY_OPT_IN
76+
);
5277
}
5378

5479
protected init() {
@@ -166,6 +191,7 @@ export class CassandraDriverInstrumentation extends InstrumentationBase<Cassandr
166191

167192
private _getPatchedSendOnConnection() {
168193
return (original: (...args: unknown[]) => unknown) => {
194+
const plugin = this;
169195
// eslint-disable-next-line @typescript-eslint/no-explicit-any
170196
return function patchedSendOnConnection(this: any, ...args: unknown[]) {
171197
const span = trace.getSpan(context.active());
@@ -174,10 +200,17 @@ export class CassandraDriverInstrumentation extends InstrumentationBase<Cassandr
174200
if (span !== undefined && conn !== undefined) {
175201
const port = parseInt(conn.port, 10);
176202

177-
span.setAttribute(ATTR_NET_PEER_NAME, conn.address);
178-
179-
if (!isNaN(port)) {
180-
span.setAttribute(ATTR_NET_PEER_PORT, port);
203+
if (plugin._netSemconvStability & SemconvStability.OLD) {
204+
span.setAttribute(ATTR_NET_PEER_NAME, conn.address);
205+
if (!isNaN(port)) {
206+
span.setAttribute(ATTR_NET_PEER_PORT, port);
207+
}
208+
}
209+
if (plugin._netSemconvStability & SemconvStability.STABLE) {
210+
span.setAttribute(ATTR_SERVER_ADDRESS, conn.address);
211+
if (!isNaN(port)) {
212+
span.setAttribute(ATTR_SERVER_PORT, port);
213+
}
181214
}
182215
}
183216

@@ -234,10 +267,12 @@ export class CassandraDriverInstrumentation extends InstrumentationBase<Cassandr
234267

235268
const batchPromise = safeExecuteInTheMiddle(
236269
() => {
237-
return original.apply(
238-
this,
239-
args
240-
) as Promise<CassandraDriver.types.ResultSet>;
270+
return context.with(batchContext, () => {
271+
return original.apply(
272+
this,
273+
args
274+
) as Promise<CassandraDriver.types.ResultSet>;
275+
});
241276
},
242277
error => {
243278
if (error) {
@@ -285,10 +320,12 @@ export class CassandraDriverInstrumentation extends InstrumentationBase<Cassandr
285320
};
286321
args[3] = wrappedCallback;
287322
}
288-
323+
const streamContext = trace.setSpan(context.active(), span);
289324
return safeExecuteInTheMiddle(
290325
() => {
291-
return original.apply(this, args);
326+
return context.with(streamContext, () => {
327+
return original.apply(this, args);
328+
});
292329
},
293330
error => {
294331
if (error) {
@@ -304,24 +341,39 @@ export class CassandraDriverInstrumentation extends InstrumentationBase<Cassandr
304341
{ op, query }: { op: string; query?: unknown },
305342
client: CassandraDriver.Client
306343
): Span {
307-
const attributes: Attributes = {
308-
[ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_CASSANDRA,
309-
};
344+
const attributes: Attributes = {};
345+
346+
if (this._dbSemconvStability & SemconvStability.OLD) {
347+
attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_CASSANDRA;
348+
}
349+
if (this._dbSemconvStability & SemconvStability.STABLE) {
350+
attributes[ATTR_DB_SYSTEM_NAME] = DB_SYSTEM_NAME_VALUE_CASSANDRA;
351+
}
310352

311353
if (this._shouldIncludeDbStatement() && query !== undefined) {
312354
const statement = truncateQuery(query, this._getMaxQueryLength());
313-
attributes[ATTR_DB_STATEMENT] = statement;
355+
if (this._dbSemconvStability & SemconvStability.OLD) {
356+
attributes[ATTR_DB_STATEMENT] = statement;
357+
}
358+
if (this._dbSemconvStability & SemconvStability.STABLE) {
359+
attributes[ATTR_DB_QUERY_TEXT] = statement;
360+
}
314361
}
315362

363+
// db.user (deprecated, no stable replacement - only emit with OLD)
316364
// eslint-disable-next-line @typescript-eslint/no-explicit-any
317365
const user = (client as any).options?.credentials?.username;
318-
319-
if (user) {
366+
if (user && this._dbSemconvStability & SemconvStability.OLD) {
320367
attributes[ATTR_DB_USER] = user;
321368
}
322369

323370
if (client.keyspace) {
324-
attributes[ATTR_DB_NAME] = client.keyspace;
371+
if (this._dbSemconvStability & SemconvStability.OLD) {
372+
attributes[ATTR_DB_NAME] = client.keyspace;
373+
}
374+
if (this._dbSemconvStability & SemconvStability.STABLE) {
375+
attributes[ATTR_DB_NAMESPACE] = client.keyspace;
376+
}
325377
}
326378

327379
return this.tracer.startSpan(`cassandra-driver.${op}`, {

packages/instrumentation-cassandra-driver/src/semconv.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,12 @@ export const ATTR_NET_PEER_PORT = 'net.peer.port' as const;
9595
* @experimental This enum value is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
9696
*/
9797
export const DB_SYSTEM_VALUE_CASSANDRA = 'cassandra' as const;
98+
99+
/**
100+
* Enum value "cassandra" for attribute {@link ATTR_DB_SYSTEM_NAME}.
101+
*
102+
* [Apache Cassandra](https://cassandra.apache.org/)
103+
*
104+
* @experimental This enum value is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
105+
*/
106+
export const DB_SYSTEM_NAME_VALUE_CASSANDRA = 'cassandra' as const;

0 commit comments

Comments
 (0)