@adonisjs/otel 1.0.0-next.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.md +9 -0
- package/README.md +38 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +69 -0
- package/build/index.d.ts +11 -0
- package/build/index.js +19 -0
- package/build/providers/otel_provider.d.ts +11 -0
- package/build/providers/otel_provider.js +50 -0
- package/build/src/decorators.d.ts +68 -0
- package/build/src/decorators.js +102 -0
- package/build/src/define_config.d.ts +2 -0
- package/build/src/define_config.js +3 -0
- package/build/src/helpers.d.ts +174 -0
- package/build/src/helpers.js +236 -0
- package/build/src/middleware/otel_middleware.d.ts +20 -0
- package/build/src/middleware/otel_middleware.js +64 -0
- package/build/src/otel.d.ts +65 -0
- package/build/src/otel.js +329 -0
- package/build/src/start.d.ts +18 -0
- package/build/src/start.js +37 -0
- package/build/src/types/decorators.d.ts +13 -0
- package/build/src/types/decorators.js +1 -0
- package/build/src/types/index.d.ts +155 -0
- package/build/src/types/index.js +1 -0
- package/build/src/types/instrumentations.d.ts +79 -0
- package/build/src/types/instrumentations.js +1 -0
- package/build/src/types/logging.d.ts +12 -0
- package/build/src/types/logging.js +13 -0
- package/build/stubs/config.stub +12 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/main.js +7 -0
- package/build/stubs/otel.stub +12 -0
- package/package.json +134 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @adonisjs/otel
|
|
2
|
+
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
OpenTelemetry integration for AdonisJS with sensible defaults and zero-config setup. Get distributed tracing, metrics, and automatic instrumentation out of the box.
|
|
10
|
+
|
|
11
|
+
## Official Documentation
|
|
12
|
+
|
|
13
|
+
The documentation is available on the [AdonisJS website](https://docs.adonisjs.com/guides/digging-deeper/otel)
|
|
14
|
+
|
|
15
|
+
## Contributing
|
|
16
|
+
|
|
17
|
+
One of the primary goals of AdonisJS is to have a vibrant community of users and contributors who believes in the principles of the framework.
|
|
18
|
+
|
|
19
|
+
We encourage you to read the [contribution guide](https://github.com/adonisjs/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.
|
|
20
|
+
|
|
21
|
+
## Code of Conduct
|
|
22
|
+
|
|
23
|
+
In order to ensure that the AdonisJS community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/adonisjs/.github/blob/main/docs/CODE_OF_CONDUCT.md).
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
AdonisJS OpenTelemetry is open-sourced software licensed under the [MIT license](LICENSE.md).
|
|
28
|
+
|
|
29
|
+
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/otel/checks.yml?style=for-the-badge
|
|
30
|
+
[gh-workflow-url]: https://github.com/adonisjs/otel/actions/workflows/checks.yml "Github action"
|
|
31
|
+
|
|
32
|
+
[npm-image]: https://img.shields.io/npm/v/@adonisjs/otel/latest.svg?style=for-the-badge&logo=npm
|
|
33
|
+
[npm-url]: https://www.npmjs.com/package/@adonisjs/otel/v/latest "npm"
|
|
34
|
+
|
|
35
|
+
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
|
|
36
|
+
|
|
37
|
+
[license-url]: LICENSE.md
|
|
38
|
+
[license-image]: https://img.shields.io/github/license/adonisjs/otel?style=for-the-badge
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|--------------------------------------------------------------------------
|
|
3
|
+
| Configure hook
|
|
4
|
+
|--------------------------------------------------------------------------
|
|
5
|
+
|
|
|
6
|
+
| The configure hook is called when someone runs "node ace configure <package>"
|
|
7
|
+
| command. You are free to perform any operations inside this function to
|
|
8
|
+
| configure the package.
|
|
9
|
+
|
|
|
10
|
+
| To make things easier, you have access to the underlying "ConfigureCommand"
|
|
11
|
+
| instance and you can use codemods to modify the source files.
|
|
12
|
+
|
|
|
13
|
+
*/
|
|
14
|
+
import { stubsRoot } from './stubs/main.js';
|
|
15
|
+
export async function configure(command) {
|
|
16
|
+
const codemods = await command.createCodemods();
|
|
17
|
+
/**
|
|
18
|
+
* Publish the configuration file
|
|
19
|
+
*/
|
|
20
|
+
await codemods.makeUsingStub(stubsRoot, 'config.stub', {});
|
|
21
|
+
/**
|
|
22
|
+
* Publish the bin/otel.ts file
|
|
23
|
+
*/
|
|
24
|
+
await codemods.makeUsingStub(stubsRoot, 'otel.stub', {});
|
|
25
|
+
/**
|
|
26
|
+
* Add import to bin/server.ts as the FIRST import
|
|
27
|
+
* This is critical for auto-instrumentation to work
|
|
28
|
+
*/
|
|
29
|
+
const project = await codemods.getTsMorphProject();
|
|
30
|
+
const serverFile = project?.getSourceFile(command.app.makePath('bin/server.ts'));
|
|
31
|
+
if (serverFile) {
|
|
32
|
+
const firstImport = serverFile.getImportDeclarations()[0];
|
|
33
|
+
const insertIndex = firstImport?.getChildIndex() ?? 0;
|
|
34
|
+
serverFile.insertStatements(insertIndex, [
|
|
35
|
+
'/**',
|
|
36
|
+
' * OpenTelemetry initialization - MUST be the first import',
|
|
37
|
+
' * @see https://opentelemetry.io/docs/languages/js/getting-started/nodejs/',
|
|
38
|
+
' */',
|
|
39
|
+
`import './otel.js'`,
|
|
40
|
+
'',
|
|
41
|
+
]);
|
|
42
|
+
await serverFile.save();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Register the provider
|
|
46
|
+
*/
|
|
47
|
+
await codemods.updateRcFile((rcFile) => rcFile.addProvider('@adonisjs/otel/otel_provider'));
|
|
48
|
+
/**
|
|
49
|
+
* Register the middleware
|
|
50
|
+
*/
|
|
51
|
+
await codemods.registerMiddleware('router', [
|
|
52
|
+
{ path: '@adonisjs/otel/otel_middleware', position: 'before' },
|
|
53
|
+
]);
|
|
54
|
+
/**
|
|
55
|
+
* Add new environment variables
|
|
56
|
+
*/
|
|
57
|
+
await codemods.defineEnvVariables({
|
|
58
|
+
APP_NAME: command.app.appName,
|
|
59
|
+
APP_VERSION: '0.0.1',
|
|
60
|
+
APP_ENV: 'development',
|
|
61
|
+
});
|
|
62
|
+
await codemods.defineEnvValidations({
|
|
63
|
+
variables: {
|
|
64
|
+
APP_NAME: 'Env.schema.string()',
|
|
65
|
+
APP_VERSION: 'Env.schema.string()',
|
|
66
|
+
APP_ENV: "Env.schema.enum(['development', 'staging', 'production'] as const)",
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { configure } from './configure.js';
|
|
2
|
+
export { defineConfig } from './src/define_config.js';
|
|
3
|
+
export { OtelManager } from './src/otel.js';
|
|
4
|
+
/**
|
|
5
|
+
* Re-export OTLP exporters so users don't need to install those 100 packages
|
|
6
|
+
* from OpenTelemetry just to get the exporters.
|
|
7
|
+
*/
|
|
8
|
+
export { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
|
|
9
|
+
export { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
|
|
10
|
+
export { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
11
|
+
export { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
|
package/build/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|--------------------------------------------------------------------------
|
|
3
|
+
| Package entrypoint
|
|
4
|
+
|--------------------------------------------------------------------------
|
|
5
|
+
|
|
|
6
|
+
| Export values from the package entrypoint as you see fit.
|
|
7
|
+
|
|
|
8
|
+
*/
|
|
9
|
+
export { configure } from './configure.js';
|
|
10
|
+
export { defineConfig } from './src/define_config.js';
|
|
11
|
+
export { OtelManager } from './src/otel.js';
|
|
12
|
+
/**
|
|
13
|
+
* Re-export OTLP exporters so users don't need to install those 100 packages
|
|
14
|
+
* from OpenTelemetry just to get the exporters.
|
|
15
|
+
*/
|
|
16
|
+
export { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
|
|
17
|
+
export { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
|
|
18
|
+
export { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
19
|
+
export { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
2
|
+
export default class OtelProvider {
|
|
3
|
+
#private;
|
|
4
|
+
protected app: ApplicationService;
|
|
5
|
+
constructor(app: ApplicationService);
|
|
6
|
+
register(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Gracefully flush pending spans
|
|
9
|
+
*/
|
|
10
|
+
shutdown(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
2
|
+
import { configProvider } from '@adonisjs/core';
|
|
3
|
+
import { ExceptionHandler } from '@adonisjs/core/http';
|
|
4
|
+
import { getCurrentSpan } from '../src/helpers.js';
|
|
5
|
+
import OtelMiddleware from '../src/middleware/otel_middleware.js';
|
|
6
|
+
import { OtelManager } from '../src/otel.js';
|
|
7
|
+
export default class OtelProvider {
|
|
8
|
+
app;
|
|
9
|
+
constructor(app) {
|
|
10
|
+
this.app = app;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Hook into ExceptionHandler to record exceptions in spans
|
|
14
|
+
*/
|
|
15
|
+
#registerExceptionHandler() {
|
|
16
|
+
const originalReport = ExceptionHandler.prototype.report;
|
|
17
|
+
ExceptionHandler.macro('report', async function (error, ctx) {
|
|
18
|
+
// @ts-expect-error - protected method
|
|
19
|
+
const httpError = this.toHttpError(error);
|
|
20
|
+
if (!this.shouldReport(httpError))
|
|
21
|
+
return;
|
|
22
|
+
const span = getCurrentSpan();
|
|
23
|
+
if (span && error instanceof Error) {
|
|
24
|
+
span.recordException(error);
|
|
25
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
26
|
+
}
|
|
27
|
+
return originalReport.call(this, error, ctx);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
register() {
|
|
31
|
+
this.#registerExceptionHandler();
|
|
32
|
+
this.#registerMiddleware();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register the OtelMiddleware as a singleton in the container
|
|
36
|
+
*/
|
|
37
|
+
#registerMiddleware() {
|
|
38
|
+
this.app.container.singleton(OtelMiddleware, async () => {
|
|
39
|
+
const otelConfigProvider = this.app.config.get('otel', {});
|
|
40
|
+
const config = await configProvider.resolve(this.app, otelConfigProvider);
|
|
41
|
+
return new OtelMiddleware({ userContext: config?.userContext });
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gracefully flush pending spans
|
|
46
|
+
*/
|
|
47
|
+
async shutdown() {
|
|
48
|
+
await OtelManager.getInstance()?.shutdown();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { SpanOptions } from './types/index.js';
|
|
2
|
+
type Constructor = new (...args: any[]) => any;
|
|
3
|
+
/**
|
|
4
|
+
* Decorator to create a span around a method.
|
|
5
|
+
*
|
|
6
|
+
* Automatically handles:
|
|
7
|
+
* - Creating and closing the span
|
|
8
|
+
* - Capturing exceptions and setting error status
|
|
9
|
+
* - Async/await support
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { span } from '@adonisjs/otel'
|
|
14
|
+
*
|
|
15
|
+
* class UserService {
|
|
16
|
+
* @span()
|
|
17
|
+
* async findById(id: string) {
|
|
18
|
+
* // Span name: "UserService.findById"
|
|
19
|
+
* return db.users.find(id)
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* @span({ name: 'user.create', attributes: { operation: 'create' } })
|
|
23
|
+
* async create(data: UserData) {
|
|
24
|
+
* return db.users.create(data)
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function span(options?: SpanOptions): (target: object, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
30
|
+
/**
|
|
31
|
+
* Decorator to create spans around all methods of a class.
|
|
32
|
+
*
|
|
33
|
+
* Automatically handles:
|
|
34
|
+
* - Creating and closing spans for each method
|
|
35
|
+
* - Capturing exceptions and setting error status
|
|
36
|
+
* - Async/await support
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { spanAll } from '@adonisjs/otel'
|
|
41
|
+
*
|
|
42
|
+
* @spanAll()
|
|
43
|
+
* class OrderService {
|
|
44
|
+
* async create(data: OrderData) {
|
|
45
|
+
* // Span name: "OrderService.create"
|
|
46
|
+
* return db.orders.create(data)
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* async findById(id: string) {
|
|
50
|
+
* // Span name: "OrderService.findById"
|
|
51
|
+
* return db.orders.find(id)
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* @spanAll({ prefix: 'order' })
|
|
56
|
+
* class OrderService {
|
|
57
|
+
* async create(data: OrderData) {
|
|
58
|
+
* // Span name: "order.create"
|
|
59
|
+
* return db.orders.create(data)
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function spanAll(options?: {
|
|
65
|
+
prefix?: string;
|
|
66
|
+
attributes?: Record<string, string | number | boolean>;
|
|
67
|
+
}): <T extends Constructor>(constructor: T) => T;
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { record } from './helpers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a method to create a span around its execution
|
|
4
|
+
*/
|
|
5
|
+
function wrapMethod(target, propertyKey, descriptor, options) {
|
|
6
|
+
const originalMethod = descriptor.value;
|
|
7
|
+
const className = target.constructor.name;
|
|
8
|
+
descriptor.value = function (...args) {
|
|
9
|
+
const spanName = options?.name ?? `${className}.${propertyKey}`;
|
|
10
|
+
return record(spanName, (activeSpan) => {
|
|
11
|
+
if (options?.attributes)
|
|
12
|
+
activeSpan.setAttributes(options.attributes);
|
|
13
|
+
return originalMethod.apply(this, args);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
return descriptor;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Decorator to create a span around a method.
|
|
20
|
+
*
|
|
21
|
+
* Automatically handles:
|
|
22
|
+
* - Creating and closing the span
|
|
23
|
+
* - Capturing exceptions and setting error status
|
|
24
|
+
* - Async/await support
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { span } from '@adonisjs/otel'
|
|
29
|
+
*
|
|
30
|
+
* class UserService {
|
|
31
|
+
* @span()
|
|
32
|
+
* async findById(id: string) {
|
|
33
|
+
* // Span name: "UserService.findById"
|
|
34
|
+
* return db.users.find(id)
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* @span({ name: 'user.create', attributes: { operation: 'create' } })
|
|
38
|
+
* async create(data: UserData) {
|
|
39
|
+
* return db.users.create(data)
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function span(options) {
|
|
45
|
+
return function (target, propertyKey, descriptor) {
|
|
46
|
+
return wrapMethod(target, propertyKey, descriptor, options);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Decorator to create spans around all methods of a class.
|
|
51
|
+
*
|
|
52
|
+
* Automatically handles:
|
|
53
|
+
* - Creating and closing spans for each method
|
|
54
|
+
* - Capturing exceptions and setting error status
|
|
55
|
+
* - Async/await support
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { spanAll } from '@adonisjs/otel'
|
|
60
|
+
*
|
|
61
|
+
* @spanAll()
|
|
62
|
+
* class OrderService {
|
|
63
|
+
* async create(data: OrderData) {
|
|
64
|
+
* // Span name: "OrderService.create"
|
|
65
|
+
* return db.orders.create(data)
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* async findById(id: string) {
|
|
69
|
+
* // Span name: "OrderService.findById"
|
|
70
|
+
* return db.orders.find(id)
|
|
71
|
+
* }
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* @spanAll({ prefix: 'order' })
|
|
75
|
+
* class OrderService {
|
|
76
|
+
* async create(data: OrderData) {
|
|
77
|
+
* // Span name: "order.create"
|
|
78
|
+
* return db.orders.create(data)
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function spanAll(options) {
|
|
84
|
+
return function (constructor) {
|
|
85
|
+
const prototype = constructor.prototype;
|
|
86
|
+
const propertyNames = Object.getOwnPropertyNames(prototype);
|
|
87
|
+
for (const propertyName of propertyNames) {
|
|
88
|
+
if (propertyName === 'constructor')
|
|
89
|
+
continue;
|
|
90
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
|
|
91
|
+
if (!descriptor || typeof descriptor.value !== 'function')
|
|
92
|
+
continue;
|
|
93
|
+
const spanName = options?.prefix ? `${options.prefix}.${propertyName}` : undefined;
|
|
94
|
+
const wrappedDescriptor = wrapMethod(prototype, propertyName, descriptor, {
|
|
95
|
+
name: spanName,
|
|
96
|
+
attributes: options?.attributes,
|
|
97
|
+
});
|
|
98
|
+
Object.defineProperty(prototype, propertyName, wrappedDescriptor);
|
|
99
|
+
}
|
|
100
|
+
return constructor;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { Attributes, Span } from '@opentelemetry/api';
|
|
2
|
+
import { type HeadersCarrier, type OtelLoggingPresetOptions, type UserContextResult } from './types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get the currently active span from the current context.
|
|
5
|
+
*
|
|
6
|
+
* Returns `undefined` if there is no active span.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { getCurrentSpan } from '@adonisjs/otel'
|
|
11
|
+
*
|
|
12
|
+
* function myUtility() {
|
|
13
|
+
* const span = getCurrentSpan()
|
|
14
|
+
* span?.setAttributes({ 'custom.attribute': 'value' })
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function getCurrentSpan(): Span | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Set attributes on the currently active span.
|
|
21
|
+
*
|
|
22
|
+
* This is a convenience wrapper around `getCurrentSpan()?.setAttributes()`.
|
|
23
|
+
* Does nothing if there is no active span.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { setAttributes } from '@adonisjs/otel'
|
|
28
|
+
*
|
|
29
|
+
* function processOrder(orderId: string) {
|
|
30
|
+
* setAttributes({
|
|
31
|
+
* 'order.id': orderId,
|
|
32
|
+
* 'order.type': 'subscription',
|
|
33
|
+
* })
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function setAttributes(attributes: Attributes): void;
|
|
38
|
+
/**
|
|
39
|
+
* Record a code section as a span in your traces.
|
|
40
|
+
*
|
|
41
|
+
* Automatically handles:
|
|
42
|
+
* - Creating and closing the span
|
|
43
|
+
* - Capturing exceptions and setting error status
|
|
44
|
+
* - Async/await support
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { record } from '@adonisjs/otel'
|
|
49
|
+
*
|
|
50
|
+
* // Sync
|
|
51
|
+
* const result = record('database.query', () => {
|
|
52
|
+
* return db.query('SELECT * FROM users')
|
|
53
|
+
* })
|
|
54
|
+
*
|
|
55
|
+
* // Async
|
|
56
|
+
* const user = await record('user.fetch', async () => {
|
|
57
|
+
* return await userService.findById(id)
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // With attributes
|
|
61
|
+
* const order = await record('order.process', async (span) => {
|
|
62
|
+
* span.setAttributes({ 'order.id': orderId })
|
|
63
|
+
* return await processOrder(orderId)
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function record<T>(name: string, callback: (span: Span) => T): T;
|
|
68
|
+
export declare function handleError(span: Span, error: Error): void;
|
|
69
|
+
/**
|
|
70
|
+
* Set user information on the currently active span.
|
|
71
|
+
*
|
|
72
|
+
* Uses OpenTelemetry semantic conventions for user attributes.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { setUser } from '@adonisjs/otel'
|
|
77
|
+
*
|
|
78
|
+
* // In a controller or middleware
|
|
79
|
+
* setUser({
|
|
80
|
+
* id: auth.user.id,
|
|
81
|
+
* email: auth.user.email,
|
|
82
|
+
* role: auth.user.role,
|
|
83
|
+
* })
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare function setUser(user: UserContextResult): void;
|
|
87
|
+
/**
|
|
88
|
+
* Inject the current trace context into headers for propagation.
|
|
89
|
+
*
|
|
90
|
+
* Use this when making outgoing HTTP requests, dispatching queue jobs,
|
|
91
|
+
* or any cross-service communication where you want to maintain trace continuity.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { injectTraceContext } from '@adonisjs/otel'
|
|
96
|
+
*
|
|
97
|
+
* // HTTP request to another service
|
|
98
|
+
* const headers = {}
|
|
99
|
+
* injectTraceContext(headers)
|
|
100
|
+
* await fetch('https://api.example.com', { headers })
|
|
101
|
+
*
|
|
102
|
+
* // Queue job dispatch
|
|
103
|
+
* const jobHeaders = {}
|
|
104
|
+
* injectTraceContext(jobHeaders)
|
|
105
|
+
* await queue.dispatch('process-order', { orderId }, { headers: jobHeaders })
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function injectTraceContext(headers: HeadersCarrier): void;
|
|
109
|
+
/**
|
|
110
|
+
* Extract trace context from incoming headers.
|
|
111
|
+
*
|
|
112
|
+
* Use this in queue workers, background jobs, or any service receiving
|
|
113
|
+
* requests from another traced service to continue the trace.
|
|
114
|
+
*
|
|
115
|
+
* @returns The extracted context that can be used with `record()` or `trace.startActiveSpan()`
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { extractTraceContext, record } from '@adonisjs/otel'
|
|
120
|
+
* import { context } from '@opentelemetry/api'
|
|
121
|
+
*
|
|
122
|
+
* // In a queue worker
|
|
123
|
+
* const extractedContext = extractTraceContext(job.headers)
|
|
124
|
+
*
|
|
125
|
+
* context.with(extractedContext, () => {
|
|
126
|
+
* record('process-job', () => {
|
|
127
|
+
* // This span will be a child of the original trace
|
|
128
|
+
* })
|
|
129
|
+
* })
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function extractTraceContext(headers: HeadersCarrier): import("@opentelemetry/api").Context;
|
|
133
|
+
/**
|
|
134
|
+
* Record an event on the currently active span.
|
|
135
|
+
*
|
|
136
|
+
* Events are time-stamped annotations that can be attached to spans
|
|
137
|
+
* to record discrete occurrences during a span's lifetime.
|
|
138
|
+
*
|
|
139
|
+
* @see https://opentelemetry.io/docs/concepts/signals/traces/#span-events
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { recordEvent } from '@adonisjs/otel'
|
|
144
|
+
*
|
|
145
|
+
* // Simple event
|
|
146
|
+
* recordEvent('cache.miss')
|
|
147
|
+
*
|
|
148
|
+
* // Event with attributes
|
|
149
|
+
* recordEvent('order.processed', {
|
|
150
|
+
* 'order.id': orderId,
|
|
151
|
+
* 'order.total': 99.99,
|
|
152
|
+
* })
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export declare function recordEvent(name: string, attributes?: Attributes): void;
|
|
156
|
+
/**
|
|
157
|
+
* Preset for pino-pretty to hide OpenTelemetry-injected fields ( in development).
|
|
158
|
+
*
|
|
159
|
+
* By default, hides: pid, hostname, trace_id, span_id, trace_flags, route, request_id, x-request-id
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* import { otelLoggingPreset } from '@adonisjs/otel'
|
|
164
|
+
*
|
|
165
|
+
* // Hide all OTEL fields
|
|
166
|
+
* targets.pretty(otelLoggingPreset())
|
|
167
|
+
*
|
|
168
|
+
* // Keep trace context visible
|
|
169
|
+
* targets.pretty(otelLoggingPreset({ keep: ['trace_id', 'span_id'] }))
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function otelLoggingPreset(options?: OtelLoggingPresetOptions): {
|
|
173
|
+
ignore: string;
|
|
174
|
+
};
|