@uphold/opentelemetry-instrumentation-connect-node 0.1.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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +11 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +83 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/interceptor.d.ts +5 -0
- package/dist/interceptor.d.ts.map +1 -0
- package/dist/interceptor.js +133 -0
- package/dist/interceptor.js.map +1 -0
- package/dist/internal-types.d.ts +6 -0
- package/dist/internal-types.d.ts.map +1 -0
- package/dist/internal-types.js +3 -0
- package/dist/internal-types.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +76 -0
- package/dist/utils.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Uphold
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @uphold/opentelemetry-instrumentation-connect-node
|
|
2
|
+
|
|
3
|
+
OpenTelemetry instrumentation for [`@connectrpc/connect-node`](https://www.npmjs.com/package/@connectrpc/connect-node) RPC client and server.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @uphold/opentelemetry-instrumentation-connect-node
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Supported versions
|
|
12
|
+
|
|
13
|
+
- [`@connectrpc/connect-node`](https://www.npmjs.com/package/@connectrpc/connect-node) versions `^2.0.0`
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Enable the instrumentation offered by this package, like so:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
|
|
21
|
+
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
|
|
22
|
+
const { ConnectNodeInstrumentation } = require('@uphold/opentelemetry-instrumentation-connect-node');
|
|
23
|
+
|
|
24
|
+
const provider = new NodeTracerProvider({
|
|
25
|
+
spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())]
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
provider.register();
|
|
29
|
+
|
|
30
|
+
registerInstrumentations({
|
|
31
|
+
instrumentations: [new ConnectNodeInstrumentation()]
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Instrumentation options
|
|
36
|
+
|
|
37
|
+
The instrumentation accepts the following configuration:
|
|
38
|
+
|
|
39
|
+
| Options | Type | Description |
|
|
40
|
+
| ------- | ---- | ----------- |
|
|
41
|
+
| `ignoreRequest` | `IgnoreRequestMatcher` | The instrumentation will not trace any requests return `true` from the function. |
|
|
42
|
+
| `metadataToSpanAttributes` | `MetadataToSpanAttributes` | List of case insensitive metadata to convert to span attributes. Client and server (outgoing requests, incoming responses) metadata attributes will be converted to span attributes in the form of `rpc.{rpc_system}{request/response}.metadata.metadata_key`, e.g. `rpc.grpc.response.metadata.date` |
|
|
43
|
+
|
|
44
|
+
## Caveats
|
|
45
|
+
|
|
46
|
+
<details>
|
|
47
|
+
<summary>Non-unary requests will not be traced</summary>
|
|
48
|
+
<br>
|
|
49
|
+
|
|
50
|
+
Only unary requests will be traced. Server streaming, client streaming and bidirectional streaming are not supported due to a bug in context propagation for generator functions. Supposedly, there are workarounds but none of them worked. See https://github.com/open-telemetry/opentelemetry-js/issues/2951 and https://github.com/nodejs/node/issues/42237 for more details.
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
## Tests
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
npm test
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
Licensed under MIT.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,gCAAgC,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectNodeInstrumentation = void 0;
|
|
4
|
+
var instrumentation_1 = require("./instrumentation");
|
|
5
|
+
Object.defineProperty(exports, "ConnectNodeInstrumentation", { enumerable: true, get: function () { return instrumentation_1.ConnectNodeInstrumentation; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAA+D;AAAtD,6HAAA,0BAA0B,OAAA","sourcesContent":["export { ConnectNodeInstrumentation } from './instrumentation';\nexport type { ConnectNodeInstrumentationConfig } from './types';\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ConnectNodeInstrumentationConfig } from './types';
|
|
2
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
3
|
+
export declare class ConnectNodeInstrumentation extends InstrumentationBase<ConnectNodeInstrumentationConfig> {
|
|
4
|
+
constructor(config?: ConnectNodeInstrumentationConfig);
|
|
5
|
+
init(): InstrumentationNodeModuleDefinition[];
|
|
6
|
+
private _patchCreateConnectTransport;
|
|
7
|
+
private _patchCreateGrpcTransport;
|
|
8
|
+
private _patchCreateGrpcWebTransport;
|
|
9
|
+
private _patchConnectNodeAdapter;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gCAAgC,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,mCAAmC,EAAE,MAAM,gCAAgC,CAAC;AAI1G,qBAAa,0BAA2B,SAAQ,mBAAmB,CAAC,gCAAgC,CAAC;gBACvF,MAAM,GAAE,gCAAqC;IAIzD,IAAI;IA2BJ,OAAO,CAAC,4BAA4B;IAepC,OAAO,CAAC,yBAAyB;IAejC,OAAO,CAAC,4BAA4B;IAepC,OAAO,CAAC,wBAAwB;CAcjC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ConnectNodeInstrumentation = void 0;
|
|
7
|
+
const instrumentation_1 = require("@opentelemetry/instrumentation");
|
|
8
|
+
const interceptor_1 = require("./interceptor");
|
|
9
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
10
|
+
class ConnectNodeInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
super('@uphold/opentelemetry-instrumentation-connect-node', package_json_1.default.version, config);
|
|
13
|
+
}
|
|
14
|
+
init() {
|
|
15
|
+
return [
|
|
16
|
+
new instrumentation_1.InstrumentationNodeModuleDefinition('@connectrpc/connect-node', ['^2.0.0'], moduleExports => {
|
|
17
|
+
this._wrap(moduleExports, 'createConnectTransport', this._patchCreateConnectTransport());
|
|
18
|
+
this._wrap(moduleExports, 'createGrpcTransport', this._patchCreateGrpcTransport());
|
|
19
|
+
this._wrap(moduleExports, 'createGrpcWebTransport', this._patchCreateGrpcWebTransport());
|
|
20
|
+
this._wrap(moduleExports, 'connectNodeAdapter', this._patchConnectNodeAdapter());
|
|
21
|
+
return moduleExports;
|
|
22
|
+
}, moduleExports => {
|
|
23
|
+
if (moduleExports === undefined) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this._unwrap(moduleExports, 'createConnectTransport');
|
|
27
|
+
this._unwrap(moduleExports, 'createGrpcTransport');
|
|
28
|
+
this._unwrap(moduleExports, 'createGrpcWebTransport');
|
|
29
|
+
this._unwrap(moduleExports, 'connectNodeAdapter');
|
|
30
|
+
})
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
_patchCreateConnectTransport() {
|
|
34
|
+
return (original) => {
|
|
35
|
+
this._diag.debug('patched createConnectTransport');
|
|
36
|
+
return (options) => {
|
|
37
|
+
const interceptor = (0, interceptor_1.createInterceptor)(this.getConfig(), this._diag, this.tracer, 'client');
|
|
38
|
+
return original({
|
|
39
|
+
...options,
|
|
40
|
+
interceptors: [interceptor, ...(options.interceptors ?? [])]
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
_patchCreateGrpcTransport() {
|
|
46
|
+
return (original) => {
|
|
47
|
+
this._diag.debug('patched createGrpcTransport');
|
|
48
|
+
return (options) => {
|
|
49
|
+
const interceptor = (0, interceptor_1.createInterceptor)(this.getConfig(), this._diag, this.tracer, 'client');
|
|
50
|
+
return original({
|
|
51
|
+
...options,
|
|
52
|
+
interceptors: [interceptor, ...(options.interceptors ?? [])]
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
_patchCreateGrpcWebTransport() {
|
|
58
|
+
return (original) => {
|
|
59
|
+
this._diag.debug('patched createGrpcWebTransport');
|
|
60
|
+
return (options) => {
|
|
61
|
+
const interceptor = (0, interceptor_1.createInterceptor)(this.getConfig(), this._diag, this.tracer, 'client');
|
|
62
|
+
return original({
|
|
63
|
+
...options,
|
|
64
|
+
interceptors: [interceptor, ...(options.interceptors ?? [])]
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
_patchConnectNodeAdapter() {
|
|
70
|
+
return (original) => {
|
|
71
|
+
this._diag.debug('patched connectNodeAdapter');
|
|
72
|
+
return (options) => {
|
|
73
|
+
const interceptor = (0, interceptor_1.createInterceptor)(this.getConfig(), this._diag, this.tracer, 'server');
|
|
74
|
+
return original({
|
|
75
|
+
...options,
|
|
76
|
+
interceptors: [interceptor, ...(options.interceptors ?? [])]
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.ConnectNodeInstrumentation = ConnectNodeInstrumentation;
|
|
83
|
+
//# sourceMappingURL=instrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ConnectNodeAdapterOptions,\n ConnectTransportOptions,\n GrpcTransportOptions,\n GrpcWebTransportOptions,\n connectNodeAdapter,\n createConnectTransport,\n createGrpcTransport,\n createGrpcWebTransport\n} from '@connectrpc/connect-node';\nimport { ConnectNodeInstrumentationConfig } from './types';\nimport { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';\nimport { createInterceptor } from './interceptor';\nimport packageJson from '../package.json';\n\nexport class ConnectNodeInstrumentation extends InstrumentationBase<ConnectNodeInstrumentationConfig> {\n constructor(config: ConnectNodeInstrumentationConfig = {}) {\n super('@uphold/opentelemetry-instrumentation-connect-node', packageJson.version, config);\n }\n\n init() {\n return [\n new InstrumentationNodeModuleDefinition(\n '@connectrpc/connect-node',\n ['^2.0.0'],\n moduleExports => {\n this._wrap(moduleExports, 'createConnectTransport', this._patchCreateConnectTransport());\n this._wrap(moduleExports, 'createGrpcTransport', this._patchCreateGrpcTransport());\n this._wrap(moduleExports, 'createGrpcWebTransport', this._patchCreateGrpcWebTransport());\n this._wrap(moduleExports, 'connectNodeAdapter', this._patchConnectNodeAdapter());\n\n return moduleExports;\n },\n moduleExports => {\n if (moduleExports === undefined) {\n return;\n }\n\n this._unwrap(moduleExports, 'createConnectTransport');\n this._unwrap(moduleExports, 'createGrpcTransport');\n this._unwrap(moduleExports, 'createGrpcWebTransport');\n this._unwrap(moduleExports, 'connectNodeAdapter');\n }\n )\n ];\n }\n\n private _patchCreateConnectTransport() {\n return (original: typeof createConnectTransport) => {\n this._diag.debug('patched createConnectTransport');\n\n return (options: ConnectTransportOptions) => {\n const interceptor = createInterceptor(this.getConfig(), this._diag, this.tracer, 'client');\n\n return original({\n ...options,\n interceptors: [interceptor, ...(options.interceptors ?? [])]\n });\n };\n };\n }\n\n private _patchCreateGrpcTransport() {\n return (original: typeof createGrpcTransport) => {\n this._diag.debug('patched createGrpcTransport');\n\n return (options: GrpcTransportOptions) => {\n const interceptor = createInterceptor(this.getConfig(), this._diag, this.tracer, 'client');\n\n return original({\n ...options,\n interceptors: [interceptor, ...(options.interceptors ?? [])]\n });\n };\n };\n }\n\n private _patchCreateGrpcWebTransport() {\n return (original: typeof createGrpcWebTransport) => {\n this._diag.debug('patched createGrpcWebTransport');\n\n return (options: GrpcWebTransportOptions) => {\n const interceptor = createInterceptor(this.getConfig(), this._diag, this.tracer, 'client');\n\n return original({\n ...options,\n interceptors: [interceptor, ...(options.interceptors ?? [])]\n });\n };\n };\n }\n\n private _patchConnectNodeAdapter() {\n return (original: typeof connectNodeAdapter) => {\n this._diag.debug('patched connectNodeAdapter');\n\n return (options: ConnectNodeAdapterOptions) => {\n const interceptor = createInterceptor(this.getConfig(), this._diag, this.tracer, 'server');\n\n return original({\n ...options,\n interceptors: [interceptor, ...(options.interceptors ?? [])]\n });\n };\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ConnectNodeInstrumentationConfig } from './types';
|
|
2
|
+
import { DiagLogger, Tracer } from '@opentelemetry/api';
|
|
3
|
+
import { InterceptorAnyFn, RpcKind } from './internal-types';
|
|
4
|
+
export declare const createInterceptor: (config: ConnectNodeInstrumentationConfig, diag: DiagLogger, tracer: Tracer, kind: RpcKind) => (next: InterceptorAnyFn) => InterceptorAnyFn;
|
|
5
|
+
//# sourceMappingURL=interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,gCAAgC,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAkB,MAAM,EAA+B,MAAM,oBAAoB,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAY,MAAM,kBAAkB,CAAC;AAuHvE,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,gCAAgC,EACxC,MAAM,UAAU,EAChB,QAAQ,MAAM,EACd,MAAM,OAAO,MAML,MAAM,gBAAgB,KAAG,gBA+ClC,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createInterceptor = void 0;
|
|
4
|
+
const incubating_1 = require("@opentelemetry/semantic-conventions/incubating");
|
|
5
|
+
const api_1 = require("@opentelemetry/api");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const lodash_1 = require("lodash");
|
|
8
|
+
const instrumentation_1 = require("@opentelemetry/instrumentation");
|
|
9
|
+
const createMetadataAttributesExtractor = (config, kind, phase) => {
|
|
10
|
+
const metadataToSpanAttributes = config.metadataToSpanAttributes?.[kind]?.[phase] ?? [];
|
|
11
|
+
const mappings = new Map(metadataToSpanAttributes.map(value => [value.toLowerCase(), value.toLowerCase().replace(/-/g, '_')]));
|
|
12
|
+
if (mappings.size === 0) {
|
|
13
|
+
return () => ({});
|
|
14
|
+
}
|
|
15
|
+
// See: https://opentelemetry.io/docs/specs/semconv/rpc/
|
|
16
|
+
return (span, metadata) => {
|
|
17
|
+
const rpcSystem = span.attributes[incubating_1.ATTR_RPC_SYSTEM];
|
|
18
|
+
const attributes = {};
|
|
19
|
+
if (rpcSystem && metadata) {
|
|
20
|
+
for (const [key, mappedKey] of mappings) {
|
|
21
|
+
const value = metadata.get(key);
|
|
22
|
+
if (value != null) {
|
|
23
|
+
attributes[`grpc.${rpcSystem}.${phase}.metadata.${mappedKey}`] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return attributes;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const createStartSpan = (config, tracer, kind) => {
|
|
31
|
+
const extractMetadata = createMetadataAttributesExtractor(config, kind, 'request');
|
|
32
|
+
const parseUrl = (0, lodash_1.memoize)((url) => new URL(url));
|
|
33
|
+
// See: https://opentelemetry.io/docs/specs/semconv/rpc/
|
|
34
|
+
return (req) => {
|
|
35
|
+
const fullName = `${req.service.typeName}/${req.method.name}`;
|
|
36
|
+
const url = parseUrl(req.url);
|
|
37
|
+
const rpcSystem = (0, utils_1.resolveRpcSystem)(req.header);
|
|
38
|
+
const span = tracer.startSpan(fullName, {
|
|
39
|
+
attributes: {
|
|
40
|
+
[incubating_1.ATTR_RPC_METHOD]: req.method.name,
|
|
41
|
+
[incubating_1.ATTR_RPC_SERVICE]: req.service.typeName,
|
|
42
|
+
[incubating_1.ATTR_RPC_SYSTEM]: rpcSystem,
|
|
43
|
+
[incubating_1.ATTR_SERVER_ADDRESS]: url.hostname,
|
|
44
|
+
[incubating_1.ATTR_SERVER_PORT]: url.port || undefined
|
|
45
|
+
},
|
|
46
|
+
kind: (0, utils_1.rpcKindToSpanKind)(kind)
|
|
47
|
+
});
|
|
48
|
+
span.setAttributes(extractMetadata(span, req.header));
|
|
49
|
+
return span;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const createEndSpanWithSuccess = (config, kind) => {
|
|
53
|
+
const extractMetadata = createMetadataAttributesExtractor(config, kind, 'response');
|
|
54
|
+
// See: https://opentelemetry.io/docs/specs/semconv/rpc/
|
|
55
|
+
return (span, res) => {
|
|
56
|
+
if (span.ended) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const rpcSystem = span.attributes[incubating_1.ATTR_RPC_SYSTEM];
|
|
60
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
61
|
+
if (rpcSystem === 'grpc') {
|
|
62
|
+
span.setAttribute(incubating_1.ATTR_RPC_GRPC_STATUS_CODE, 0);
|
|
63
|
+
}
|
|
64
|
+
span.setAttributes(extractMetadata(span, res.header));
|
|
65
|
+
span.end();
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const createEndSpanWithError = (config, kind) => {
|
|
69
|
+
const extractMetadata = createMetadataAttributesExtractor(config, kind, 'response');
|
|
70
|
+
// See: https://opentelemetry.io/docs/specs/semconv/rpc/
|
|
71
|
+
return (span, err) => {
|
|
72
|
+
if (span.ended) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const error = err instanceof Error ? err : undefined;
|
|
76
|
+
const connectError = (0, utils_1.isConnectError)(error) ? error : undefined;
|
|
77
|
+
const rpcSystem = span.attributes[incubating_1.ATTR_RPC_SYSTEM];
|
|
78
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error?.message });
|
|
79
|
+
if (rpcSystem === 'grpc') {
|
|
80
|
+
span.setAttribute(incubating_1.ATTR_RPC_GRPC_STATUS_CODE, connectError?.code ?? 2);
|
|
81
|
+
}
|
|
82
|
+
else if (rpcSystem === 'connect_rpc') {
|
|
83
|
+
span.setAttribute(incubating_1.ATTR_RPC_CONNECT_RPC_ERROR_CODE, (0, utils_1.errorCodeToString)(connectError?.code));
|
|
84
|
+
}
|
|
85
|
+
span.setAttributes(extractMetadata(span, connectError?.metadata));
|
|
86
|
+
if (error) {
|
|
87
|
+
span.recordException(error);
|
|
88
|
+
}
|
|
89
|
+
span.end();
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
const createInterceptor = (config, diag, tracer, kind) => {
|
|
93
|
+
const startSpan = createStartSpan(config, tracer, kind);
|
|
94
|
+
const endSpanWithSuccess = createEndSpanWithSuccess(config, kind);
|
|
95
|
+
const endSpanWithError = createEndSpanWithError(config, kind);
|
|
96
|
+
return (next) => async (req) => {
|
|
97
|
+
// Only unary requests are supported due to a bug in Node.js async context propagation on generator functions.
|
|
98
|
+
// See https://github.com/open-telemetry/opentelemetry-js/issues/2951 and https://github.com/nodejs/node/issues/42237
|
|
99
|
+
if (req.method.methodKind !== 'unary') {
|
|
100
|
+
return await next(req);
|
|
101
|
+
}
|
|
102
|
+
const shouldIgnoreRequest = (0, instrumentation_1.safeExecuteInTheMiddle)(() => config.ignoreRequest?.(req) === true, (err) => {
|
|
103
|
+
if (err != null) {
|
|
104
|
+
diag.error('caught ignoreRequest error: ', err);
|
|
105
|
+
}
|
|
106
|
+
}, true);
|
|
107
|
+
if (shouldIgnoreRequest) {
|
|
108
|
+
return await next(req);
|
|
109
|
+
}
|
|
110
|
+
let ctx = api_1.context.active();
|
|
111
|
+
const span = startSpan(req);
|
|
112
|
+
if (kind === 'server') {
|
|
113
|
+
ctx = api_1.propagation.extract(ctx, req.header);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
api_1.propagation.inject(ctx, req.header);
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
return await api_1.context.with(api_1.trace.setSpan(ctx, span), async () => {
|
|
120
|
+
next = api_1.context.bind(ctx, next);
|
|
121
|
+
const res = await next(req);
|
|
122
|
+
endSpanWithSuccess(span, res);
|
|
123
|
+
return res;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
endSpanWithError(span, err);
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
exports.createInterceptor = createInterceptor;
|
|
133
|
+
//# sourceMappingURL=interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.js","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":";;;AAAA,+EAQwD;AAGxD,4CAAqG;AAGrG,mCAAiG;AACjG,mCAAiC;AACjC,oEAAwE;AAExE,MAAM,iCAAiC,GAAG,CACxC,MAAwC,EACxC,IAAa,EACb,KAAe,EACf,EAAE;IACF,MAAM,wBAAwB,GAAG,MAAM,CAAC,wBAAwB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACxF,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,wBAAwB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CACrG,CAAC;IAEF,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IAED,wDAAwD;IACxD,OAAO,CAAC,IAAU,EAAE,QAAkB,EAAE,EAAE;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,4BAAe,CAAC,CAAC;QACnD,MAAM,UAAU,GAA2B,EAAE,CAAC;QAE9C,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;YAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEhC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,UAAU,CAAC,QAAQ,SAAS,IAAI,KAAK,aAAa,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC;gBACzE,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,MAAwC,EAAE,MAAc,EAAE,IAAa,EAAE,EAAE;IAClG,MAAM,eAAe,GAAG,iCAAiC,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IACnF,MAAM,QAAQ,GAAG,IAAA,gBAAO,EAAC,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAExD,wDAAwD;IACxD,OAAO,CAAC,GAAiC,EAAE,EAAE;QAC3C,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAA,wBAAgB,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE/C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE;YACtC,UAAU,EAAE;gBACV,CAAC,4BAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI;gBAClC,CAAC,6BAAgB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ;gBACxC,CAAC,4BAAe,CAAC,EAAE,SAAS;gBAC5B,CAAC,gCAAmB,CAAC,EAAE,GAAG,CAAC,QAAQ;gBACnC,CAAC,6BAAgB,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;aAC1C;YACD,IAAI,EAAE,IAAA,yBAAiB,EAAC,IAAI,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,IAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAE9D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,MAAwC,EAAE,IAAa,EAAE,EAAE;IAC3F,MAAM,eAAe,GAAG,iCAAiC,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAEpF,wDAAwD;IACxD,OAAO,CAAC,IAAU,EAAE,GAAmC,EAAE,EAAE;QACzD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,4BAAe,CAAC,CAAC;QAEnD,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,oBAAc,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5C,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,sCAAyB,EAAE,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,IAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,MAAwC,EAAE,IAAa,EAAE,EAAE;IACzF,MAAM,eAAe,GAAG,iCAAiC,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAEpF,wDAAwD;IACxD,OAAO,CAAC,IAAU,EAAE,GAAY,EAAE,EAAE;QAClC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAE,GAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,MAAM,YAAY,GAAG,IAAA,sBAAc,EAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAsB,CAAC,CAAC,CAAC,SAAS,CAAC;QACjF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,4BAAe,CAAC,CAAC;QAEnD,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,oBAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAExE,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,CAAC,sCAAyB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC;QACxE,CAAC;aAAM,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;YACvC,IAAI,CAAC,YAAY,CAAC,4CAA+B,EAAE,IAAA,yBAAiB,EAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5F,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,IAAY,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;QAE1E,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,CAAC;IACb,CAAC,CAAC;AACJ,CAAC,CAAC;AAEK,MAAM,iBAAiB,GAAG,CAC/B,MAAwC,EACxC,IAAgB,EAChB,MAAc,EACd,IAAa,EACb,EAAE;IACF,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACxD,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE9D,OAAO,CAAC,IAAsB,EAAoB,EAAE,CAClD,KAAK,EAAC,GAAG,EAAC,EAAE;QACV,8GAA8G;QAC9G,qHAAqH;QACrH,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;YACtC,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,MAAM,mBAAmB,GAAG,IAAA,wCAAsB,EAChD,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAC1C,CAAC,GAAY,EAAE,EAAE;YACf,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;YAClD,CAAC;QACH,CAAC,EACD,IAAI,CACL,CAAC;QAEF,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,IAAI,GAAG,GAAG,aAAO,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAE5B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,GAAG,GAAG,iBAAW,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,iBAAW,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC;YACH,OAAO,MAAM,aAAO,CAAC,IAAI,CAAC,WAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE;gBAC7D,IAAI,GAAG,aAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAE/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;gBAE5B,kBAAkB,CAAC,IAAY,EAAE,GAAG,CAAC,CAAC;gBAEtC,OAAO,GAAG,CAAC;YACb,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gBAAgB,CAAC,IAAY,EAAE,GAAG,CAAC,CAAC;YAEpC,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACN,CAAC,CAAC;AAzDW,QAAA,iBAAiB,qBAyD5B","sourcesContent":["import {\n ATTR_RPC_CONNECT_RPC_ERROR_CODE,\n ATTR_RPC_GRPC_STATUS_CODE,\n ATTR_RPC_METHOD,\n ATTR_RPC_SERVICE,\n ATTR_RPC_SYSTEM,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT\n} from '@opentelemetry/semantic-conventions/incubating';\nimport { ConnectError, StreamRequest, StreamResponse, UnaryRequest, UnaryResponse } from '@connectrpc/connect';\nimport { ConnectNodeInstrumentationConfig } from './types';\nimport { DiagLogger, SpanStatusCode, Tracer, context, propagation, trace } from '@opentelemetry/api';\nimport { InterceptorAnyFn, RpcKind, RpcPhase } from './internal-types';\nimport { Span } from '@opentelemetry/sdk-trace-base';\nimport { errorCodeToString, isConnectError, resolveRpcSystem, rpcKindToSpanKind } from './utils';\nimport { memoize } from 'lodash';\nimport { safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';\n\nconst createMetadataAttributesExtractor = (\n config: ConnectNodeInstrumentationConfig,\n kind: RpcKind,\n phase: RpcPhase\n) => {\n const metadataToSpanAttributes = config.metadataToSpanAttributes?.[kind]?.[phase] ?? [];\n const mappings = new Map(\n metadataToSpanAttributes.map(value => [value.toLowerCase(), value.toLowerCase().replace(/-/g, '_')])\n );\n\n if (mappings.size === 0) {\n return () => ({});\n }\n\n // See: https://opentelemetry.io/docs/specs/semconv/rpc/\n return (span: Span, metadata?: Headers) => {\n const rpcSystem = span.attributes[ATTR_RPC_SYSTEM];\n const attributes: Record<string, string> = {};\n\n if (rpcSystem && metadata) {\n for (const [key, mappedKey] of mappings) {\n const value = metadata.get(key);\n\n if (value != null) {\n attributes[`grpc.${rpcSystem}.${phase}.metadata.${mappedKey}`] = value;\n }\n }\n }\n\n return attributes;\n };\n};\n\nconst createStartSpan = (config: ConnectNodeInstrumentationConfig, tracer: Tracer, kind: RpcKind) => {\n const extractMetadata = createMetadataAttributesExtractor(config, kind, 'request');\n const parseUrl = memoize((url: string) => new URL(url));\n\n // See: https://opentelemetry.io/docs/specs/semconv/rpc/\n return (req: UnaryRequest | StreamRequest) => {\n const fullName = `${req.service.typeName}/${req.method.name}`;\n const url = parseUrl(req.url);\n const rpcSystem = resolveRpcSystem(req.header);\n\n const span = tracer.startSpan(fullName, {\n attributes: {\n [ATTR_RPC_METHOD]: req.method.name,\n [ATTR_RPC_SERVICE]: req.service.typeName,\n [ATTR_RPC_SYSTEM]: rpcSystem,\n [ATTR_SERVER_ADDRESS]: url.hostname,\n [ATTR_SERVER_PORT]: url.port || undefined\n },\n kind: rpcKindToSpanKind(kind)\n });\n\n span.setAttributes(extractMetadata(span as Span, req.header));\n\n return span;\n };\n};\n\nconst createEndSpanWithSuccess = (config: ConnectNodeInstrumentationConfig, kind: RpcKind) => {\n const extractMetadata = createMetadataAttributesExtractor(config, kind, 'response');\n\n // See: https://opentelemetry.io/docs/specs/semconv/rpc/\n return (span: Span, res: UnaryResponse | StreamResponse) => {\n if (span.ended) {\n return;\n }\n\n const rpcSystem = span.attributes[ATTR_RPC_SYSTEM];\n\n span.setStatus({ code: SpanStatusCode.OK });\n\n if (rpcSystem === 'grpc') {\n span.setAttribute(ATTR_RPC_GRPC_STATUS_CODE, 0);\n }\n\n span.setAttributes(extractMetadata(span as Span, res.header));\n span.end();\n };\n};\n\nconst createEndSpanWithError = (config: ConnectNodeInstrumentationConfig, kind: RpcKind) => {\n const extractMetadata = createMetadataAttributesExtractor(config, kind, 'response');\n\n // See: https://opentelemetry.io/docs/specs/semconv/rpc/\n return (span: Span, err: unknown) => {\n if (span.ended) {\n return;\n }\n\n const error = err instanceof Error ? (err as Error) : undefined;\n const connectError = isConnectError(error) ? (error as ConnectError) : undefined;\n const rpcSystem = span.attributes[ATTR_RPC_SYSTEM];\n\n span.setStatus({ code: SpanStatusCode.ERROR, message: error?.message });\n\n if (rpcSystem === 'grpc') {\n span.setAttribute(ATTR_RPC_GRPC_STATUS_CODE, connectError?.code ?? 2);\n } else if (rpcSystem === 'connect_rpc') {\n span.setAttribute(ATTR_RPC_CONNECT_RPC_ERROR_CODE, errorCodeToString(connectError?.code));\n }\n\n span.setAttributes(extractMetadata(span as Span, connectError?.metadata));\n\n if (error) {\n span.recordException(error);\n }\n\n span.end();\n };\n};\n\nexport const createInterceptor = (\n config: ConnectNodeInstrumentationConfig,\n diag: DiagLogger,\n tracer: Tracer,\n kind: RpcKind\n) => {\n const startSpan = createStartSpan(config, tracer, kind);\n const endSpanWithSuccess = createEndSpanWithSuccess(config, kind);\n const endSpanWithError = createEndSpanWithError(config, kind);\n\n return (next: InterceptorAnyFn): InterceptorAnyFn =>\n async req => {\n // Only unary requests are supported due to a bug in Node.js async context propagation on generator functions.\n // See https://github.com/open-telemetry/opentelemetry-js/issues/2951 and https://github.com/nodejs/node/issues/42237\n if (req.method.methodKind !== 'unary') {\n return await next(req);\n }\n\n const shouldIgnoreRequest = safeExecuteInTheMiddle(\n () => config.ignoreRequest?.(req) === true,\n (err: unknown) => {\n if (err != null) {\n diag.error('caught ignoreRequest error: ', err);\n }\n },\n true\n );\n\n if (shouldIgnoreRequest) {\n return await next(req);\n }\n\n let ctx = context.active();\n const span = startSpan(req);\n\n if (kind === 'server') {\n ctx = propagation.extract(ctx, req.header);\n } else {\n propagation.inject(ctx, req.header);\n }\n\n try {\n return await context.with(trace.setSpan(ctx, span), async () => {\n next = context.bind(ctx, next);\n\n const res = await next(req);\n\n endSpanWithSuccess(span as Span, res);\n\n return res;\n });\n } catch (err) {\n endSpanWithError(span as Span, err);\n\n throw err;\n }\n };\n};\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StreamRequest, StreamResponse, UnaryRequest, UnaryResponse } from '@connectrpc/connect';
|
|
2
|
+
export type InterceptorAnyFn = (req: UnaryRequest | StreamRequest) => Promise<UnaryResponse | StreamResponse>;
|
|
3
|
+
export type RpcSystem = 'connect_rpc' | 'grpc' | undefined;
|
|
4
|
+
export type RpcKind = 'server' | 'client';
|
|
5
|
+
export type RpcPhase = 'request' | 'response';
|
|
6
|
+
//# sourceMappingURL=internal-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-types.d.ts","sourceRoot":"","sources":["../src/internal-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtG,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,aAAa,KAAK,OAAO,CAAC,aAAa,GAAG,cAAc,CAAC,CAAC;AAE9G,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3D,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-types.js","sourceRoot":"","sources":["../src/internal-types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StreamRequest, StreamResponse, UnaryRequest, UnaryResponse } from '@connectrpc/connect';\n\nexport type InterceptorAnyFn = (req: UnaryRequest | StreamRequest) => Promise<UnaryResponse | StreamResponse>;\n\nexport type RpcSystem = 'connect_rpc' | 'grpc' | undefined;\n\nexport type RpcKind = 'server' | 'client';\n\nexport type RpcPhase = 'request' | 'response';\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { InstrumentationConfig } from '@opentelemetry/instrumentation';
|
|
2
|
+
import { StreamRequest, UnaryRequest } from '@connectrpc/connect';
|
|
3
|
+
export type IgnoreRequestMatcher = (req: UnaryRequest | StreamRequest) => boolean;
|
|
4
|
+
export type MetadataToSpanAttributes = {
|
|
5
|
+
client?: {
|
|
6
|
+
response?: string[];
|
|
7
|
+
request?: string[];
|
|
8
|
+
};
|
|
9
|
+
server?: {
|
|
10
|
+
response?: string[];
|
|
11
|
+
request?: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export interface ConnectNodeInstrumentationConfig extends InstrumentationConfig {
|
|
15
|
+
ignoreRequest?: IgnoreRequestMatcher;
|
|
16
|
+
metadataToSpanAttributes?: MetadataToSpanAttributes;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,aAAa,KAAK,OAAO,CAAC;AAElF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,gCAAiC,SAAQ,qBAAqB;IAE7E,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAErC,wBAAwB,CAAC,EAAE,wBAAwB,CAAC;CACrD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport { StreamRequest, UnaryRequest } from '@connectrpc/connect';\n\nexport type IgnoreRequestMatcher = (req: UnaryRequest | StreamRequest) => boolean;\n\nexport type MetadataToSpanAttributes = {\n client?: {\n response?: string[];\n request?: string[];\n };\n server?: {\n response?: string[];\n request?: string[];\n };\n};\n\nexport interface ConnectNodeInstrumentationConfig extends InstrumentationConfig {\n // Omits tracing on any requests that match the given predicate.\n ignoreRequest?: IgnoreRequestMatcher;\n // Map the following metadata to span attributes.\n metadataToSpanAttributes?: MetadataToSpanAttributes;\n}\n"]}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ConnectError } from '@connectrpc/connect';
|
|
2
|
+
import { RpcKind, RpcSystem } from './internal-types';
|
|
3
|
+
import { SpanKind } from '@opentelemetry/api';
|
|
4
|
+
export declare const isConnectError: (err: unknown) => err is ConnectError;
|
|
5
|
+
export declare const resolveRpcSystem: (header: Headers) => RpcSystem;
|
|
6
|
+
export declare const errorCodeToString: (code?: number) => "internal" | "unknown" | "canceled" | "ok" | "aborted" | "unavailable" | "already_exists" | "data_loss" | "deadline_exceeded" | "failed_precondition" | "invalid_argument" | "not_found" | "out_of_range" | "permission_denied" | "resource_exhausted" | "unauthenticated" | "unimplemented";
|
|
7
|
+
export declare const rpcKindToSpanKind: (kind: RpcKind) => SpanKind.INTERNAL | SpanKind.SERVER | SpanKind.CLIENT;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,YAUpD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,OAAO,KAAG,SAUlD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,iSAuC9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,OAAO,0DAS9C,CAAC"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rpcKindToSpanKind = exports.errorCodeToString = exports.resolveRpcSystem = exports.isConnectError = void 0;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
const isConnectError = (err) => {
|
|
6
|
+
const connectErr = err;
|
|
7
|
+
return (connectErr != null &&
|
|
8
|
+
typeof connectErr.message === 'string' &&
|
|
9
|
+
typeof connectErr.rawMessage === 'string' &&
|
|
10
|
+
Number.isInteger(connectErr.code) &&
|
|
11
|
+
connectErr.metadata instanceof Headers);
|
|
12
|
+
};
|
|
13
|
+
exports.isConnectError = isConnectError;
|
|
14
|
+
const resolveRpcSystem = (header) => {
|
|
15
|
+
if (header.get('Content-Type')?.startsWith('application/grpc')) {
|
|
16
|
+
return 'grpc';
|
|
17
|
+
}
|
|
18
|
+
if (header.has('Connect-Protocol-Version')) {
|
|
19
|
+
return 'connect_rpc';
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
};
|
|
23
|
+
exports.resolveRpcSystem = resolveRpcSystem;
|
|
24
|
+
const errorCodeToString = (code) => {
|
|
25
|
+
switch (code) {
|
|
26
|
+
case 0:
|
|
27
|
+
return 'ok';
|
|
28
|
+
case 1:
|
|
29
|
+
return 'canceled';
|
|
30
|
+
case 2:
|
|
31
|
+
return 'unknown';
|
|
32
|
+
case 3:
|
|
33
|
+
return 'invalid_argument';
|
|
34
|
+
case 4:
|
|
35
|
+
return 'deadline_exceeded';
|
|
36
|
+
case 5:
|
|
37
|
+
return 'not_found';
|
|
38
|
+
case 6:
|
|
39
|
+
return 'already_exists';
|
|
40
|
+
case 7:
|
|
41
|
+
return 'permission_denied';
|
|
42
|
+
case 8:
|
|
43
|
+
return 'resource_exhausted';
|
|
44
|
+
case 9:
|
|
45
|
+
return 'failed_precondition';
|
|
46
|
+
case 10:
|
|
47
|
+
return 'aborted';
|
|
48
|
+
case 11:
|
|
49
|
+
return 'out_of_range';
|
|
50
|
+
case 12:
|
|
51
|
+
return 'unimplemented';
|
|
52
|
+
case 13:
|
|
53
|
+
return 'internal';
|
|
54
|
+
case 14:
|
|
55
|
+
return 'unavailable';
|
|
56
|
+
case 15:
|
|
57
|
+
return 'data_loss';
|
|
58
|
+
case 16:
|
|
59
|
+
return 'unauthenticated';
|
|
60
|
+
default:
|
|
61
|
+
return 'unknown';
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
exports.errorCodeToString = errorCodeToString;
|
|
65
|
+
const rpcKindToSpanKind = (kind) => {
|
|
66
|
+
switch (kind) {
|
|
67
|
+
case 'client':
|
|
68
|
+
return api_1.SpanKind.CLIENT;
|
|
69
|
+
case 'server':
|
|
70
|
+
return api_1.SpanKind.SERVER;
|
|
71
|
+
default:
|
|
72
|
+
return api_1.SpanKind.INTERNAL;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
exports.rpcKindToSpanKind = rpcKindToSpanKind;
|
|
76
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAEA,4CAA8C;AAEvC,MAAM,cAAc,GAAG,CAAC,GAAY,EAAuB,EAAE;IAClE,MAAM,UAAU,GAAG,GAAmB,CAAC;IAEvC,OAAO,CACL,UAAU,IAAI,IAAI;QAClB,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ;QACtC,OAAO,UAAU,CAAC,UAAU,KAAK,QAAQ;QACzC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC;QACjC,UAAU,CAAC,QAAQ,YAAY,OAAO,CACvC,CAAC;AACJ,CAAC,CAAC;AAVW,QAAA,cAAc,kBAUzB;AAEK,MAAM,gBAAgB,GAAG,CAAC,MAAe,EAAa,EAAE;IAC7D,IAAI,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAC3C,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAVW,QAAA,gBAAgB,oBAU3B;AAEK,MAAM,iBAAiB,GAAG,CAAC,IAAa,EAAE,EAAE;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,CAAC;YACJ,OAAO,IAAI,CAAC;QACd,KAAK,CAAC;YACJ,OAAO,UAAU,CAAC;QACpB,KAAK,CAAC;YACJ,OAAO,SAAS,CAAC;QACnB,KAAK,CAAC;YACJ,OAAO,kBAAkB,CAAC;QAC5B,KAAK,CAAC;YACJ,OAAO,mBAAmB,CAAC;QAC7B,KAAK,CAAC;YACJ,OAAO,WAAW,CAAC;QACrB,KAAK,CAAC;YACJ,OAAO,gBAAgB,CAAC;QAC1B,KAAK,CAAC;YACJ,OAAO,mBAAmB,CAAC;QAC7B,KAAK,CAAC;YACJ,OAAO,oBAAoB,CAAC;QAC9B,KAAK,CAAC;YACJ,OAAO,qBAAqB,CAAC;QAC/B,KAAK,EAAE;YACL,OAAO,SAAS,CAAC;QACnB,KAAK,EAAE;YACL,OAAO,cAAc,CAAC;QACxB,KAAK,EAAE;YACL,OAAO,eAAe,CAAC;QACzB,KAAK,EAAE;YACL,OAAO,UAAU,CAAC;QACpB,KAAK,EAAE;YACL,OAAO,aAAa,CAAC;QACvB,KAAK,EAAE;YACL,OAAO,WAAW,CAAC;QACrB,KAAK,EAAE;YACL,OAAO,iBAAiB,CAAC;QAC3B;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC,CAAC;AAvCW,QAAA,iBAAiB,qBAuC5B;AAEK,MAAM,iBAAiB,GAAG,CAAC,IAAa,EAAE,EAAE;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,cAAQ,CAAC,MAAM,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,cAAQ,CAAC,MAAM,CAAC;QACzB;YACE,OAAO,cAAQ,CAAC,QAAQ,CAAC;IAC7B,CAAC;AACH,CAAC,CAAC;AATW,QAAA,iBAAiB,qBAS5B","sourcesContent":["import type { ConnectError } from '@connectrpc/connect';\nimport { RpcKind, RpcSystem } from './internal-types';\nimport { SpanKind } from '@opentelemetry/api';\n\nexport const isConnectError = (err: unknown): err is ConnectError => {\n const connectErr = err as ConnectError;\n\n return (\n connectErr != null &&\n typeof connectErr.message === 'string' &&\n typeof connectErr.rawMessage === 'string' &&\n Number.isInteger(connectErr.code) &&\n connectErr.metadata instanceof Headers\n );\n};\n\nexport const resolveRpcSystem = (header: Headers): RpcSystem => {\n if (header.get('Content-Type')?.startsWith('application/grpc')) {\n return 'grpc';\n }\n\n if (header.has('Connect-Protocol-Version')) {\n return 'connect_rpc';\n }\n\n return undefined;\n};\n\nexport const errorCodeToString = (code?: number) => {\n switch (code) {\n case 0:\n return 'ok';\n case 1:\n return 'canceled';\n case 2:\n return 'unknown';\n case 3:\n return 'invalid_argument';\n case 4:\n return 'deadline_exceeded';\n case 5:\n return 'not_found';\n case 6:\n return 'already_exists';\n case 7:\n return 'permission_denied';\n case 8:\n return 'resource_exhausted';\n case 9:\n return 'failed_precondition';\n case 10:\n return 'aborted';\n case 11:\n return 'out_of_range';\n case 12:\n return 'unimplemented';\n case 13:\n return 'internal';\n case 14:\n return 'unavailable';\n case 15:\n return 'data_loss';\n case 16:\n return 'unauthenticated';\n default:\n return 'unknown';\n }\n};\n\nexport const rpcKindToSpanKind = (kind: RpcKind) => {\n switch (kind) {\n case 'client':\n return SpanKind.CLIENT;\n case 'server':\n return SpanKind.SERVER;\n default:\n return SpanKind.INTERNAL;\n }\n};\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uphold/opentelemetry-instrumentation-connect-node",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenTelemetry instrumentation for `@connectrpc/connect-node` RPC client and server",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"author": "Uphold",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/uphold/opentelemetry-js-contrib.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"opentelemetry",
|
|
17
|
+
"instrumentation",
|
|
18
|
+
"nodejs",
|
|
19
|
+
"tracing",
|
|
20
|
+
"connectrpc",
|
|
21
|
+
"connect-es",
|
|
22
|
+
"grpc",
|
|
23
|
+
"rpc"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"prebuild": "rm -rf dist",
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"lint": "eslint",
|
|
35
|
+
"postlint": "tsc --noEmit",
|
|
36
|
+
"release": "release-it --config ../../.release-it.js",
|
|
37
|
+
"test": "vitest"
|
|
38
|
+
},
|
|
39
|
+
"lint-staged": {
|
|
40
|
+
"*.{ts,js}": [
|
|
41
|
+
"eslint"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@opentelemetry/instrumentation": "^0.200.0",
|
|
46
|
+
"@opentelemetry/semantic-conventions": "~1.32.0",
|
|
47
|
+
"lodash": "^4.17.21"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@opentelemetry/api": ">=1 <2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@connectrpc/connect": "^2.0.2",
|
|
54
|
+
"@connectrpc/connect-node": "^2.0.2",
|
|
55
|
+
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
56
|
+
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
57
|
+
"@types/lodash": "^4.17.16"
|
|
58
|
+
}
|
|
59
|
+
}
|