@sebspark/opentelemetry-instrumentation-opensearch 0.2.0 → 0.2.2
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 +47 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +8 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -95,22 +95,59 @@ Set at span creation, before the request is sent.
|
|
|
95
95
|
|
|
96
96
|
Set on the span after a successful response.
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
#### Always present on search responses
|
|
99
|
+
|
|
100
|
+
| Attribute | Type | Example | Description |
|
|
99
101
|
|---|---|---|---|
|
|
100
102
|
| `server.address` | string | `opensearch.example.com` | Hostname of the node that handled the request |
|
|
101
103
|
| `server.port` | number | `9200` | Omitted when using the default port for the protocol |
|
|
102
104
|
| `http.response.status_code` | number | `200` | HTTP status code of the response |
|
|
103
105
|
| `db.opensearch.took` | number | `5` | Time in milliseconds OpenSearch spent executing the request |
|
|
104
106
|
| `db.opensearch.timed_out` | boolean | `false` | Whether the request hit the `timeout` threshold |
|
|
105
|
-
| `db.opensearch.terminated_early` | boolean | `true` | Whether the request hit the `terminate_after` document limit and returned partial results. Omitted when not present |
|
|
106
107
|
| `db.opensearch.shards.total` | number | `5` | Total number of shards the request was executed against |
|
|
107
108
|
| `db.opensearch.shards.successful` | number | `5` | Number of shards that responded successfully |
|
|
108
109
|
| `db.opensearch.shards.failed` | number | `0` | Number of shards that failed |
|
|
109
|
-
| `db.opensearch.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
|
116
|
-
|
|
110
|
+
| `db.opensearch.hits.total` | number | `42` | Total number of matching documents |
|
|
111
|
+
|
|
112
|
+
#### Conditionally present
|
|
113
|
+
|
|
114
|
+
These attributes only appear when specific conditions are met, either because OpenSearch omits them by default or because they require the query to opt in.
|
|
115
|
+
|
|
116
|
+
| Attribute | Type | Condition | When to use |
|
|
117
|
+
|---|---|---|---|
|
|
118
|
+
| `db.opensearch.shards.skipped` | number | Present when OpenSearch skips shards, e.g. when using `_routing` or shard-level filtering | Useful for verifying that routing is working as intended — a high skipped count means fewer shards are doing work |
|
|
119
|
+
| `db.opensearch.terminated_early` | boolean | Present when the query includes `terminate_after: N` in the request body | Use `terminate_after` when you want to cap result collection for performance reasons (e.g. existence checks). The attribute tells you whether the cap was actually hit |
|
|
120
|
+
| `db.opensearch.phase_took.*` | number | Present when the request uses `search_type: 'dfs_query_then_fetch'` | Use DFS search type when accurate relevance scoring across shards matters (e.g. small indices or cross-shard ranking). The phase breakdown lets you identify which phase dominates latency |
|
|
121
|
+
|
|
122
|
+
To enable `phase_took`, set `search_type` on the request:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
client.search({
|
|
126
|
+
index: 'my_index',
|
|
127
|
+
search_type: 'dfs_query_then_fetch',
|
|
128
|
+
body: { query: { ... } },
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To enable `terminated_early`, set `terminate_after` in the query body:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
client.search({
|
|
136
|
+
index: 'my_index',
|
|
137
|
+
body: {
|
|
138
|
+
terminate_after: 1000,
|
|
139
|
+
query: { ... },
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### `db.opensearch.phase_took.*` fields
|
|
145
|
+
|
|
146
|
+
| Attribute | Description |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `db.opensearch.phase_took.can_match` | Time spent determining which shards can match the query |
|
|
149
|
+
| `db.opensearch.phase_took.dfs_pre_query` | Time spent collecting term statistics across shards before the query phase |
|
|
150
|
+
| `db.opensearch.phase_took.dfs_query` | Time spent executing the query using globally collected term statistics |
|
|
151
|
+
| `db.opensearch.phase_took.expand` | Time spent expanding results (e.g. for collapse/inner hits) |
|
|
152
|
+
| `db.opensearch.phase_took.fetch` | Time spent fetching document source and fields |
|
|
153
|
+
| `db.opensearch.phase_took.query` | Time spent in the standard query phase |
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;;UAOiB,+BAAA,SAAwC,qBAAA;EACvD,qBAAA,aAAkC,MAAA,EAAQ,sBAAA;EAC1C,WAAA,IAAe,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,sBAAA;EACnC,YAAA,IAAgB,IAAA,EAAM,IAAA,EAAM,QAAA,EAAU,WAAA;EACtC,+BAAA;EACA,0BAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;;UAOiB,+BAAA,SAAwC,qBAAA;EACvD,qBAAA,aAAkC,MAAA,EAAQ,sBAAA;EAC1C,WAAA,IAAe,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,sBAAA;EACnC,YAAA,IAAgB,IAAA,EAAM,IAAA,EAAM,QAAA,EAAU,WAAA;EACtC,+BAAA;EACA,0BAAA;AAAA;;;cCGW,yBAAA,SAAkC,mBAAA;EAAA,iBAC5B,QAAA;EAAA,QACT,SAAA;cAEI,MAAA,GAAQ,+BAAA;EAAA,UAQV,IAAA,CAAA;EAED,MAAA,CAAA;EAWA,OAAA,CAAA;AAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,8 @@ import { SpanKind, SpanStatusCode, context, trace } from "@opentelemetry/api";
|
|
|
5
5
|
import { suppressTracing } from "@opentelemetry/core";
|
|
6
6
|
import { ATTR_DB_OPERATION_NAME, ATTR_DB_QUERY_TEXT, ATTR_DB_SYSTEM_NAME, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT } from "@opentelemetry/semantic-conventions";
|
|
7
7
|
//#region package.json
|
|
8
|
-
var
|
|
8
|
+
var name = "@sebspark/opentelemetry-instrumentation-opensearch";
|
|
9
|
+
var version = "0.2.2";
|
|
9
10
|
//#endregion
|
|
10
11
|
//#region src/parse-path.ts
|
|
11
12
|
const parsePath = (path) => {
|
|
@@ -18,6 +19,7 @@ const parsePath = (path) => {
|
|
|
18
19
|
};
|
|
19
20
|
//#endregion
|
|
20
21
|
//#region src/response-attributes.ts
|
|
22
|
+
const ATTR_DB_OPENSEARCH_DURATION_MS = "db.opensearch.duration_ms";
|
|
21
23
|
const extractResponseAttributes = (res) => {
|
|
22
24
|
const attrs = {};
|
|
23
25
|
const { hostname, port } = res.meta.connection.url;
|
|
@@ -73,13 +75,16 @@ const createPatchedRequest = (getTracer, config = {}, original, clientVersion) =
|
|
|
73
75
|
}
|
|
74
76
|
});
|
|
75
77
|
config.requestHook?.(span, params);
|
|
78
|
+
const startTime = Date.now();
|
|
76
79
|
const onSuccess = (res) => {
|
|
80
|
+
span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime);
|
|
77
81
|
for (const [key, value] of Object.entries(extractResponseAttributes(res))) span.setAttribute(key, value);
|
|
78
82
|
if (config.moduleVersionAttributeName) span.setAttribute(config.moduleVersionAttributeName, clientVersion);
|
|
79
83
|
config.responseHook?.(span, res);
|
|
80
84
|
span.end();
|
|
81
85
|
};
|
|
82
86
|
const onError = (err) => {
|
|
87
|
+
span.setAttribute(ATTR_DB_OPENSEARCH_DURATION_MS, Date.now() - startTime);
|
|
83
88
|
if (err instanceof Error) span.recordException(err);
|
|
84
89
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
85
90
|
span.end();
|
|
@@ -106,13 +111,14 @@ const createPatchedRequest = (getTracer, config = {}, original, clientVersion) =
|
|
|
106
111
|
};
|
|
107
112
|
//#endregion
|
|
108
113
|
//#region src/index.ts
|
|
114
|
+
const PACKAGE_NAME = name;
|
|
109
115
|
const PACKAGE_VERSION = version;
|
|
110
116
|
const OPENSEARCH_CLIENT_VERSION = opensearchPkg.version;
|
|
111
117
|
var OpenSearchInstrumentation = class extends InstrumentationBase {
|
|
112
118
|
osConfig;
|
|
113
119
|
_original;
|
|
114
120
|
constructor(config = {}) {
|
|
115
|
-
super(
|
|
121
|
+
super(PACKAGE_NAME, PACKAGE_VERSION, {
|
|
116
122
|
...config,
|
|
117
123
|
enabled: false
|
|
118
124
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["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":["","export const parsePath = (\n path: string\n): { index?: string; operation?: string } => {\n const match = path.match(/^\\/(?:([^/_][^/]*)\\/)?_([^/]+)/)\n if (!match) return {}\n return { index: match[1], operation: match[2] }\n}\n","import type { Types } from '@opensearch-project/opensearch'\nimport type { ApiResponse } from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n} from '@opentelemetry/semantic-conventions'\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['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_OPERATION_NAME,\n ATTR_DB_QUERY_TEXT,\n ATTR_DB_SYSTEM_NAME,\n} from '@opentelemetry/semantic-conventions'\nimport { parsePath } from './parse-path'\nimport { extractResponseAttributes } 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)\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 && { 'db.opensearch.index': index }),\n ...(queryText && { [ATTR_DB_QUERY_TEXT]: queryText }),\n },\n }\n )\n config.requestHook?.(span, params)\n\n const onSuccess = (res: ApiResponse) => {\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 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_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(\n '@sebspark/opentelemetry-instrumentation-opensearch',\n PACKAGE_VERSION,\n { ...config, enabled: false }\n )\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":["","export const parsePath = (\n path: string\n): { index?: string; operation?: string } => {\n const match = path.match(/^\\/(?:([^/_][^/]*)\\/)?_([^/]+)/)\n if (!match) return {}\n return { index: match[1], operation: match[2] }\n}\n","import type { Types } from '@opensearch-project/opensearch'\nimport type { ApiResponse } from '@opensearch-project/opensearch/lib/Transport.js'\nimport {\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['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_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)\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 && { 'db.opensearch.index': 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.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -27,17 +27,17 @@
|
|
|
27
27
|
"@opentelemetry/api": ">=1.9.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@opentelemetry/core": "2.6.
|
|
31
|
-
"@opentelemetry/instrumentation": "0.
|
|
30
|
+
"@opentelemetry/core": "2.6.1",
|
|
31
|
+
"@opentelemetry/instrumentation": "0.214.0",
|
|
32
32
|
"@opentelemetry/semantic-conventions": "1.40.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@opensearch-project/opensearch": "3.5.1",
|
|
36
|
-
"@opentelemetry/api": "1.9.
|
|
37
|
-
"@opentelemetry/instrumentation-http": "0.
|
|
38
|
-
"@opentelemetry/instrumentation-undici": "0.
|
|
39
|
-
"@opentelemetry/sdk-trace-base": "2.6.
|
|
40
|
-
"@opentelemetry/sdk-trace-node": "2.6.
|
|
36
|
+
"@opentelemetry/api": "1.9.1",
|
|
37
|
+
"@opentelemetry/instrumentation-http": "0.214.0",
|
|
38
|
+
"@opentelemetry/instrumentation-undici": "0.24.0",
|
|
39
|
+
"@opentelemetry/sdk-trace-base": "2.6.1",
|
|
40
|
+
"@opentelemetry/sdk-trace-node": "2.6.1",
|
|
41
41
|
"@testcontainers/opensearch": "11.13.0"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|