@tramvai/module-opentelemetry 4.41.99

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.
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var semanticConventions = require('@opentelemetry/semantic-conventions');
6
+ var api = require('@opentelemetry/api');
7
+ var pathToRegexp = require('path-to-regexp');
8
+ var flatten = require('@tinkoff/utils/array/flatten');
9
+ var errors = require('@tinkoff/errors');
10
+ var core = require('@tramvai/core');
11
+ var tokensServer = require('@tramvai/tokens-server');
12
+ var tokensServerPrivate = require('@tramvai/tokens-server-private');
13
+ var tokensCommon = require('@tramvai/tokens-common');
14
+ var tokens = require('../tokens.js');
15
+
16
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
17
+
18
+ var pathToRegexp__default = /*#__PURE__*/_interopDefaultLegacy(pathToRegexp);
19
+ var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
20
+
21
+ const REQUEST_SPAN = Symbol('opentelemetry.tramvai.server.request.span');
22
+ const providers = [
23
+ core.provide({
24
+ provide: tokensServerPrivate.WEB_FASTIFY_APP_INIT_TOKEN,
25
+ useFactory: ({ app, tracer, tracesExcludePaths, envManager }) => {
26
+ return () => {
27
+ // todo copypaste from @tinkoff/measure-fastify-requests
28
+ const excludePatterns = flatten__default["default"](tracesExcludePaths).map((p) => pathToRegexp__default["default"](p));
29
+ app.addHook('onRequest', (req, reply, done) => {
30
+ var _a;
31
+ // skip traces for healthchecks
32
+ if (excludePatterns.some((p) => p.test(req.url))) {
33
+ done();
34
+ return;
35
+ }
36
+ // propagate context from incoming request
37
+ // https://opentelemetry.io/docs/languages/js/propagation/#manual-context-propagation
38
+ const activeContext = api.propagation.extract(api.ROOT_CONTEXT, req.headers);
39
+ const httpMethod = req.method;
40
+ // todo useful because always get `*`, rewrite with tramvai router route?
41
+ const httpRoute = ((_a = req.routeOptions) === null || _a === void 0 ? void 0 : _a.url)
42
+ ? req.routeOptions.url // since fastify@4.10.0
43
+ : req.routerPath;
44
+ const parsedUrl = new URL(`http://localhost${req.url}`);
45
+ // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#name
46
+ tracer.startActiveSpan(`${httpMethod} ${httpRoute === '*' ? 'APP' : httpRoute}`,
47
+ // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#http-server-semantic-conventions
48
+ { kind: api.SpanKind.SERVER }, activeContext, (span) => {
49
+ req[REQUEST_SPAN] = span;
50
+ // todo: move custom tramvai attrs to constants
51
+ /**
52
+ * let's add some conventions for tramvai attributes:
53
+ * - `tramvai` prefix for all specific attributes in tramvai instrumentation
54
+ * - `tramvai.scope` second prefix to define module, e.g. `tramvai.scope: server`
55
+ * - `tramvai.*` second prefix for specific modules, e.g. `tramvai.server`
56
+ * - `tramvai.server.handler` - `app` value for pages handler, another possible values - `papi`, `request-limiter`
57
+ * - `tramvai.server.framework` - reserved for future, if we will add support for other server frameworks
58
+ */
59
+ span.setAttribute('tramvai.scope', 'server');
60
+ span.setAttribute('tramvai.server.handler', 'app');
61
+ span.setAttribute('tramvai.server.framework', 'fastify');
62
+ // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/attributes-registry/http.md
63
+ span.setAttribute(semanticConventions.ATTR_HTTP_REQUEST_METHOD, httpMethod);
64
+ span.setAttribute(semanticConventions.ATTR_SERVER_ADDRESS, req.headers['x-original-host'] || req.headers.host || envManager.get('PORT'));
65
+ span.setAttribute(semanticConventions.ATTR_SERVER_PORT, envManager.get('PORT'));
66
+ // route should have low-cardinality - https://github.com/open-telemetry/semantic-conventions/blob/main/docs/attributes-registry/http.md
67
+ span.setAttribute(semanticConventions.ATTR_HTTP_ROUTE, httpRoute);
68
+ span.setAttribute(semanticConventions.ATTR_URL_PATH, parsedUrl.pathname);
69
+ span.setAttribute(semanticConventions.ATTR_URL_QUERY, parsedUrl.search.replace('?', ''));
70
+ span.setAttribute(semanticConventions.ATTR_URL_SCHEME, parsedUrl.protocol.replace(':', ''));
71
+ span.setAttribute(semanticConventions.ATTR_URL_FULL, parsedUrl.href);
72
+ done();
73
+ });
74
+ });
75
+ app.addHook('onResponse', (req, reply) => {
76
+ if (req[REQUEST_SPAN]) {
77
+ const span = req[REQUEST_SPAN];
78
+ if (reply.statusCode >= 400) ;
79
+ else {
80
+ span.setAttribute(semanticConventions.ATTR_HTTP_RESPONSE_STATUS_CODE, reply.statusCode);
81
+ // todo req/res headers?
82
+ span.end();
83
+ }
84
+ }
85
+ });
86
+ };
87
+ },
88
+ deps: {
89
+ app: tokensServerPrivate.WEB_FASTIFY_APP_TOKEN,
90
+ tracer: tokens.OPENTELEMETRY_TRACER_TOKEN,
91
+ tracesExcludePaths: tokensServer.UTILITY_SERVER_PATHS,
92
+ envManager: tokensCommon.ENV_MANAGER_TOKEN,
93
+ },
94
+ }),
95
+ core.provide({
96
+ provide: tokensServerPrivate.WEB_FASTIFY_APP_AFTER_ERROR_TOKEN,
97
+ useFactory: (deps) => {
98
+ return (error, req, reply) => {
99
+ var _a;
100
+ if (req[REQUEST_SPAN]) {
101
+ const span = req[REQUEST_SPAN];
102
+ let httpStatus;
103
+ // todo duplicated logic from packages/modules/server/src/server/error/prepareLogsForError.ts
104
+ if (errors.isNotFoundError(error)) {
105
+ httpStatus = error.httpStatus || 404;
106
+ }
107
+ else if (errors.isHttpError(error)) {
108
+ httpStatus = error.httpStatus || 500;
109
+ }
110
+ else {
111
+ httpStatus = error.statusCode || 500;
112
+ }
113
+ span.setAttribute(semanticConventions.ATTR_HTTP_RESPONSE_STATUS_CODE, httpStatus);
114
+ // todo req/res headers?
115
+ // todo "error.type" attribute?
116
+ // do not set error status for incoming requests with 4xx status
117
+ // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
118
+ if (httpStatus >= 500) {
119
+ span.recordException(error);
120
+ span.setStatus({
121
+ code: api.SpanStatusCode.ERROR,
122
+ message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : 'Unknown error',
123
+ });
124
+ }
125
+ span.end();
126
+ // todo RootErrorBoundary is out of scope, because it is rendered after `WEB_FASTIFY_APP_AFTER_ERROR_TOKEN` hooks
127
+ }
128
+ };
129
+ },
130
+ deps: {},
131
+ }),
132
+ ];
133
+
134
+ exports.REQUEST_SPAN = REQUEST_SPAN;
135
+ exports.providers = providers;
@@ -0,0 +1,4 @@
1
+ export * from './tokens';
2
+ export declare class OpenTelemetryModule {
3
+ }
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,127 @@
1
+ import { __decorate } from 'tslib';
2
+ import { Module, provide, commandLineListTokens, optional, APP_INFO_TOKEN } from '@tramvai/core';
3
+ import { NodeTracerProvider, SimpleSpanProcessor, ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';
4
+ import { Resource } from '@opentelemetry/resources';
5
+ import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
6
+ import { LOGGER_TOKEN, ENV_MANAGER_TOKEN } from '@tramvai/tokens-common';
7
+ import { OPENTELEMETRY_PROVIDER_TOKEN, OPENTELEMETRY_PROVIDER_CONFIG_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN, OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN, OPENTELEMETRY_TRACER_TOKEN } from './tokens.es.js';
8
+ export { OPENTELEMETRY_PROVIDER_CONFIG_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN, OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN, OPENTELEMETRY_PROVIDER_TOKEN, OPENTELEMETRY_TRACER_TOKEN } from './tokens.es.js';
9
+ import { TramvaiTracerImpl } from './tracer/tracer.es.js';
10
+ import { providers } from './instrumentation/server.es.js';
11
+ import { providers as providers$1 } from './instrumentation/httpClient.es.js';
12
+ import { providers as providers$2 } from './instrumentation/logs.es.js';
13
+
14
+ let OpenTelemetryModule = class OpenTelemetryModule {
15
+ };
16
+ OpenTelemetryModule = __decorate([
17
+ Module({
18
+ imports: [],
19
+ providers: [
20
+ ...providers,
21
+ ...providers$1,
22
+ ...providers$2,
23
+ provide({
24
+ provide: commandLineListTokens.init,
25
+ useFactory: ({ provider }) => {
26
+ return function initializeOpenTelemetryProvider() {
27
+ provider.register();
28
+ };
29
+ },
30
+ deps: {
31
+ provider: OPENTELEMETRY_PROVIDER_TOKEN,
32
+ },
33
+ }),
34
+ provide({
35
+ provide: commandLineListTokens.close,
36
+ useFactory: ({ provider, logger }) => {
37
+ return function shutdownOpenTelemetryProvider() {
38
+ const log = logger('opentelemetry');
39
+ provider.shutdown().catch((error) => {
40
+ log.error({
41
+ event: 'provider-shutdown-error',
42
+ error,
43
+ });
44
+ });
45
+ };
46
+ },
47
+ deps: {
48
+ provider: OPENTELEMETRY_PROVIDER_TOKEN,
49
+ logger: LOGGER_TOKEN,
50
+ },
51
+ }),
52
+ provide({
53
+ provide: OPENTELEMETRY_PROVIDER_TOKEN,
54
+ useFactory: ({ config }) => {
55
+ return new NodeTracerProvider(config);
56
+ },
57
+ deps: {
58
+ config: OPENTELEMETRY_PROVIDER_CONFIG_TOKEN,
59
+ },
60
+ }),
61
+ // todo maybe not needed?
62
+ provide({
63
+ provide: OPENTELEMETRY_PROVIDER_CONFIG_TOKEN,
64
+ useFactory: ({ resource, spanProcessors }) => {
65
+ return { resource, spanProcessors: spanProcessors !== null && spanProcessors !== void 0 ? spanProcessors : [] };
66
+ },
67
+ deps: {
68
+ resource: OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN,
69
+ spanProcessors: optional(OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN),
70
+ },
71
+ }),
72
+ provide({
73
+ provide: OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN,
74
+ useFactory: ({ attributesList }) => {
75
+ const attributes = attributesList.reduce((acc, attribute) => {
76
+ return {
77
+ ...acc,
78
+ ...attribute,
79
+ };
80
+ }, {});
81
+ // todo async attributes
82
+ return new Resource(attributes);
83
+ },
84
+ deps: {
85
+ attributesList: OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN,
86
+ },
87
+ }),
88
+ provide({
89
+ provide: OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN,
90
+ useFactory: ({ appInfo, envManager }) => {
91
+ return {
92
+ [ATTR_SERVICE_NAME]: appInfo.appName,
93
+ [ATTR_SERVICE_VERSION]: envManager.get('APP_VERSION'),
94
+ };
95
+ },
96
+ deps: {
97
+ appInfo: APP_INFO_TOKEN,
98
+ envManager: ENV_MANAGER_TOKEN,
99
+ },
100
+ }),
101
+ provide({
102
+ provide: OPENTELEMETRY_TRACER_TOKEN,
103
+ useFactory: ({ provider }) => {
104
+ const tracer = provider.getTracer('tramvai', '1.0.0');
105
+ return new TramvaiTracerImpl({ tracer });
106
+ },
107
+ deps: {
108
+ provider: OPENTELEMETRY_PROVIDER_TOKEN,
109
+ },
110
+ }),
111
+ // todo open telemetry debug flag or wrap ConsoleSpanExporter in logger
112
+ ...(process.env.NODE_ENV === 'development'
113
+ ? [
114
+ provide({
115
+ provide: OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN,
116
+ useFactory: () => {
117
+ return new SimpleSpanProcessor(new ConsoleSpanExporter());
118
+ },
119
+ }),
120
+ ]
121
+ : []),
122
+ ],
123
+ })
124
+ ], OpenTelemetryModule);
125
+ // todo declareModule!
126
+
127
+ export { OpenTelemetryModule };
package/lib/server.js ADDED
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var core = require('@tramvai/core');
7
+ var sdkTraceNode = require('@opentelemetry/sdk-trace-node');
8
+ var resources = require('@opentelemetry/resources');
9
+ var semanticConventions = require('@opentelemetry/semantic-conventions');
10
+ var tokensCommon = require('@tramvai/tokens-common');
11
+ var tokens = require('./tokens.js');
12
+ var tracer = require('./tracer/tracer.js');
13
+ var server = require('./instrumentation/server.js');
14
+ var httpClient = require('./instrumentation/httpClient.js');
15
+ var logs = require('./instrumentation/logs.js');
16
+
17
+ exports.OpenTelemetryModule = class OpenTelemetryModule {
18
+ };
19
+ exports.OpenTelemetryModule = tslib.__decorate([
20
+ core.Module({
21
+ imports: [],
22
+ providers: [
23
+ ...server.providers,
24
+ ...httpClient.providers,
25
+ ...logs.providers,
26
+ core.provide({
27
+ provide: core.commandLineListTokens.init,
28
+ useFactory: ({ provider }) => {
29
+ return function initializeOpenTelemetryProvider() {
30
+ provider.register();
31
+ };
32
+ },
33
+ deps: {
34
+ provider: tokens.OPENTELEMETRY_PROVIDER_TOKEN,
35
+ },
36
+ }),
37
+ core.provide({
38
+ provide: core.commandLineListTokens.close,
39
+ useFactory: ({ provider, logger }) => {
40
+ return function shutdownOpenTelemetryProvider() {
41
+ const log = logger('opentelemetry');
42
+ provider.shutdown().catch((error) => {
43
+ log.error({
44
+ event: 'provider-shutdown-error',
45
+ error,
46
+ });
47
+ });
48
+ };
49
+ },
50
+ deps: {
51
+ provider: tokens.OPENTELEMETRY_PROVIDER_TOKEN,
52
+ logger: tokensCommon.LOGGER_TOKEN,
53
+ },
54
+ }),
55
+ core.provide({
56
+ provide: tokens.OPENTELEMETRY_PROVIDER_TOKEN,
57
+ useFactory: ({ config }) => {
58
+ return new sdkTraceNode.NodeTracerProvider(config);
59
+ },
60
+ deps: {
61
+ config: tokens.OPENTELEMETRY_PROVIDER_CONFIG_TOKEN,
62
+ },
63
+ }),
64
+ // todo maybe not needed?
65
+ core.provide({
66
+ provide: tokens.OPENTELEMETRY_PROVIDER_CONFIG_TOKEN,
67
+ useFactory: ({ resource, spanProcessors }) => {
68
+ return { resource, spanProcessors: spanProcessors !== null && spanProcessors !== void 0 ? spanProcessors : [] };
69
+ },
70
+ deps: {
71
+ resource: tokens.OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN,
72
+ spanProcessors: core.optional(tokens.OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN),
73
+ },
74
+ }),
75
+ core.provide({
76
+ provide: tokens.OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN,
77
+ useFactory: ({ attributesList }) => {
78
+ const attributes = attributesList.reduce((acc, attribute) => {
79
+ return {
80
+ ...acc,
81
+ ...attribute,
82
+ };
83
+ }, {});
84
+ // todo async attributes
85
+ return new resources.Resource(attributes);
86
+ },
87
+ deps: {
88
+ attributesList: tokens.OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN,
89
+ },
90
+ }),
91
+ core.provide({
92
+ provide: tokens.OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN,
93
+ useFactory: ({ appInfo, envManager }) => {
94
+ return {
95
+ [semanticConventions.ATTR_SERVICE_NAME]: appInfo.appName,
96
+ [semanticConventions.ATTR_SERVICE_VERSION]: envManager.get('APP_VERSION'),
97
+ };
98
+ },
99
+ deps: {
100
+ appInfo: core.APP_INFO_TOKEN,
101
+ envManager: tokensCommon.ENV_MANAGER_TOKEN,
102
+ },
103
+ }),
104
+ core.provide({
105
+ provide: tokens.OPENTELEMETRY_TRACER_TOKEN,
106
+ useFactory: ({ provider }) => {
107
+ const tracer$1 = provider.getTracer('tramvai', '1.0.0');
108
+ return new tracer.TramvaiTracerImpl({ tracer: tracer$1 });
109
+ },
110
+ deps: {
111
+ provider: tokens.OPENTELEMETRY_PROVIDER_TOKEN,
112
+ },
113
+ }),
114
+ // todo open telemetry debug flag or wrap ConsoleSpanExporter in logger
115
+ ...(process.env.NODE_ENV === 'development'
116
+ ? [
117
+ core.provide({
118
+ provide: tokens.OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN,
119
+ useFactory: () => {
120
+ return new sdkTraceNode.SimpleSpanProcessor(new sdkTraceNode.ConsoleSpanExporter());
121
+ },
122
+ }),
123
+ ]
124
+ : []),
125
+ ],
126
+ })
127
+ ], exports.OpenTelemetryModule);
128
+ // todo declareModule!
129
+
130
+ exports.OPENTELEMETRY_PROVIDER_CONFIG_TOKEN = tokens.OPENTELEMETRY_PROVIDER_CONFIG_TOKEN;
131
+ exports.OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN = tokens.OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN;
132
+ exports.OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN = tokens.OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN;
133
+ exports.OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN = tokens.OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN;
134
+ exports.OPENTELEMETRY_PROVIDER_TOKEN = tokens.OPENTELEMETRY_PROVIDER_TOKEN;
135
+ exports.OPENTELEMETRY_TRACER_TOKEN = tokens.OPENTELEMETRY_TRACER_TOKEN;
@@ -0,0 +1,10 @@
1
+ import { createToken, Scope } from '@tinkoff/dippy';
2
+
3
+ const OPENTELEMETRY_PROVIDER_TOKEN = createToken('tramvai opentelemetry provider', { scope: Scope.SINGLETON });
4
+ const OPENTELEMETRY_PROVIDER_CONFIG_TOKEN = createToken('tramvai opentelemetry provider config', { scope: Scope.SINGLETON });
5
+ const OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN = createToken('tramvai opentelemetry provider span processor', { multi: true, scope: Scope.SINGLETON });
6
+ const OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN = createToken('tramvai opentelemetry provider resource', { scope: Scope.SINGLETON });
7
+ const OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN = createToken('tramvai opentelemetry provider resource attributes', { multi: true, scope: Scope.SINGLETON });
8
+ const OPENTELEMETRY_TRACER_TOKEN = createToken('tramvai opentelemetry tracer', { scope: Scope.SINGLETON });
9
+
10
+ export { OPENTELEMETRY_PROVIDER_CONFIG_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN, OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN, OPENTELEMETRY_PROVIDER_TOKEN, OPENTELEMETRY_TRACER_TOKEN };
@@ -0,0 +1,41 @@
1
+ import type { Context, Span, SpanOptions } from '@opentelemetry/api';
2
+ import type { SpanProcessor, TracerConfig, BasicTracerProvider } from '@opentelemetry/sdk-trace-node';
3
+ import type { Resource } from '@opentelemetry/resources';
4
+ export type TraceParams = {
5
+ skipError?: (error: Error) => boolean;
6
+ };
7
+ /**
8
+ * API inspired by:
9
+ * - https://github.com/DataDog/dd-trace-js/blob/59e9a2a75f4256755b4e6c9951a0bdf8d39b4015/index.d.ts#L9
10
+ * - https://github.com/vercel/next.js/blob/9a1cd356dbafbfcf23d1b9ec05f772f766d05580/packages/next/src/server/lib/trace/tracer.ts#L74
11
+ */
12
+ export interface TramvaiTracer {
13
+ startSpan(name: string, options?: SpanOptions, context?: Context): Span;
14
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, fn: F): ReturnType<F>;
15
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, options: SpanOptions, fn: F): ReturnType<F>;
16
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, options: SpanOptions, context: Context, fn: F): ReturnType<F>;
17
+ getActiveSpan(): Span | undefined;
18
+ trace<T>(name: string, fn: (span: Span) => Promise<T>, params?: TraceParams): Promise<T>;
19
+ trace<T>(name: string, fn: (span: Span) => T, params?: TraceParams): T;
20
+ trace<T>(name: string, options: SpanOptions, fn: (span: Span) => Promise<T>, params?: TraceParams): Promise<T>;
21
+ trace<T>(name: string, options: SpanOptions, fn: (span: Span) => T, params?: TraceParams): T;
22
+ }
23
+ export declare const OPENTELEMETRY_PROVIDER_TOKEN: BasicTracerProvider & {
24
+ __type?: "base token" | undefined;
25
+ };
26
+ export declare const OPENTELEMETRY_PROVIDER_CONFIG_TOKEN: TracerConfig & {
27
+ __type?: "base token" | undefined;
28
+ };
29
+ export declare const OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN: SpanProcessor & {
30
+ __type?: "multi token" | undefined;
31
+ };
32
+ export declare const OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN: Resource & {
33
+ __type?: "base token" | undefined;
34
+ };
35
+ export declare const OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN: import("@opentelemetry/api").Attributes & {
36
+ __type?: "multi token" | undefined;
37
+ };
38
+ export declare const OPENTELEMETRY_TRACER_TOKEN: TramvaiTracer & {
39
+ __type?: "base token" | undefined;
40
+ };
41
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { createToken, Scope } from '@tinkoff/dippy';
2
+
3
+ const OPENTELEMETRY_PROVIDER_TOKEN = createToken('tramvai opentelemetry provider', { scope: Scope.SINGLETON });
4
+ const OPENTELEMETRY_PROVIDER_CONFIG_TOKEN = createToken('tramvai opentelemetry provider config', { scope: Scope.SINGLETON });
5
+ const OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN = createToken('tramvai opentelemetry provider span processor', { multi: true, scope: Scope.SINGLETON });
6
+ const OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN = createToken('tramvai opentelemetry provider resource', { scope: Scope.SINGLETON });
7
+ const OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN = createToken('tramvai opentelemetry provider resource attributes', { multi: true, scope: Scope.SINGLETON });
8
+ const OPENTELEMETRY_TRACER_TOKEN = createToken('tramvai opentelemetry tracer', { scope: Scope.SINGLETON });
9
+
10
+ export { OPENTELEMETRY_PROVIDER_CONFIG_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN, OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN, OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN, OPENTELEMETRY_PROVIDER_TOKEN, OPENTELEMETRY_TRACER_TOKEN };
package/lib/tokens.js ADDED
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var dippy = require('@tinkoff/dippy');
6
+
7
+ const OPENTELEMETRY_PROVIDER_TOKEN = dippy.createToken('tramvai opentelemetry provider', { scope: dippy.Scope.SINGLETON });
8
+ const OPENTELEMETRY_PROVIDER_CONFIG_TOKEN = dippy.createToken('tramvai opentelemetry provider config', { scope: dippy.Scope.SINGLETON });
9
+ const OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN = dippy.createToken('tramvai opentelemetry provider span processor', { multi: true, scope: dippy.Scope.SINGLETON });
10
+ const OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN = dippy.createToken('tramvai opentelemetry provider resource', { scope: dippy.Scope.SINGLETON });
11
+ const OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN = dippy.createToken('tramvai opentelemetry provider resource attributes', { multi: true, scope: dippy.Scope.SINGLETON });
12
+ const OPENTELEMETRY_TRACER_TOKEN = dippy.createToken('tramvai opentelemetry tracer', { scope: dippy.Scope.SINGLETON });
13
+
14
+ exports.OPENTELEMETRY_PROVIDER_CONFIG_TOKEN = OPENTELEMETRY_PROVIDER_CONFIG_TOKEN;
15
+ exports.OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN = OPENTELEMETRY_PROVIDER_RESOURCE_ATTRIBUTES_TOKEN;
16
+ exports.OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN = OPENTELEMETRY_PROVIDER_RESOURCE_TOKEN;
17
+ exports.OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN = OPENTELEMETRY_PROVIDER_SPAN_PROCESSOR_TOKEN;
18
+ exports.OPENTELEMETRY_PROVIDER_TOKEN = OPENTELEMETRY_PROVIDER_TOKEN;
19
+ exports.OPENTELEMETRY_TRACER_TOKEN = OPENTELEMETRY_TRACER_TOKEN;
@@ -0,0 +1,18 @@
1
+ import type { Context, Span, SpanOptions, Tracer } from '@opentelemetry/api';
2
+ import type { TraceParams, TramvaiTracer } from '../tokens';
3
+ export declare class TramvaiTracerImpl implements TramvaiTracer {
4
+ private tracer;
5
+ constructor({ tracer }: {
6
+ tracer: Tracer;
7
+ });
8
+ startSpan(...args: any[]): Span;
9
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, fn: F): ReturnType<F>;
10
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, options: SpanOptions, fn: F): ReturnType<F>;
11
+ startActiveSpan<F extends (span: Span) => unknown>(name: string, options: SpanOptions, ctx: Context, fn: F): ReturnType<F>;
12
+ getActiveSpan(): Span | undefined;
13
+ trace<T>(name: string, fn: (span: Span) => Promise<T>, params?: TraceParams): Promise<T>;
14
+ trace<T>(name: string, fn: (span: Span) => T, params?: TraceParams): T;
15
+ trace<T>(name: string, options: SpanOptions, fn: (span: Span) => Promise<T>, params?: TraceParams): Promise<T>;
16
+ trace<T>(name: string, options: SpanOptions, fn: (span: Span, params?: TraceParams) => T): T;
17
+ }
18
+ //# sourceMappingURL=tracer.d.ts.map
@@ -0,0 +1,78 @@
1
+ import isPromise from '@tinkoff/utils/is/promise';
2
+ import { trace, context, ROOT_CONTEXT, SpanStatusCode } from '@opentelemetry/api';
3
+ import { isSilentError } from '@tinkoff/errors';
4
+
5
+ /* eslint-disable prefer-destructuring */
6
+ function recordAndThrowError(span, error, { skipError = () => false }) {
7
+ var _a;
8
+ span.recordException(error);
9
+ if (!(skipError(error) || isSilentError(error))) {
10
+ span.setStatus({
11
+ code: SpanStatusCode.ERROR,
12
+ message: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : 'Unknown error',
13
+ });
14
+ }
15
+ span.end();
16
+ throw error;
17
+ }
18
+ class TramvaiTracerImpl {
19
+ constructor({ tracer }) {
20
+ this.tracer = tracer;
21
+ }
22
+ startSpan(...args) {
23
+ // @ts-expect-error
24
+ return this.tracer.startSpan(...args);
25
+ }
26
+ startActiveSpan(...args) {
27
+ // @ts-expect-error
28
+ return this.tracer.startActiveSpan(...args);
29
+ }
30
+ getActiveSpan() {
31
+ return trace.getSpan(context.active());
32
+ }
33
+ trace(...args) {
34
+ var _a;
35
+ const name = args[0];
36
+ let fn;
37
+ let options;
38
+ let params;
39
+ if (args.length === 2 || (args.length === 3 && typeof args[2] === 'object')) {
40
+ fn = args[1];
41
+ options = {};
42
+ params = args[2] || {};
43
+ }
44
+ else {
45
+ fn = args[2];
46
+ options = args[1];
47
+ params = args[3] || {};
48
+ }
49
+ const activeSpan = trace.getSpan(context.active());
50
+ const spanContext = activeSpan ? trace.setSpan(context.active(), activeSpan) : undefined;
51
+ const ctx = (_a = spanContext !== null && spanContext !== void 0 ? spanContext : context.active()) !== null && _a !== void 0 ? _a : ROOT_CONTEXT;
52
+ return this.startActiveSpan(name, options, ctx, (span) => {
53
+ try {
54
+ const result = fn(span);
55
+ // wrap promise fn, end span if promise is resolved or rejected
56
+ if (isPromise(result)) {
57
+ return result
58
+ .then((res) => {
59
+ span.end();
60
+ return res;
61
+ })
62
+ .catch((error) => {
63
+ recordAndThrowError(span, error, params);
64
+ });
65
+ }
66
+ // otherwise, end span immediately
67
+ span.end();
68
+ return result;
69
+ }
70
+ catch (error) {
71
+ recordAndThrowError(span, error, params);
72
+ }
73
+ });
74
+ }
75
+ }
76
+ /* eslint-enable prefer-destructuring */
77
+
78
+ export { TramvaiTracerImpl };