@grupodiariodaregiao/bunstone 0.6.0 → 0.7.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/AGENTS.md CHANGED
@@ -193,6 +193,7 @@ This file is published with the `@grupodiariodaregiao/bunstone` package so codin
193
193
  - `docs/pt-BR/routing-params.md`
194
194
  - `docs/pt-BR/scheduling.md`
195
195
  - `docs/pt-BR/testing.md`
196
+ - `docs/telemetry.md`
196
197
 
197
198
  ## Bundled Examples
198
199
 
@@ -5559,6 +5560,303 @@ it("deve mockar um command handler", async () => {
5559
5560
  O utilitário `Test.createTestingModule()` limpa automaticamente o `GlobalRegistry` e o estado interno antes da compilação, garantindo que os testes permaneçam isolados entre si.
5560
5561
  ````
5561
5562
 
5563
+ ## Source: `docs/telemetry.md`
5564
+
5565
+ ````md
5566
+ # OpenTelemetry (Observability)
5567
+
5568
+ Bunstone has built-in OpenTelemetry instrumentation that automatically captures **traces** and **metrics** from all major application layers — no manual instrumentation required.
5569
+
5570
+ ## What gets instrumented automatically
5571
+
5572
+ | Layer | Traces | Metrics |
5573
+ |---|---|---|
5574
+ | **HTTP** (Elysia routes) | ✅ Per-request spans with route, method, status | ✅ `http.server.request.duration`, `http.server.request.count` |
5575
+ | **SQL** | ✅ Per-query spans with operation and sanitized SQL | ✅ `db.query.duration` |
5576
+ | **CQRS — Commands** | ✅ Per-command spans | ✅ `cqrs.command.duration` |
5577
+ | **CQRS — Queries** | ✅ Per-query spans | ✅ `cqrs.query.duration` |
5578
+ | **CQRS — Events** | ✅ Per-publish spans | ✅ `cqrs.event.publish.count` |
5579
+ | **RabbitMQ — publish** | ✅ Producer spans + W3C context injection | ✅ `messaging.rabbitmq.publish.duration` |
5580
+ | **RabbitMQ — consume** | ✅ Consumer spans + W3C context extraction | ✅ `messaging.rabbitmq.consume.duration` |
5581
+ | **BullMQ — process** | ✅ Per-job spans | ✅ `messaging.bullmq.process.duration` |
5582
+
5583
+ > **Context propagation is automatic.** Because every HTTP request runs inside an OTel `AsyncLocalStorage` context, SQL queries, CQRS commands, and message publishes that happen during a request are automatically nested as child spans of the HTTP span — no manual context passing needed.
5584
+
5585
+ ## Quick start
5586
+
5587
+ ### 1. Install (already included in Bunstone)
5588
+
5589
+ ```bash
5590
+ # OTel packages are bundled — nothing extra to install
5591
+ ```
5592
+
5593
+ ### 2. Register `TelemetryModule`
5594
+
5595
+ Add it as the **first** import in your root module so the SDK is ready before any routes start handling requests.
5596
+
5597
+ ```typescript
5598
+ import { Module, TelemetryModule } from "@grupodiariodaregiao/bunstone";
5599
+
5600
+ @Module({
5601
+ imports: [
5602
+ TelemetryModule.register({
5603
+ serviceName: "orders-api",
5604
+ serviceVersion: "1.2.0",
5605
+ environment: process.env.NODE_ENV ?? "production",
5606
+ traces: {
5607
+ otlp: { endpoint: "http://otel-collector:4318" },
5608
+ },
5609
+ metrics: {
5610
+ otlp: { endpoint: "http://otel-collector:4318" },
5611
+ exportIntervalMillis: 30_000,
5612
+ },
5613
+ }),
5614
+ // ... other modules
5615
+ ],
5616
+ })
5617
+ export class AppModule {}
5618
+ ```
5619
+
5620
+ ### 3. Start your app normally
5621
+
5622
+ ```typescript
5623
+ import "reflect-metadata";
5624
+ import { AppStartup } from "@grupodiariodaregiao/bunstone";
5625
+ import { AppModule } from "./app.module";
5626
+
5627
+ const app = await AppStartup.create(AppModule);
5628
+ app.listen(3000);
5629
+ ```
5630
+
5631
+ That's it. All instrumented layers will immediately start producing telemetry.
5632
+
5633
+ ---
5634
+
5635
+ ## Configuration reference
5636
+
5637
+ ### `TelemetryOptions`
5638
+
5639
+ ```typescript
5640
+ interface TelemetryOptions {
5641
+ /** Service name included in all traces and metrics — required */
5642
+ serviceName: string;
5643
+
5644
+ /** Semantic version string (default: "unknown") */
5645
+ serviceVersion?: string;
5646
+
5647
+ /** Deployment environment, e.g. "production" (default: "production") */
5648
+ environment?: string;
5649
+
5650
+ traces?: {
5651
+ /** Enable tracing. Default: true */
5652
+ enabled?: boolean;
5653
+
5654
+ /** OTLP HTTP exporter options */
5655
+ otlp?: {
5656
+ /**
5657
+ * Base endpoint URL.
5658
+ * Traces are sent to {endpoint}/v1/traces.
5659
+ * Falls back to OTEL_EXPORTER_OTLP_ENDPOINT env var, then
5660
+ * "http://localhost:4318".
5661
+ */
5662
+ endpoint?: string;
5663
+ /** Extra HTTP headers for every OTLP request */
5664
+ headers?: Record<string, string>;
5665
+ };
5666
+
5667
+ /**
5668
+ * Sampling ratio 0.0–1.0.
5669
+ * 1.0 = record every span (default).
5670
+ * 0.1 = record 10 % of root spans.
5671
+ */
5672
+ sampleRatio?: number;
5673
+ };
5674
+
5675
+ metrics?: {
5676
+ /** Enable metrics. Default: true */
5677
+ enabled?: boolean;
5678
+
5679
+ otlp?: {
5680
+ endpoint?: string;
5681
+ headers?: Record<string, string>;
5682
+ };
5683
+
5684
+ /**
5685
+ * How often metrics are pushed to the exporter in milliseconds.
5686
+ * Default: 60_000 (1 minute).
5687
+ */
5688
+ exportIntervalMillis?: number;
5689
+ };
5690
+
5691
+ /**
5692
+ * Also print spans and metrics to stdout.
5693
+ * Useful in local development. Default: false.
5694
+ */
5695
+ consoleExport?: boolean;
5696
+ }
5697
+ ```
5698
+
5699
+ ---
5700
+
5701
+ ## Local development with console output
5702
+
5703
+ ```typescript
5704
+ TelemetryModule.register({
5705
+ serviceName: "my-api",
5706
+ consoleExport: true, // prints spans to stdout
5707
+ traces: { enabled: true },
5708
+ metrics: { enabled: true, exportIntervalMillis: 10_000 },
5709
+ })
5710
+ ```
5711
+
5712
+ ---
5713
+
5714
+ ## Connecting to a collector
5715
+
5716
+ Any OpenTelemetry-compatible collector works.
5717
+
5718
+ ### Jaeger (all-in-one)
5719
+
5720
+ ```bash
5721
+ docker run -d \
5722
+ -p 4318:4318 \ # OTLP HTTP
5723
+ -p 16686:16686 \ # Jaeger UI
5724
+ jaegertracing/all-in-one:latest
5725
+ ```
5726
+
5727
+ ```typescript
5728
+ TelemetryModule.register({
5729
+ serviceName: "my-api",
5730
+ traces: { otlp: { endpoint: "http://localhost:4318" } },
5731
+ })
5732
+ ```
5733
+
5734
+ Open <http://localhost:16686> to view traces.
5735
+
5736
+ ### Grafana + Tempo + Prometheus
5737
+
5738
+ ```typescript
5739
+ TelemetryModule.register({
5740
+ serviceName: "my-api",
5741
+ traces: {
5742
+ otlp: { endpoint: "http://tempo:4318" },
5743
+ },
5744
+ metrics: {
5745
+ otlp: { endpoint: "http://otel-collector:4318" },
5746
+ exportIntervalMillis: 15_000,
5747
+ },
5748
+ })
5749
+ ```
5750
+
5751
+ ### Using environment variables
5752
+
5753
+ Instead of hardcoding the endpoint you can set:
5754
+
5755
+ ```bash
5756
+ OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
5757
+ ```
5758
+
5759
+ and omit `otlp.endpoint` from the config object.
5760
+
5761
+ ---
5762
+
5763
+ ## Distributed tracing across services
5764
+
5765
+ Bunstone follows the **W3C Trace Context** standard ([RFC](https://www.w3.org/TR/trace-context/)).
5766
+
5767
+ - **Incoming requests**: The `traceparent` / `tracestate` headers are automatically extracted and used as the parent context for all spans generated during that request.
5768
+ - **Outgoing RabbitMQ messages**: The current trace context is automatically injected into message headers so consumers in other services can continue the same trace.
5769
+
5770
+ This means a single distributed trace can span your Bunstone service **and** any downstream service that understands W3C Trace Context.
5771
+
5772
+ ---
5773
+
5774
+ ## Span and metric names reference
5775
+
5776
+ ### HTTP spans
5777
+
5778
+ | Attribute | Value |
5779
+ |---|---|
5780
+ | Span name | `{METHOD} {route}` — e.g. `GET /users/:id` |
5781
+ | `http.request.method` | `GET`, `POST`, etc. |
5782
+ | `http.route` | Parametrized route, e.g. `/users/:id` |
5783
+ | `url.path` | Actual path, e.g. `/users/123` |
5784
+ | `url.full` | Full URL |
5785
+ | `http.response.status_code` | HTTP status code |
5786
+ | Span status | `OK` for < 500, `ERROR` for ≥ 500 |
5787
+
5788
+ ### SQL spans
5789
+
5790
+ | Attribute | Value |
5791
+ |---|---|
5792
+ | Span name | `db.{OPERATION}` — e.g. `db.SELECT` |
5793
+ | `db.system` | `postgresql`, `mysql`, or `sqlite` |
5794
+ | `db.operation.name` | SQL operation keyword |
5795
+ | `db.query.text` | Sanitized SQL (parameter values replaced with `?`) |
5796
+
5797
+ ### CQRS spans
5798
+
5799
+ | Attribute | Value |
5800
+ |---|---|
5801
+ | Span name | `command.execute {CommandName}` / `query.execute {QueryName}` / `event.publish {EventName}` |
5802
+ | `cqrs.type` | `command`, `query`, or `event` |
5803
+ | `cqrs.command.name` / `cqrs.query.name` / `cqrs.event.name` | Class name of the command/query/event |
5804
+
5805
+ ### RabbitMQ spans
5806
+
5807
+ | Attribute | Value |
5808
+ |---|---|
5809
+ | Span name | `rabbitmq.publish {exchange}` or `rabbitmq.consume {queue}` |
5810
+ | `messaging.system` | `rabbitmq` |
5811
+ | `messaging.operation.type` | `publish` or `deliver` |
5812
+ | `messaging.destination.name` | Exchange or queue name |
5813
+ | `messaging.rabbitmq.destination.routing_key` | Routing key |
5814
+
5815
+ ### BullMQ spans
5816
+
5817
+ | Attribute | Value |
5818
+ |---|---|
5819
+ | Span name | `bullmq.process {queue}/{jobName}` |
5820
+ | `messaging.system` | `bullmq` |
5821
+ | `messaging.operation.type` | `process` |
5822
+ | `messaging.destination.name` | Queue name |
5823
+ | `messaging.bullmq.job.name` | Job name |
5824
+ | `messaging.bullmq.job.id` | Job ID |
5825
+ | `messaging.bullmq.job.attempts` | Number of processing attempts |
5826
+
5827
+ ---
5828
+
5829
+ ## Advanced: bring your own SDK
5830
+
5831
+ `TelemetryModule` is optional. If you already have a custom `TracerProvider` and `MeterProvider` set up via `@opentelemetry/api`, Bunstone's instrumentation will automatically use them — because all instrumentation only calls the OTel API, which delegates to whatever provider is globally registered.
5832
+
5833
+ ```typescript
5834
+ import { trace, metrics } from "@opentelemetry/api";
5835
+
5836
+ // Set up your own providers before AppStartup.create()
5837
+ trace.setGlobalTracerProvider(myTracerProvider);
5838
+ metrics.setGlobalMeterProvider(myMeterProvider);
5839
+
5840
+ // Then start the app — no TelemetryModule needed
5841
+ const app = await AppStartup.create(AppModule);
5842
+ ```
5843
+
5844
+ ---
5845
+
5846
+ ## Graceful shutdown
5847
+
5848
+ `TelemetryModule` registers an `onModuleDestroy` lifecycle hook that flushes all pending spans and metrics before the process exits. If you're not using `TelemetryModule`, call `TelemetrySdk.shutdown()` manually:
5849
+
5850
+ ```typescript
5851
+ import { TelemetrySdk } from "@grupodiariodaregiao/bunstone";
5852
+
5853
+ process.on("SIGTERM", async () => {
5854
+ await TelemetrySdk.shutdown();
5855
+ process.exit(0);
5856
+ });
5857
+ ```
5858
+ ````
5859
+
5562
5860
  ## Full Examples
5563
5861
 
5564
5862
  ## Source: `examples/01-basic-app/index.ts`
package/dist/index.d.ts CHANGED
@@ -63,6 +63,9 @@ export * from "./lib/types/options";
63
63
  export * from "./lib/types/module-config";
64
64
  export * from "./lib/schedule/cron/cron";
65
65
  export * from "./lib/schedule/timeout/timeout";
66
+ export { TelemetryModule } from "./lib/telemetry/telemetry-module";
67
+ export { TelemetrySdk } from "./lib/telemetry/telemetry.sdk";
68
+ export type { TelemetryOptions, OtlpExporterOptions } from "./lib/telemetry/interfaces/telemetry-options.interface";
66
69
  export * from "./lib/testing/test";
67
70
  export * from "./lib/testing/testing-module";
68
71
  export * from "./lib/testing/test-app";