@sebspark/opentelemetry-instrumentation-opensearch 0.3.15 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @sebspark/opentelemetry-instrumentation-opensearch
2
2
 
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7db408f: feat(opensearch): type `aggs`/`aggregations` in `SearchRequestBody<T>` against the index mapping. Restores `field` and `script` on `max`, `min`, `sum`, `avg`, `value_count`, `cardinality` and `terms`, which `@opensearch-project/opensearch` 3.9.0 dropped (opensearch-project/opensearch-js#1154). `field` on these and on `date_histogram`, `date_range` and `range` autocompletes paths from the mapping and accepts any other field name. `filter` takes an index-aware query, `top_hits` gets index-aware `sort`/`_source`, and sub-aggregations are typed recursively. Other aggregations keep their upstream types. `AggregationContainer<T>` is exported for typing individual aggregations.
8
+
9
+ feat(opensearch): the typing never blocks a request OpenSearch accepts. Fields that are not in the mapping (e.g. added by dynamic mapping) are accepted in `query`, `sort`, `_source`, `collapse`, `highlight`, aggregation `field`/`filter` and `top_hits` `sort`/`_source`; mapped fields still autocomplete. `DocumentFor<T>` accepts fields that are not in the mapping as `unknown`, so `index`, `bulk` and the bulk helpers take documents with extra fields. A generic `SearchRequest<T>` can be passed to the upstream `Client`.
10
+
11
+ fix(opensearch): sort accepts the direction shorthand (`{ age: 'desc' }`), `knn_vector` fields map to `number[]` in `DocumentFor`, `knn.filter` is a single query instead of an array, and `script_score.query` is required. OpenSearch rejects both an array `knn.filter` and a `script_score` without `query`, so only requests that already failed at runtime stop compiling. To migrate, combine several knn filters in one `bool` query (`filter: { bool: { filter: [...] } }`), and add `query: { match_all: {} }` to a `script_score` that had none.
12
+
13
+ chore(deps): update dependencies
14
+ - `@google-cloud/pubsub` 6.3.1 → 6.3.2
15
+ - `@inquirer/figures` 2.0.9 → 2.0.10
16
+ - `@inquirer/prompts` 8.7.4 → 8.7.5
17
+ - `@opentelemetry/semantic-conventions` 1.43.0 → 1.44.0
18
+ - `redis` 6.3.0 → 6.3.1
19
+ - `tsdown` 0.23.1 → 0.23.4
20
+
21
+ fix: dependency issues found by knip
22
+ - `@sebspark/promise-cache`: drop the unused `@sebspark/otel`
23
+ - `@sebspark/socket.io-gcp-pubsub-emitter`: drop the unused `uuid`
24
+ - `@sebspark/memredis`: derive `GetExOptions` from `redis` instead of importing the unlisted `@redis/client` internals
25
+
26
+ fix(test-iap): the default base image of `TestIapContainer` is now `node:26.13.0-alpine`, pinned by digest, instead of the floating `node:22-alpine`. Use `withBaseImage()` to choose another image.
27
+
28
+ ## 0.4.0
29
+
30
+ ### Minor Changes
31
+
32
+ - ad1e80f: Upgraded to OpenTelemetry 3.0. Peer `@opentelemetry/api` is now `>=1.10.0 <1.11.0`.
33
+
3
34
  ## 0.3.15
4
35
 
5
36
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { ApiResponse, TransportRequestParams } from "@opensearch-project/opensearch/lib/Transport.js";
2
2
  import { InstrumentationBase, InstrumentationConfig } from "@opentelemetry/instrumentation";
3
3
  import { Span } from "@opentelemetry/api";
4
- //#region src/types.d.ts
5
4
  interface OpenSearchInstrumentationConfig extends InstrumentationConfig {
6
5
  dbStatementSerializer?: false | ((params: TransportRequestParams) => string);
7
6
  requestHook?: (span: Span, params: TransportRequestParams) => void;
@@ -9,8 +8,6 @@ interface OpenSearchInstrumentationConfig extends InstrumentationConfig {
9
8
  suppressInternalInstrumentation?: boolean;
10
9
  moduleVersionAttributeName?: string;
11
10
  }
12
- //#endregion
13
- //#region src/index.d.ts
14
11
  export declare class OpenSearchInstrumentation extends InstrumentationBase {
15
12
  private readonly osConfig;
16
13
  private _original;
@@ -19,6 +16,5 @@ export declare class OpenSearchInstrumentation extends InstrumentationBase {
19
16
  enable(): void;
20
17
  disable(): void;
21
18
  }
22
- //#endregion
23
19
  export type { OpenSearchInstrumentationConfig };
24
20
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;UAOiB,wCAAwC;EACvD,kCAAkC,QAAQ;EAC1C,eAAe,MAAM,MAAM,QAAQ;EACnC,gBAAgB,MAAM,MAAM,UAAU;EACtC;EACA;;;;qBCGW,kCAAkC;mBAC5B;UACT;EAER,YAAY,SAAQ;YAQV;EAED;EAWA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;UAOiB,wCAAwC;EACvD,kCAAkC,QAAQ;EAC1C,eAAe,MAAM,MAAM,QAAQ;EACnC,gBAAgB,MAAM,MAAM,UAAU;EACtC;EACA;;qBCGW,kCAAkC;mBAC5B;UACT;EAER,YAAY,SAAQ;YAQV;EAED;EAWA"}
package/dist/index.mjs CHANGED
@@ -4,11 +4,10 @@ import { InstrumentationBase } from "@opentelemetry/instrumentation";
4
4
  import { SpanKind, SpanStatusCode, context, trace } from "@opentelemetry/api";
5
5
  import { suppressTracing } from "@opentelemetry/core";
6
6
  import { ATTR_DB_COLLECTION_NAME, ATTR_DB_OPERATION_NAME, ATTR_DB_QUERY_TEXT, ATTR_DB_SYSTEM_NAME, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT } from "@opentelemetry/semantic-conventions";
7
- //#region package.json
7
+ // package.json
8
8
  var name = "@sebspark/opentelemetry-instrumentation-opensearch";
9
- var version = "0.3.15";
10
- //#endregion
11
- //#region src/parse-path.ts
9
+ var version = "0.4.1";
10
+ // src/parse-path.ts
12
11
  const METHOD_OPERATIONS = {
13
12
  PUT: "indices.create",
14
13
  DELETE: "indices.delete"
@@ -33,8 +32,7 @@ const parsePath = (path, method) => {
33
32
  }
34
33
  return {};
35
34
  };
36
- //#endregion
37
- //#region src/response-attributes.ts
35
+ // src/response-attributes.ts
38
36
  const ATTR_DB_OPENSEARCH_DURATION_MS = "db.opensearch.duration_ms";
39
37
  const extractResponseAttributes = (res) => {
40
38
  const attrs = {};
@@ -67,16 +65,14 @@ const extractResponseAttributes = (res) => {
67
65
  if (total != null && typeof total === "object") attrs["db.opensearch.hits.total"] = total.value;
68
66
  return attrs;
69
67
  };
70
- //#endregion
71
- //#region src/serialize-body.ts
68
+ // src/serialize-body.ts
72
69
  const serializeBody = (params, config) => {
73
70
  if (!params.body) return void 0;
74
71
  if (config.dbStatementSerializer === false) return void 0;
75
72
  if (typeof config.dbStatementSerializer === "function") return config.dbStatementSerializer(params);
76
73
  return typeof params.body === "string" ? params.body : JSON.stringify(params.body);
77
74
  };
78
- //#endregion
79
- //#region src/patch-request.ts
75
+ // src/patch-request.ts
80
76
  const createPatchedRequest = (getTracer, config = {}, original, clientVersion) => {
81
77
  function patchedRequest(params, options, callback) {
82
78
  const { index, operation } = parsePath(params.path, params.method);
@@ -125,8 +121,7 @@ const createPatchedRequest = (getTracer, config = {}, original, clientVersion) =
125
121
  }
126
122
  return patchedRequest;
127
123
  };
128
- //#endregion
129
- //#region src/index.ts
124
+ // src/index.ts
130
125
  const PACKAGE_NAME = name;
131
126
  const PACKAGE_VERSION = version;
132
127
  const OPENSEARCH_CLIENT_VERSION = opensearchPkg.version;
@@ -154,7 +149,6 @@ var OpenSearchInstrumentation = class extends InstrumentationBase {
154
149
  }
155
150
  }
156
151
  };
157
- //#endregion
158
152
  export { OpenSearchInstrumentation };
159
153
 
160
154
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["pkg.name","pkg.version"],"sources":["../package.json","../src/parse-path.ts","../src/response-attributes.ts","../src/serialize-body.ts","../src/patch-request.ts","../src/index.ts"],"sourcesContent":["","const METHOD_OPERATIONS: Record<string, string> = {\n PUT: 'indices.create',\n DELETE: 'indices.delete',\n}\n\nconst OPERATION_ALIASES: Record<string, string> = {\n doc: 'index',\n}\n\nexport const parsePath = (\n path: string,\n method?: string\n): { index?: string; operation?: string } => {\n const decoded = decodeURIComponent(path)\n const match = decoded.match(/^\\/(?:([^/_][^/]*)\\/)?_([^/]+)/)\n if (match) {\n const operation = OPERATION_ALIASES[match[2]] ?? match[2]\n return { index: match[1], operation }\n }\n\n if (method) {\n const operation = METHOD_OPERATIONS[method.toUpperCase()]\n if (operation) {\n const index = decoded.replace(/^\\//, '') || undefined\n return { index, operation }\n }\n }\n\n return {}\n}\n","import type { Types } from '@opensearch-project/opensearch'\nimport type { ApiResponse } from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions'\n\nexport const ATTR_DB_OPENSEARCH_DURATION_MS = 'db.opensearch.duration_ms'\n\nexport const extractResponseAttributes = (\n res: ApiResponse\n): Record<string, string | number | boolean> => {\n const attrs: Record<string, string | number | boolean> = {}\n\n const { hostname, port } = res.meta.connection.url\n attrs[ATTR_SERVER_ADDRESS] = hostname\n if (port) attrs[ATTR_SERVER_PORT] = Number(port)\n if (res.statusCode != null)\n attrs[ATTR_HTTP_RESPONSE_STATUS_CODE] = res.statusCode\n\n const body = res.body as Types.Core_Search.ResponseBody | null | undefined\n if (body == null) return attrs\n\n if (body.took != null) attrs['db.opensearch.took'] = body.took\n if (body.timed_out != null) attrs['db.opensearch.timed_out'] = body.timed_out\n if (body.terminated_early != null)\n attrs['db.opensearch.terminated_early'] = body.terminated_early\n\n const shards = body._shards\n if (shards != null) {\n attrs['db.opensearch.shards.total'] = shards.total\n attrs['db.opensearch.shards.successful'] = shards.successful\n attrs['db.opensearch.shards.failed'] = shards.failed\n if (shards.skipped != null)\n attrs['db.opensearch.shards.skipped'] = shards.skipped\n }\n\n const phaseTook = body.phase_took\n if (phaseTook != null) {\n attrs['db.opensearch.phase_took.can_match'] = phaseTook.can_match\n attrs['db.opensearch.phase_took.dfs_pre_query'] = phaseTook.dfs_pre_query\n attrs['db.opensearch.phase_took.dfs_query'] = phaseTook.dfs_query\n attrs['db.opensearch.phase_took.expand'] = phaseTook.expand\n attrs['db.opensearch.phase_took.fetch'] = phaseTook.fetch\n attrs['db.opensearch.phase_took.query'] = phaseTook.query\n }\n\n const total = body.hits?.total\n if (total != null && typeof total === 'object') {\n attrs['db.opensearch.hits.total'] = total.value\n }\n\n return attrs\n}\n","import type { TransportRequestParams } from '@opensearch-project/opensearch/lib/Transport.js'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport const serializeBody = (\n params: TransportRequestParams,\n config: Pick<OpenSearchInstrumentationConfig, 'dbStatementSerializer'>\n): string | undefined => {\n if (!params.body) return undefined\n if (config.dbStatementSerializer === false) return undefined\n if (typeof config.dbStatementSerializer === 'function') {\n return config.dbStatementSerializer(params)\n }\n return typeof params.body === 'string'\n ? params.body\n : JSON.stringify(params.body)\n}\n","import type Transport from '@opensearch-project/opensearch/lib/Transport.js'\nimport type {\n ApiError,\n ApiResponse,\n TransportRequestCallback,\n TransportRequestOptions,\n TransportRequestParams,\n TransportRequestPromise,\n} from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\n context,\n SpanKind,\n SpanStatusCode,\n type Tracer,\n trace,\n} from '@opentelemetry/api'\nimport { suppressTracing } from '@opentelemetry/core'\nimport {\n ATTR_DB_COLLECTION_NAME,\n ATTR_DB_OPERATION_NAME,\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_SYSTEM_NAME,\n} from '@opentelemetry/semantic-conventions'\nimport { parsePath } from './parse-path'\nimport {\n ATTR_DB_OPENSEARCH_DURATION_MS,\n extractResponseAttributes,\n} from './response-attributes'\nimport { serializeBody } from './serialize-body'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport type OriginalRequest = (\n this: Transport,\n params: TransportRequestParams,\n options?: TransportRequestOptions\n) => TransportRequestPromise<ApiResponse>\n\ntype OriginalRequestWithCallback = (\n this: Transport,\n params: TransportRequestParams,\n options: TransportRequestOptions | undefined,\n callback: (err: ApiError, result: ApiResponse) => void\n) => TransportRequestCallback\n\nexport const createPatchedRequest = (\n getTracer: () => Tracer,\n config: OpenSearchInstrumentationConfig = {},\n original: OriginalRequest,\n clientVersion: string\n) => {\n function patchedRequest(\n params: TransportRequestParams,\n options?: TransportRequestOptions\n ): TransportRequestPromise<ApiResponse>\n function patchedRequest(\n params: TransportRequestParams,\n options: TransportRequestOptions | undefined,\n callback: (err: ApiError, result: ApiResponse) => void\n ): TransportRequestCallback\n function patchedRequest(\n this: Transport,\n params: TransportRequestParams,\n options?: TransportRequestOptions,\n callback?: (err: ApiError, result: ApiResponse) => void\n ): TransportRequestPromise<ApiResponse> | TransportRequestCallback {\n const { index, operation } = parsePath(params.path, params.method)\n const queryText = serializeBody(params, config)\n\n const span = getTracer().startSpan(\n [operation, index].filter(Boolean).join(' ') || params.path,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n [ATTR_DB_SYSTEM_NAME]: 'opensearch',\n ...(operation && { [ATTR_DB_OPERATION_NAME]: operation }),\n ...(index && { [ATTR_DB_COLLECTION_NAME]: index }),\n ...(queryText && { [ATTR_DB_QUERY_TEXT]: queryText }),\n },\n }\n )\n config.requestHook?.(span, params)\n\n const startTime = Date.now()\n\n const onSuccess = (res: ApiResponse) => {\n span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime)\n for (const [key, value] of Object.entries(\n extractResponseAttributes(res)\n )) {\n span.setAttribute(key, value)\n }\n if (config.moduleVersionAttributeName) {\n span.setAttribute(config.moduleVersionAttributeName, clientVersion)\n }\n config.responseHook?.(span, res)\n span.end()\n }\n\n const onError = (err: unknown) => {\n span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime)\n if (err instanceof Error) span.recordException(err)\n span.setStatus({ code: SpanStatusCode.ERROR })\n span.end()\n }\n\n const callCtx = config.suppressInternalInstrumentation\n ? suppressTracing(context.active())\n : trace.setSpan(context.active(), span)\n\n if (typeof callback === 'function') {\n const originalWithCallback = (\n original as OriginalRequestWithCallback\n ).bind(this)\n return context.with(callCtx, () =>\n originalWithCallback(params, options, (err, res) => {\n err ? onError(err) : onSuccess(res)\n callback(err, res)\n })\n )\n }\n\n const result = context.with(callCtx, () =>\n original.call(this, params, options)\n )\n const settled = result.then(\n (res: ApiResponse) => {\n onSuccess(res)\n return res\n },\n (err: unknown) => {\n onError(err)\n throw err\n }\n )\n return Object.assign(settled, { abort: result.abort })\n }\n\n return patchedRequest\n}\n","import Transport from '@opensearch-project/opensearch/lib/Transport.js'\nimport opensearchPkg from '@opensearch-project/opensearch/package.json' with {\n type: 'json',\n}\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport pkg from '../package.json' with { type: 'json' }\nimport { createPatchedRequest, type OriginalRequest } from './patch-request'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport type { OpenSearchInstrumentationConfig } from './types'\n\nconst PACKAGE_NAME: string = pkg.name\nconst PACKAGE_VERSION: string = pkg.version\nconst OPENSEARCH_CLIENT_VERSION: string = opensearchPkg.version\n\nexport class OpenSearchInstrumentation extends InstrumentationBase {\n private readonly osConfig: OpenSearchInstrumentationConfig\n private _original: OriginalRequest | undefined\n\n constructor(config: OpenSearchInstrumentationConfig = {}) {\n super(PACKAGE_NAME, PACKAGE_VERSION, { ...config, enabled: false })\n this.osConfig = config\n if (config.enabled !== false) {\n this.enable()\n }\n }\n\n protected init() {}\n\n override enable() {\n if (this._original) return\n this._original = Transport.prototype.request as OriginalRequest\n Transport.prototype.request = createPatchedRequest(\n () => this.tracer,\n this.osConfig,\n this._original,\n OPENSEARCH_CLIENT_VERSION\n )\n }\n\n override disable() {\n if (this._original) {\n Transport.prototype.request = this._original\n this._original = undefined\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["pkg.name","pkg.version"],"sources":["../package.json","../src/parse-path.ts","../src/response-attributes.ts","../src/serialize-body.ts","../src/patch-request.ts","../src/index.ts"],"sourcesContent":["","const METHOD_OPERATIONS: Record<string, string> = {\n PUT: 'indices.create',\n DELETE: 'indices.delete',\n}\n\nconst OPERATION_ALIASES: Record<string, string> = {\n doc: 'index',\n}\n\nexport const parsePath = (\n path: string,\n method?: string\n): { index?: string; operation?: string } => {\n const decoded = decodeURIComponent(path)\n const match = decoded.match(/^\\/(?:([^/_][^/]*)\\/)?_([^/]+)/)\n if (match) {\n const operation = OPERATION_ALIASES[match[2]] ?? match[2]\n return { index: match[1], operation }\n }\n\n if (method) {\n const operation = METHOD_OPERATIONS[method.toUpperCase()]\n if (operation) {\n const index = decoded.replace(/^\\//, '') || undefined\n return { index, operation }\n }\n }\n\n return {}\n}\n","import type { Types } from '@opensearch-project/opensearch'\nimport type { ApiResponse } from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions'\n\nexport const ATTR_DB_OPENSEARCH_DURATION_MS = 'db.opensearch.duration_ms'\n\nexport const extractResponseAttributes = (\n res: ApiResponse\n): Record<string, string | number | boolean> => {\n const attrs: Record<string, string | number | boolean> = {}\n\n const { hostname, port } = res.meta.connection.url\n attrs[ATTR_SERVER_ADDRESS] = hostname\n if (port) attrs[ATTR_SERVER_PORT] = Number(port)\n if (res.statusCode != null)\n attrs[ATTR_HTTP_RESPONSE_STATUS_CODE] = res.statusCode\n\n const body = res.body as Types.Core_Search.ResponseBody | null | undefined\n if (body == null) return attrs\n\n if (body.took != null) attrs['db.opensearch.took'] = body.took\n if (body.timed_out != null) attrs['db.opensearch.timed_out'] = body.timed_out\n if (body.terminated_early != null)\n attrs['db.opensearch.terminated_early'] = body.terminated_early\n\n const shards = body._shards\n if (shards != null) {\n attrs['db.opensearch.shards.total'] = shards.total\n attrs['db.opensearch.shards.successful'] = shards.successful\n attrs['db.opensearch.shards.failed'] = shards.failed\n if (shards.skipped != null)\n attrs['db.opensearch.shards.skipped'] = shards.skipped\n }\n\n const phaseTook = body.phase_took\n if (phaseTook != null) {\n attrs['db.opensearch.phase_took.can_match'] = phaseTook.can_match\n attrs['db.opensearch.phase_took.dfs_pre_query'] = phaseTook.dfs_pre_query\n attrs['db.opensearch.phase_took.dfs_query'] = phaseTook.dfs_query\n attrs['db.opensearch.phase_took.expand'] = phaseTook.expand\n attrs['db.opensearch.phase_took.fetch'] = phaseTook.fetch\n attrs['db.opensearch.phase_took.query'] = phaseTook.query\n }\n\n const total = body.hits?.total\n if (total != null && typeof total === 'object') {\n attrs['db.opensearch.hits.total'] = total.value\n }\n\n return attrs\n}\n","import type { TransportRequestParams } from '@opensearch-project/opensearch/lib/Transport.js'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport const serializeBody = (\n params: TransportRequestParams,\n config: Pick<OpenSearchInstrumentationConfig, 'dbStatementSerializer'>\n): string | undefined => {\n if (!params.body) return undefined\n if (config.dbStatementSerializer === false) return undefined\n if (typeof config.dbStatementSerializer === 'function') {\n return config.dbStatementSerializer(params)\n }\n return typeof params.body === 'string'\n ? params.body\n : JSON.stringify(params.body)\n}\n","import type Transport from '@opensearch-project/opensearch/lib/Transport.js'\nimport type {\n ApiError,\n ApiResponse,\n TransportRequestCallback,\n TransportRequestOptions,\n TransportRequestParams,\n TransportRequestPromise,\n} from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\n context,\n SpanKind,\n SpanStatusCode,\n type Tracer,\n trace,\n} from '@opentelemetry/api'\nimport { suppressTracing } from '@opentelemetry/core'\nimport {\n ATTR_DB_COLLECTION_NAME,\n ATTR_DB_OPERATION_NAME,\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_SYSTEM_NAME,\n} from '@opentelemetry/semantic-conventions'\nimport { parsePath } from './parse-path'\nimport {\n ATTR_DB_OPENSEARCH_DURATION_MS,\n extractResponseAttributes,\n} from './response-attributes'\nimport { serializeBody } from './serialize-body'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport type OriginalRequest = (\n this: Transport,\n params: TransportRequestParams,\n options?: TransportRequestOptions\n) => TransportRequestPromise<ApiResponse>\n\ntype OriginalRequestWithCallback = (\n this: Transport,\n params: TransportRequestParams,\n options: TransportRequestOptions | undefined,\n callback: (err: ApiError, result: ApiResponse) => void\n) => TransportRequestCallback\n\nexport const createPatchedRequest = (\n getTracer: () => Tracer,\n config: OpenSearchInstrumentationConfig = {},\n original: OriginalRequest,\n clientVersion: string\n) => {\n function patchedRequest(\n params: TransportRequestParams,\n options?: TransportRequestOptions\n ): TransportRequestPromise<ApiResponse>\n function patchedRequest(\n params: TransportRequestParams,\n options: TransportRequestOptions | undefined,\n callback: (err: ApiError, result: ApiResponse) => void\n ): TransportRequestCallback\n function patchedRequest(\n this: Transport,\n params: TransportRequestParams,\n options?: TransportRequestOptions,\n callback?: (err: ApiError, result: ApiResponse) => void\n ): TransportRequestPromise<ApiResponse> | TransportRequestCallback {\n const { index, operation } = parsePath(params.path, params.method)\n const queryText = serializeBody(params, config)\n\n const span = getTracer().startSpan(\n [operation, index].filter(Boolean).join(' ') || params.path,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n [ATTR_DB_SYSTEM_NAME]: 'opensearch',\n ...(operation && { [ATTR_DB_OPERATION_NAME]: operation }),\n ...(index && { [ATTR_DB_COLLECTION_NAME]: index }),\n ...(queryText && { [ATTR_DB_QUERY_TEXT]: queryText }),\n },\n }\n )\n config.requestHook?.(span, params)\n\n const startTime = Date.now()\n\n const onSuccess = (res: ApiResponse) => {\n span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime)\n for (const [key, value] of Object.entries(\n extractResponseAttributes(res)\n )) {\n span.setAttribute(key, value)\n }\n if (config.moduleVersionAttributeName) {\n span.setAttribute(config.moduleVersionAttributeName, clientVersion)\n }\n config.responseHook?.(span, res)\n span.end()\n }\n\n const onError = (err: unknown) => {\n span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime)\n if (err instanceof Error) span.recordException(err)\n span.setStatus({ code: SpanStatusCode.ERROR })\n span.end()\n }\n\n const callCtx = config.suppressInternalInstrumentation\n ? suppressTracing(context.active())\n : trace.setSpan(context.active(), span)\n\n if (typeof callback === 'function') {\n const originalWithCallback = (\n original as OriginalRequestWithCallback\n ).bind(this)\n return context.with(callCtx, () =>\n originalWithCallback(params, options, (err, res) => {\n err ? onError(err) : onSuccess(res)\n callback(err, res)\n })\n )\n }\n\n const result = context.with(callCtx, () =>\n original.call(this, params, options)\n )\n const settled = result.then(\n (res: ApiResponse) => {\n onSuccess(res)\n return res\n },\n (err: unknown) => {\n onError(err)\n throw err\n }\n )\n return Object.assign(settled, { abort: result.abort })\n }\n\n return patchedRequest\n}\n","import Transport from '@opensearch-project/opensearch/lib/Transport.js'\nimport opensearchPkg from '@opensearch-project/opensearch/package.json' with {\n type: 'json',\n}\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport pkg from '../package.json' with { type: 'json' }\nimport { createPatchedRequest, type OriginalRequest } from './patch-request'\nimport type { OpenSearchInstrumentationConfig } from './types'\n\nexport type { OpenSearchInstrumentationConfig } from './types'\n\nconst PACKAGE_NAME: string = pkg.name\nconst PACKAGE_VERSION: string = pkg.version\nconst OPENSEARCH_CLIENT_VERSION: string = opensearchPkg.version\n\nexport class OpenSearchInstrumentation extends InstrumentationBase {\n private readonly osConfig: OpenSearchInstrumentationConfig\n private _original: OriginalRequest | undefined\n\n constructor(config: OpenSearchInstrumentationConfig = {}) {\n super(PACKAGE_NAME, PACKAGE_VERSION, { ...config, enabled: false })\n this.osConfig = config\n if (config.enabled !== false) {\n this.enable()\n }\n }\n\n protected init() {}\n\n override enable() {\n if (this._original) return\n this._original = Transport.prototype.request as OriginalRequest\n Transport.prototype.request = createPatchedRequest(\n () => this.tracer,\n this.osConfig,\n this._original,\n OPENSEARCH_CLIENT_VERSION\n )\n }\n\n override disable() {\n if (this._original) {\n Transport.prototype.request = this._original\n this._original = undefined\n }\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/opentelemetry-instrumentation-opensearch",
3
- "version": "0.3.15",
3
+ "version": "0.4.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -18,35 +18,32 @@
18
18
  "build": "spark-build src/index.ts",
19
19
  "dev": "tsc --watch --noEmit",
20
20
  "lint": "biome check .",
21
- "test": "vitest run --passWithNoTests --coverage",
22
- "test:e2e": "vitest --config vitest.config.e2e.ts --run",
21
+ "test": "vitest run --passWithNoTests --coverage --fsModuleCachePath node_modules/.vitest-cache",
22
+ "test:e2e": "vitest --config vitest.config.e2e.ts --run --fsModuleCachePath node_modules/.vitest-cache",
23
23
  "typecheck": "vitest --typecheck.only --passWithNoTests --run"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@opensearch-project/opensearch": ">=2",
27
- "@opentelemetry/api": ">=1.9.0"
27
+ "@opentelemetry/api": ">=1.10.0 <1.11.0"
28
28
  },
29
29
  "dependencies": {
30
- "@opentelemetry/core": "2.11.0",
31
- "@opentelemetry/instrumentation": "0.222.0",
32
- "@opentelemetry/semantic-conventions": "1.43.0"
30
+ "@opentelemetry/core": "3.0.0",
31
+ "@opentelemetry/instrumentation": "0.300.0",
32
+ "@opentelemetry/semantic-conventions": "1.44.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@biomejs/biome": "2.5.14",
36
- "@opensearch-project/opensearch": "3.6.0",
37
- "@opentelemetry/api": "1.9.1",
38
- "@opentelemetry/instrumentation-http": "0.222.0",
39
- "@opentelemetry/instrumentation-undici": "0.32.0",
40
- "@opentelemetry/sdk-trace-base": "2.11.0",
41
- "@opentelemetry/sdk-trace-node": "2.11.0",
42
- "@sebspark/tsconfig": "*",
43
- "@testcontainers/opensearch": "12.1.0",
35
+ "@biomejs/biome": "2.6.4",
36
+ "@opensearch-project/opensearch": "3.9.0",
37
+ "@opentelemetry/api": "1.10.0",
38
+ "@opentelemetry/context-async-hooks": "3.0.0",
39
+ "@opentelemetry/instrumentation-http": "0.300.0",
40
+ "@opentelemetry/instrumentation-undici": "0.34.0",
41
+ "@opentelemetry/sdk-trace": "3.0.0",
42
+ "@sebspark/tsconfig": "3.0.28",
43
+ "@testcontainers/opensearch": "12.2.1",
44
44
  "typescript": "7.0.2",
45
- "vite": "8.3.0",
46
- "vitest": "5.0.1"
47
- },
48
- "resolutions": {
49
- "protobufjs": "8.8.0"
45
+ "vite": "8.3.5",
46
+ "vitest": "5.0.5"
50
47
  },
51
48
  "repository": {
52
49
  "type": "git",