@opentelemetry/instrumentation-tedious 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,19 +42,36 @@ registerInstrumentations({
42
42
 
43
43
  ## Semantic Conventions
44
44
 
45
- 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)
45
+ 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/instrumentation-tedious@0.28.0` support has been added for migrating to the stable semantic conventions using the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable as follows:
46
+
47
+ 1. Upgrade to the latest version of this instrumentation package.
48
+ 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 to `db.*` attributes.)
49
+ 3. Modify alerts, dashboards, metrics, and other processes in your Observability system to use the stable semantic conventions.
50
+ 4. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http,database` to emit only the stable semantic conventions.
51
+
52
+ By default, if `OTEL_SEMCONV_STABILITY_OPT_IN` includes neither of the above tokens, the old v1.7.0 semconv is used.
53
+ 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.
54
+ 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.
46
55
 
47
56
  Attributes collected:
48
57
 
49
- | Attribute | Short Description |
50
- | ----------------------- | ------------------------------------------------------------------------------ |
51
- | `db.name` | This attribute is used to report the name of the database being accessed. |
52
- | `db.sql.table` | The name of the primary table that the operation is acting upon. |
53
- | `db.statement` | The database statement being executed. |
54
- | `db.system` | An identifier for the database management system (DBMS) product being used. |
55
- | `db.user` | Username for accessing the database. |
56
- | `net.peer.name` | Remote hostname or similar. |
57
- | `net.peer.port` | Remote port number. |
58
+ | Old semconv | Stable semconv | Description |
59
+ | --------------- | -------------------- | ---------------------------------- |
60
+ | `db.system` | `db.system.name` | 'mssql' (old), 'microsoft.sql_server' (stable) |
61
+ | `db.statement` | `db.query.text` | The database query being executed. |
62
+ | `db.user` | Removed | Username for accessing the database. |
63
+ | `db.name` | Removed | Integrated into new `db.namespace`. |
64
+ | (not included) | `db.namespace` | The database associated with the connection, qualified by the instance name. |
65
+ | `db.sql.table` | `db.collection.name` | The name of a collection (table, container) within the database. |
66
+ | `net.peer.name` | `server.address` | Remote hostname or similar. |
67
+ | `net.peer.port` | `server.port` | Remote port number. |
68
+
69
+ ### Trace Context Propagation
70
+
71
+ Database trace context propagation can be enabled by setting `enableTraceContextPropagation`to `true`.
72
+ This uses the [SET CONTEXT_INFO](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-context-info-transact-sql?view=sql-server-ver16)
73
+ command to set [traceparent](https://www.w3.org/TR/trace-context/#traceparent-header)information
74
+ for the current connection, which results in **an additional round-trip to the database**.
58
75
 
59
76
  ## Useful links
60
77
 
@@ -1,10 +1,21 @@
1
1
  import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
2
2
  import { TediousInstrumentationConfig } from './types';
3
+ export declare const INJECTED_CTX: unique symbol;
3
4
  export declare class TediousInstrumentation extends InstrumentationBase<TediousInstrumentationConfig> {
4
5
  static readonly COMPONENT = "tedious";
6
+ private _netSemconvStability;
7
+ private _dbSemconvStability;
5
8
  constructor(config?: TediousInstrumentationConfig);
9
+ private _setSemconvStabilityFromEnv;
6
10
  protected init(): InstrumentationNodeModuleDefinition[];
7
11
  private _patchConnect;
12
+ private _buildTraceparent;
13
+ /**
14
+ * Fire a one-off `SET CONTEXT_INFO @opentelemetry_traceparent` on the same
15
+ * connection. Marks the request with INJECTED_CTX so our patch skips it.
16
+ */
17
+ private _injectContextInfo;
18
+ private _shouldInjectFor;
8
19
  private _patchQuery;
9
20
  private _patchCallbackQuery;
10
21
  }
@@ -15,15 +15,17 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.TediousInstrumentation = void 0;
18
+ exports.TediousInstrumentation = exports.INJECTED_CTX = void 0;
19
19
  const api = require("@opentelemetry/api");
20
20
  const events_1 = require("events");
21
21
  const instrumentation_1 = require("@opentelemetry/instrumentation");
22
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
22
23
  const semconv_1 = require("./semconv");
23
24
  const utils_1 = require("./utils");
24
25
  /** @knipignore */
25
26
  const version_1 = require("./version");
26
27
  const CURRENT_DATABASE = Symbol('opentelemetry.instrumentation-tedious.current-database');
28
+ exports.INJECTED_CTX = Symbol('opentelemetry.instrumentation-tedious.context-info-injected');
27
29
  const PATCHED_METHODS = [
28
30
  'callProcedure',
29
31
  'execSql',
@@ -40,8 +42,16 @@ function setDatabase(databaseName) {
40
42
  }
41
43
  class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
42
44
  static COMPONENT = 'tedious';
45
+ _netSemconvStability;
46
+ _dbSemconvStability;
43
47
  constructor(config = {}) {
44
48
  super(version_1.PACKAGE_NAME, version_1.PACKAGE_VERSION, config);
49
+ this._setSemconvStabilityFromEnv();
50
+ }
51
+ // Used for testing.
52
+ _setSemconvStabilityFromEnv() {
53
+ this._netSemconvStability = (0, instrumentation_1.semconvStabilityFromStr)('http', process.env.OTEL_SEMCONV_STABILITY_OPT_IN);
54
+ this._dbSemconvStability = (0, instrumentation_1.semconvStabilityFromStr)('database', process.env.OTEL_SEMCONV_STABILITY_OPT_IN);
45
55
  }
46
56
  init() {
47
57
  return [
@@ -51,7 +61,7 @@ class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
51
61
  if ((0, instrumentation_1.isWrapped)(ConnectionPrototype[method])) {
52
62
  this._unwrap(ConnectionPrototype, method);
53
63
  }
54
- this._wrap(ConnectionPrototype, method, this._patchQuery(method));
64
+ this._wrap(ConnectionPrototype, method, this._patchQuery(method, moduleExports));
55
65
  }
56
66
  if ((0, instrumentation_1.isWrapped)(ConnectionPrototype.connect)) {
57
67
  this._unwrap(ConnectionPrototype, 'connect');
@@ -81,10 +91,45 @@ class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
81
91
  return original.apply(this, arguments);
82
92
  };
83
93
  }
84
- _patchQuery(operation) {
94
+ _buildTraceparent(span) {
95
+ const sc = span.spanContext();
96
+ return `00-${sc.traceId}-${sc.spanId}-0${Number(sc.traceFlags || api.TraceFlags.NONE).toString(16)}`;
97
+ }
98
+ /**
99
+ * Fire a one-off `SET CONTEXT_INFO @opentelemetry_traceparent` on the same
100
+ * connection. Marks the request with INJECTED_CTX so our patch skips it.
101
+ */
102
+ _injectContextInfo(connection, tediousModule, traceparent) {
103
+ return new Promise(resolve => {
104
+ try {
105
+ const sql = 'set context_info @opentelemetry_traceparent';
106
+ const req = new tediousModule.Request(sql, (_err) => {
107
+ resolve();
108
+ });
109
+ Object.defineProperty(req, exports.INJECTED_CTX, { value: true });
110
+ const buf = Buffer.from(traceparent, 'utf8');
111
+ req.addParameter('opentelemetry_traceparent', tediousModule.TYPES.VarBinary, buf, { length: buf.length });
112
+ connection.execSql(req);
113
+ }
114
+ catch {
115
+ resolve();
116
+ }
117
+ });
118
+ }
119
+ _shouldInjectFor(operation) {
120
+ return (operation === 'execSql' ||
121
+ operation === 'execSqlBatch' ||
122
+ operation === 'callProcedure' ||
123
+ operation === 'execute');
124
+ }
125
+ _patchQuery(operation, tediousModule) {
85
126
  return (originalMethod) => {
86
127
  const thisPlugin = this;
87
128
  function patchedMethod(request) {
129
+ // Skip our own injected request
130
+ if (request?.[exports.INJECTED_CTX]) {
131
+ return originalMethod.apply(this, arguments);
132
+ }
88
133
  if (!(request instanceof events_1.EventEmitter)) {
89
134
  thisPlugin._diag.warn(`Unexpected invocation of patched ${operation} method. Span not recorded`);
90
135
  return originalMethod.apply(this, arguments);
@@ -102,19 +147,43 @@ class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
102
147
  }
103
148
  return request.sqlTextOrProcedure;
104
149
  })(request);
150
+ const attributes = {};
151
+ if (thisPlugin._dbSemconvStability & instrumentation_1.SemconvStability.OLD) {
152
+ attributes[semconv_1.ATTR_DB_SYSTEM] = semconv_1.DB_SYSTEM_VALUE_MSSQL;
153
+ attributes[semconv_1.ATTR_DB_NAME] = databaseName;
154
+ // >=4 uses `authentication` object; older versions just userName and password pair
155
+ attributes[semconv_1.ATTR_DB_USER] =
156
+ this.config?.userName ??
157
+ this.config?.authentication?.options?.userName;
158
+ attributes[semconv_1.ATTR_DB_STATEMENT] = sql;
159
+ attributes[semconv_1.ATTR_DB_SQL_TABLE] = request.table;
160
+ }
161
+ if (thisPlugin._dbSemconvStability & instrumentation_1.SemconvStability.STABLE) {
162
+ // The OTel spec for "db.namespace" discusses handling for connection
163
+ // to MSSQL "named instances". This isn't currently supported.
164
+ // https://opentelemetry.io/docs/specs/semconv/database/sql-server/#:~:text=%5B1%5D%20db%2Enamespace
165
+ attributes[semantic_conventions_1.ATTR_DB_NAMESPACE] = databaseName;
166
+ attributes[semantic_conventions_1.ATTR_DB_SYSTEM_NAME] =
167
+ semantic_conventions_1.DB_SYSTEM_NAME_VALUE_MICROSOFT_SQL_SERVER;
168
+ attributes[semantic_conventions_1.ATTR_DB_QUERY_TEXT] = sql;
169
+ attributes[semantic_conventions_1.ATTR_DB_COLLECTION_NAME] = request.table;
170
+ // See https://opentelemetry.io/docs/specs/semconv/database/sql-server/#spans
171
+ // TODO(3290): can `db.response.status_code` be added?
172
+ // TODO(3290): is `operation` correct for `db.operation.name`
173
+ // TODO(3290): can `db.query.summary` reliably be calculated?
174
+ // TODO(3290): `db.stored_procedure.name`
175
+ }
176
+ if (thisPlugin._netSemconvStability & instrumentation_1.SemconvStability.OLD) {
177
+ attributes[semconv_1.ATTR_NET_PEER_NAME] = this.config?.server;
178
+ attributes[semconv_1.ATTR_NET_PEER_PORT] = this.config?.options?.port;
179
+ }
180
+ if (thisPlugin._netSemconvStability & instrumentation_1.SemconvStability.STABLE) {
181
+ attributes[semantic_conventions_1.ATTR_SERVER_ADDRESS] = this.config?.server;
182
+ attributes[semantic_conventions_1.ATTR_SERVER_PORT] = this.config?.options?.port;
183
+ }
105
184
  const span = thisPlugin.tracer.startSpan((0, utils_1.getSpanName)(operation, databaseName, sql, request.table), {
106
185
  kind: api.SpanKind.CLIENT,
107
- attributes: {
108
- [semconv_1.ATTR_DB_SYSTEM]: semconv_1.DB_SYSTEM_VALUE_MSSQL,
109
- [semconv_1.ATTR_DB_NAME]: databaseName,
110
- [semconv_1.ATTR_NET_PEER_PORT]: this.config?.options?.port,
111
- [semconv_1.ATTR_NET_PEER_NAME]: this.config?.server,
112
- // >=4 uses `authentication` object, older versions just userName and password pair
113
- [semconv_1.ATTR_DB_USER]: this.config?.userName ??
114
- this.config?.authentication?.options?.userName,
115
- [semconv_1.ATTR_DB_STATEMENT]: sql,
116
- [semconv_1.ATTR_DB_SQL_TABLE]: request.table,
117
- },
186
+ attributes,
118
187
  });
119
188
  const endSpan = (0, utils_1.once)((err) => {
120
189
  request.removeListener('done', incrementStatementCount);
@@ -129,6 +198,7 @@ class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
129
198
  code: api.SpanStatusCode.ERROR,
130
199
  message: err.message,
131
200
  });
201
+ // TODO(3290): set `error.type` attribute?
132
202
  }
133
203
  span.end();
134
204
  });
@@ -143,7 +213,18 @@ class TediousInstrumentation extends instrumentation_1.InstrumentationBase {
143
213
  else {
144
214
  thisPlugin._diag.error('Expected request.callback to be a function');
145
215
  }
146
- return api.context.with(api.trace.setSpan(api.context.active(), span), originalMethod, this, ...arguments);
216
+ const runUserRequest = () => {
217
+ return api.context.with(api.trace.setSpan(api.context.active(), span), originalMethod, this, ...arguments);
218
+ };
219
+ const cfg = thisPlugin.getConfig();
220
+ const shouldInject = cfg.enableTraceContextPropagation &&
221
+ thisPlugin._shouldInjectFor(operation);
222
+ if (!shouldInject)
223
+ return runUserRequest();
224
+ const traceparent = thisPlugin._buildTraceparent(span);
225
+ void thisPlugin
226
+ ._injectContextInfo(this, tediousModule, traceparent)
227
+ .finally(runUserRequest);
147
228
  }
148
229
  Object.defineProperty(patchedMethod, 'length', {
149
230
  value: originalMethod.length,
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as api from '@opentelemetry/api';\nimport { EventEmitter } from 'events';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n} from '@opentelemetry/instrumentation';\nimport {\n DB_SYSTEM_VALUE_MSSQL,\n ATTR_DB_NAME,\n ATTR_DB_SQL_TABLE,\n ATTR_DB_STATEMENT,\n ATTR_DB_SYSTEM,\n ATTR_DB_USER,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n} from './semconv';\nimport type * as tedious from 'tedious';\nimport { TediousInstrumentationConfig } from './types';\nimport { getSpanName, once } from './utils';\n/** @knipignore */\nimport { PACKAGE_NAME, PACKAGE_VERSION } from './version';\n\nconst CURRENT_DATABASE = Symbol(\n 'opentelemetry.instrumentation-tedious.current-database'\n);\nconst PATCHED_METHODS = [\n 'callProcedure',\n 'execSql',\n 'execSqlBatch',\n 'execBulkLoad',\n 'prepare',\n 'execute',\n];\n\ntype UnknownFunction = (...args: any[]) => any;\ntype ApproxConnection = EventEmitter & {\n [CURRENT_DATABASE]: string;\n config: any;\n};\ntype ApproxRequest = EventEmitter & {\n sqlTextOrProcedure: string | undefined;\n callback: any;\n table: string | undefined;\n parametersByName: any;\n};\n\nfunction setDatabase(this: ApproxConnection, databaseName: string) {\n Object.defineProperty(this, CURRENT_DATABASE, {\n value: databaseName,\n writable: true,\n });\n}\n\nexport class TediousInstrumentation extends InstrumentationBase<TediousInstrumentationConfig> {\n static readonly COMPONENT = 'tedious';\n\n constructor(config: TediousInstrumentationConfig = {}) {\n super(PACKAGE_NAME, PACKAGE_VERSION, config);\n }\n\n protected init() {\n return [\n new InstrumentationNodeModuleDefinition(\n TediousInstrumentation.COMPONENT,\n ['>=1.11.0 <20'],\n (moduleExports: typeof tedious) => {\n const ConnectionPrototype: any = moduleExports.Connection.prototype;\n for (const method of PATCHED_METHODS) {\n if (isWrapped(ConnectionPrototype[method])) {\n this._unwrap(ConnectionPrototype, method);\n }\n this._wrap(\n ConnectionPrototype,\n method,\n this._patchQuery(method) as any\n );\n }\n\n if (isWrapped(ConnectionPrototype.connect)) {\n this._unwrap(ConnectionPrototype, 'connect');\n }\n this._wrap(ConnectionPrototype, 'connect', this._patchConnect);\n\n return moduleExports;\n },\n (moduleExports: typeof tedious) => {\n if (moduleExports === undefined) return;\n const ConnectionPrototype: any = moduleExports.Connection.prototype;\n for (const method of PATCHED_METHODS) {\n this._unwrap(ConnectionPrototype, method);\n }\n this._unwrap(ConnectionPrototype, 'connect');\n }\n ),\n ];\n }\n\n private _patchConnect(original: UnknownFunction): UnknownFunction {\n return function patchedConnect(this: ApproxConnection) {\n setDatabase.call(this, this.config?.options?.database);\n\n // remove the listener first in case it's already added\n this.removeListener('databaseChange', setDatabase);\n this.on('databaseChange', setDatabase);\n\n this.once('end', () => {\n this.removeListener('databaseChange', setDatabase);\n });\n return original.apply(this, arguments as unknown as any[]);\n };\n }\n\n private _patchQuery(operation: string) {\n return (originalMethod: UnknownFunction): UnknownFunction => {\n const thisPlugin = this;\n\n function patchedMethod(this: ApproxConnection, request: ApproxRequest) {\n if (!(request instanceof EventEmitter)) {\n thisPlugin._diag.warn(\n `Unexpected invocation of patched ${operation} method. Span not recorded`\n );\n return originalMethod.apply(this, arguments as unknown as any[]);\n }\n let procCount = 0;\n let statementCount = 0;\n const incrementStatementCount = () => statementCount++;\n const incrementProcCount = () => procCount++;\n const databaseName = this[CURRENT_DATABASE];\n const sql = (request => {\n // Required for <11.0.9\n if (\n request.sqlTextOrProcedure === 'sp_prepare' &&\n request.parametersByName?.stmt?.value\n ) {\n return request.parametersByName.stmt.value;\n }\n return request.sqlTextOrProcedure;\n })(request);\n\n const span = thisPlugin.tracer.startSpan(\n getSpanName(operation, databaseName, sql, request.table),\n {\n kind: api.SpanKind.CLIENT,\n attributes: {\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_MSSQL,\n [ATTR_DB_NAME]: databaseName,\n [ATTR_NET_PEER_PORT]: this.config?.options?.port,\n [ATTR_NET_PEER_NAME]: this.config?.server,\n // >=4 uses `authentication` object, older versions just userName and password pair\n [ATTR_DB_USER]:\n this.config?.userName ??\n this.config?.authentication?.options?.userName,\n [ATTR_DB_STATEMENT]: sql,\n [ATTR_DB_SQL_TABLE]: request.table,\n },\n }\n );\n\n const endSpan = once((err?: any) => {\n request.removeListener('done', incrementStatementCount);\n request.removeListener('doneInProc', incrementStatementCount);\n request.removeListener('doneProc', incrementProcCount);\n request.removeListener('error', endSpan);\n this.removeListener('end', endSpan);\n\n span.setAttribute('tedious.procedure_count', procCount);\n span.setAttribute('tedious.statement_count', statementCount);\n if (err) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: err.message,\n });\n }\n span.end();\n });\n\n request.on('done', incrementStatementCount);\n request.on('doneInProc', incrementStatementCount);\n request.on('doneProc', incrementProcCount);\n request.once('error', endSpan);\n this.on('end', endSpan);\n\n if (typeof request.callback === 'function') {\n thisPlugin._wrap(\n request,\n 'callback',\n thisPlugin._patchCallbackQuery(endSpan)\n );\n } else {\n thisPlugin._diag.error('Expected request.callback to be a function');\n }\n\n return api.context.with(\n api.trace.setSpan(api.context.active(), span),\n originalMethod,\n this,\n ...arguments\n );\n }\n\n Object.defineProperty(patchedMethod, 'length', {\n value: originalMethod.length,\n writable: false,\n });\n\n return patchedMethod;\n };\n }\n\n private _patchCallbackQuery(endSpan: Function) {\n return (originalCallback: Function) => {\n return function (\n this: any,\n err: Error | undefined | null,\n rowCount?: number,\n rows?: any\n ) {\n endSpan(err);\n return originalCallback.apply(this, arguments);\n };\n };\n }\n}\n"]}
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as api from '@opentelemetry/api';\nimport { EventEmitter } from 'events';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n SemconvStability,\n semconvStabilityFromStr,\n} from '@opentelemetry/instrumentation';\nimport {\n ATTR_DB_COLLECTION_NAME,\n ATTR_DB_NAMESPACE,\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_SYSTEM_NAME,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n DB_SYSTEM_NAME_VALUE_MICROSOFT_SQL_SERVER,\n} from '@opentelemetry/semantic-conventions';\nimport {\n DB_SYSTEM_VALUE_MSSQL,\n ATTR_DB_NAME,\n ATTR_DB_SQL_TABLE,\n ATTR_DB_STATEMENT,\n ATTR_DB_SYSTEM,\n ATTR_DB_USER,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n} from './semconv';\nimport type * as tedious from 'tedious';\nimport { TediousInstrumentationConfig } from './types';\nimport { getSpanName, once } from './utils';\n/** @knipignore */\nimport { PACKAGE_NAME, PACKAGE_VERSION } from './version';\n\nconst CURRENT_DATABASE = Symbol(\n 'opentelemetry.instrumentation-tedious.current-database'\n);\n\nexport const INJECTED_CTX = Symbol(\n 'opentelemetry.instrumentation-tedious.context-info-injected'\n);\n\nconst PATCHED_METHODS = [\n 'callProcedure',\n 'execSql',\n 'execSqlBatch',\n 'execBulkLoad',\n 'prepare',\n 'execute',\n];\n\ntype UnknownFunction = (...args: any[]) => any;\ntype ApproxConnection = EventEmitter & {\n [CURRENT_DATABASE]: string;\n config: any;\n};\ntype ApproxRequest = EventEmitter & {\n sqlTextOrProcedure: string | undefined;\n callback: any;\n table: string | undefined;\n parametersByName: any;\n};\n\nfunction setDatabase(this: ApproxConnection, databaseName: string) {\n Object.defineProperty(this, CURRENT_DATABASE, {\n value: databaseName,\n writable: true,\n });\n}\n\nexport class TediousInstrumentation extends InstrumentationBase<TediousInstrumentationConfig> {\n static readonly COMPONENT = 'tedious';\n private _netSemconvStability!: SemconvStability;\n private _dbSemconvStability!: SemconvStability;\n\n constructor(config: TediousInstrumentationConfig = {}) {\n super(PACKAGE_NAME, PACKAGE_VERSION, config);\n this._setSemconvStabilityFromEnv();\n }\n\n // Used for testing.\n private _setSemconvStabilityFromEnv() {\n this._netSemconvStability = semconvStabilityFromStr(\n 'http',\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN\n );\n this._dbSemconvStability = semconvStabilityFromStr(\n 'database',\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN\n );\n }\n\n protected init() {\n return [\n new InstrumentationNodeModuleDefinition(\n TediousInstrumentation.COMPONENT,\n ['>=1.11.0 <20'],\n (moduleExports: typeof tedious) => {\n const ConnectionPrototype: any = moduleExports.Connection.prototype;\n for (const method of PATCHED_METHODS) {\n if (isWrapped(ConnectionPrototype[method])) {\n this._unwrap(ConnectionPrototype, method);\n }\n this._wrap(\n ConnectionPrototype,\n method,\n this._patchQuery(method, moduleExports) as any\n );\n }\n\n if (isWrapped(ConnectionPrototype.connect)) {\n this._unwrap(ConnectionPrototype, 'connect');\n }\n this._wrap(ConnectionPrototype, 'connect', this._patchConnect);\n\n return moduleExports;\n },\n (moduleExports: typeof tedious) => {\n if (moduleExports === undefined) return;\n const ConnectionPrototype: any = moduleExports.Connection.prototype;\n for (const method of PATCHED_METHODS) {\n this._unwrap(ConnectionPrototype, method);\n }\n this._unwrap(ConnectionPrototype, 'connect');\n }\n ),\n ];\n }\n\n private _patchConnect(original: UnknownFunction): UnknownFunction {\n return function patchedConnect(this: ApproxConnection) {\n setDatabase.call(this, this.config?.options?.database);\n\n // remove the listener first in case it's already added\n this.removeListener('databaseChange', setDatabase);\n this.on('databaseChange', setDatabase);\n\n this.once('end', () => {\n this.removeListener('databaseChange', setDatabase);\n });\n return original.apply(this, arguments as unknown as any[]);\n };\n }\n\n private _buildTraceparent(span: api.Span): string {\n const sc = span.spanContext();\n return `00-${sc.traceId}-${sc.spanId}-0${Number(sc.traceFlags || api.TraceFlags.NONE).toString(16)}`;\n }\n\n /**\n * Fire a one-off `SET CONTEXT_INFO @opentelemetry_traceparent` on the same\n * connection. Marks the request with INJECTED_CTX so our patch skips it.\n */\n private _injectContextInfo(\n connection: any,\n tediousModule: typeof tedious,\n traceparent: string\n ): Promise<void> {\n return new Promise(resolve => {\n try {\n const sql = 'set context_info @opentelemetry_traceparent';\n const req = new tediousModule.Request(sql, (_err: any) => {\n resolve();\n });\n Object.defineProperty(req, INJECTED_CTX, { value: true });\n const buf = Buffer.from(traceparent, 'utf8');\n req.addParameter(\n 'opentelemetry_traceparent',\n (tediousModule as any).TYPES.VarBinary,\n buf,\n { length: buf.length }\n );\n\n connection.execSql(req);\n } catch {\n resolve();\n }\n });\n }\n\n private _shouldInjectFor(operation: string): boolean {\n return (\n operation === 'execSql' ||\n operation === 'execSqlBatch' ||\n operation === 'callProcedure' ||\n operation === 'execute'\n );\n }\n\n private _patchQuery(operation: string, tediousModule: typeof tedious) {\n return (originalMethod: UnknownFunction): UnknownFunction => {\n const thisPlugin = this;\n\n function patchedMethod(this: ApproxConnection, request: ApproxRequest) {\n // Skip our own injected request\n if ((request as any)?.[INJECTED_CTX]) {\n return originalMethod.apply(this, arguments as unknown as any[]);\n }\n\n if (!(request instanceof EventEmitter)) {\n thisPlugin._diag.warn(\n `Unexpected invocation of patched ${operation} method. Span not recorded`\n );\n return originalMethod.apply(this, arguments as unknown as any[]);\n }\n let procCount = 0;\n let statementCount = 0;\n const incrementStatementCount = () => statementCount++;\n const incrementProcCount = () => procCount++;\n const databaseName = this[CURRENT_DATABASE];\n const sql = (request => {\n // Required for <11.0.9\n if (\n request.sqlTextOrProcedure === 'sp_prepare' &&\n request.parametersByName?.stmt?.value\n ) {\n return request.parametersByName.stmt.value;\n }\n return request.sqlTextOrProcedure;\n })(request);\n\n const attributes: api.Attributes = {};\n if (thisPlugin._dbSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_MSSQL;\n attributes[ATTR_DB_NAME] = databaseName;\n // >=4 uses `authentication` object; older versions just userName and password pair\n attributes[ATTR_DB_USER] =\n this.config?.userName ??\n this.config?.authentication?.options?.userName;\n attributes[ATTR_DB_STATEMENT] = sql;\n attributes[ATTR_DB_SQL_TABLE] = request.table;\n }\n if (thisPlugin._dbSemconvStability & SemconvStability.STABLE) {\n // The OTel spec for \"db.namespace\" discusses handling for connection\n // to MSSQL \"named instances\". This isn't currently supported.\n // https://opentelemetry.io/docs/specs/semconv/database/sql-server/#:~:text=%5B1%5D%20db%2Enamespace\n attributes[ATTR_DB_NAMESPACE] = databaseName;\n attributes[ATTR_DB_SYSTEM_NAME] =\n DB_SYSTEM_NAME_VALUE_MICROSOFT_SQL_SERVER;\n attributes[ATTR_DB_QUERY_TEXT] = sql;\n attributes[ATTR_DB_COLLECTION_NAME] = request.table;\n // See https://opentelemetry.io/docs/specs/semconv/database/sql-server/#spans\n // TODO(3290): can `db.response.status_code` be added?\n // TODO(3290): is `operation` correct for `db.operation.name`\n // TODO(3290): can `db.query.summary` reliably be calculated?\n // TODO(3290): `db.stored_procedure.name`\n }\n if (thisPlugin._netSemconvStability & SemconvStability.OLD) {\n attributes[ATTR_NET_PEER_NAME] = this.config?.server;\n attributes[ATTR_NET_PEER_PORT] = this.config?.options?.port;\n }\n if (thisPlugin._netSemconvStability & SemconvStability.STABLE) {\n attributes[ATTR_SERVER_ADDRESS] = this.config?.server;\n attributes[ATTR_SERVER_PORT] = this.config?.options?.port;\n }\n const span = thisPlugin.tracer.startSpan(\n getSpanName(operation, databaseName, sql, request.table),\n {\n kind: api.SpanKind.CLIENT,\n attributes,\n }\n );\n\n const endSpan = once((err?: any) => {\n request.removeListener('done', incrementStatementCount);\n request.removeListener('doneInProc', incrementStatementCount);\n request.removeListener('doneProc', incrementProcCount);\n request.removeListener('error', endSpan);\n this.removeListener('end', endSpan);\n\n span.setAttribute('tedious.procedure_count', procCount);\n span.setAttribute('tedious.statement_count', statementCount);\n if (err) {\n span.setStatus({\n code: api.SpanStatusCode.ERROR,\n message: err.message,\n });\n // TODO(3290): set `error.type` attribute?\n }\n span.end();\n });\n\n request.on('done', incrementStatementCount);\n request.on('doneInProc', incrementStatementCount);\n request.on('doneProc', incrementProcCount);\n request.once('error', endSpan);\n this.on('end', endSpan);\n\n if (typeof request.callback === 'function') {\n thisPlugin._wrap(\n request,\n 'callback',\n thisPlugin._patchCallbackQuery(endSpan)\n );\n } else {\n thisPlugin._diag.error('Expected request.callback to be a function');\n }\n\n const runUserRequest = () => {\n return api.context.with(\n api.trace.setSpan(api.context.active(), span),\n originalMethod,\n this,\n ...arguments\n );\n };\n\n const cfg = thisPlugin.getConfig();\n const shouldInject =\n cfg.enableTraceContextPropagation &&\n thisPlugin._shouldInjectFor(operation);\n\n if (!shouldInject) return runUserRequest();\n\n const traceparent = thisPlugin._buildTraceparent(span);\n\n void thisPlugin\n ._injectContextInfo(this, tediousModule, traceparent)\n .finally(runUserRequest);\n }\n\n Object.defineProperty(patchedMethod, 'length', {\n value: originalMethod.length,\n writable: false,\n });\n\n return patchedMethod;\n };\n }\n\n private _patchCallbackQuery(endSpan: Function) {\n return (originalCallback: Function) => {\n return function (\n this: any,\n err: Error | undefined | null,\n rowCount?: number,\n rows?: any\n ) {\n endSpan(err);\n return originalCallback.apply(this, arguments);\n };\n };\n }\n}\n"]}
@@ -1,3 +1,10 @@
1
1
  import { InstrumentationConfig } from '@opentelemetry/instrumentation';
2
- export type TediousInstrumentationConfig = InstrumentationConfig;
2
+ export interface TediousInstrumentationConfig extends InstrumentationConfig {
3
+ /**
4
+ * If true, injects the current DB span's W3C traceparent into SQL Server
5
+ * session state via `SET CONTEXT_INFO @opentelemetry_traceparent` (varbinary).
6
+ * Off by default to avoid the extra round-trip per request.
7
+ */
8
+ enableTraceContextPropagation?: boolean;
9
+ }
3
10
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InstrumentationConfig } from '@opentelemetry/instrumentation';\n\nexport type TediousInstrumentationConfig = InstrumentationConfig;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InstrumentationConfig } from '@opentelemetry/instrumentation';\nexport interface TediousInstrumentationConfig extends InstrumentationConfig {\n /**\n * If true, injects the current DB span's W3C traceparent into SQL Server\n * session state via `SET CONTEXT_INFO @opentelemetry_traceparent` (varbinary).\n * Off by default to avoid the extra round-trip per request.\n */\n enableTraceContextPropagation?: boolean;\n}\n"]}
@@ -1,3 +1,3 @@
1
- export declare const PACKAGE_VERSION = "0.26.0";
1
+ export declare const PACKAGE_VERSION = "0.28.0";
2
2
  export declare const PACKAGE_NAME = "@opentelemetry/instrumentation-tedious";
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -17,6 +17,6 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.PACKAGE_NAME = exports.PACKAGE_VERSION = void 0;
19
19
  // this is autogenerated file, see scripts/version-update.js
20
- exports.PACKAGE_VERSION = '0.26.0';
20
+ exports.PACKAGE_VERSION = '0.28.0';
21
21
  exports.PACKAGE_NAME = '@opentelemetry/instrumentation-tedious';
22
22
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,4DAA4D;AAC/C,QAAA,eAAe,GAAG,QAAQ,CAAC;AAC3B,QAAA,YAAY,GAAG,wCAAwC,CAAC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// this is autogenerated file, see scripts/version-update.js\nexport const PACKAGE_VERSION = '0.26.0';\nexport const PACKAGE_NAME = '@opentelemetry/instrumentation-tedious';\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,4DAA4D;AAC/C,QAAA,eAAe,GAAG,QAAQ,CAAC;AAC3B,QAAA,YAAY,GAAG,wCAAwC,CAAC","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// this is autogenerated file, see scripts/version-update.js\nexport const PACKAGE_VERSION = '0.28.0';\nexport const PACKAGE_NAME = '@opentelemetry/instrumentation-tedious';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentelemetry/instrumentation-tedious",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "OpenTelemetry instrumentation for `tedious` database client for Microsoft SQL Server",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -54,22 +54,15 @@
54
54
  "devDependencies": {
55
55
  "@opentelemetry/api": "^1.3.0",
56
56
  "@opentelemetry/context-async-hooks": "^2.0.0",
57
- "@opentelemetry/contrib-test-utils": "^0.54.0",
57
+ "@opentelemetry/contrib-test-utils": "^0.56.0",
58
58
  "@opentelemetry/sdk-trace-base": "^2.0.0",
59
- "@types/mocha": "10.0.10",
60
- "@types/node": "18.18.14",
61
- "cross-env": "7.0.3",
62
- "nyc": "17.1.0",
63
- "rimraf": "5.0.10",
64
- "semver": "7.7.3",
65
- "tedious": "17.0.0",
66
- "test-all-versions": "6.1.0",
67
- "typescript": "5.0.4"
59
+ "tedious": "17.0.0"
68
60
  },
69
61
  "dependencies": {
70
- "@opentelemetry/instrumentation": "^0.207.0",
62
+ "@opentelemetry/instrumentation": "^0.208.0",
63
+ "@opentelemetry/semantic-conventions": "^1.33.0",
71
64
  "@types/tedious": "^4.0.14"
72
65
  },
73
66
  "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-tedious#readme",
74
- "gitHead": "2801ab2f0f9243b154a624298dacb7228c4f70cd"
67
+ "gitHead": "66935ac724cc271f70028035e534d47a4dfbcf12"
75
68
  }