nestjs-otel 8.0.2 → 8.0.4-alpha.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/.claude/settings.json +24 -0
- package/.claude/settings.local.json +14 -0
- package/.tmp_build.out +3 -0
- package/CLAUDE.md +56 -0
- package/README.md +119 -0
- package/graphify-out/.graphify_labels.json +12 -0
- package/graphify-out/.graphify_python +1 -0
- package/graphify-out/.graphify_root +1 -0
- package/graphify-out/GRAPH_REPORT.md +89 -0
- package/graphify-out/cost.json +12 -0
- package/graphify-out/graph.html +6110 -0
- package/graphify-out/graph.json +4603 -0
- package/graphify-out/manifest.json +167 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/interfaces/opentelemetry-options.interface.d.ts +19 -7
- package/lib/opentelemetry-core.module.js +30 -4
- package/lib/tracing/decorators/span.js +1 -3
- package/lib/tracing/decorators/span.spec.js +147 -0
- package/lib/wide-events/wide-event-field.decorator.d.ts +14 -0
- package/lib/wide-events/wide-event-field.decorator.js +77 -0
- package/lib/wide-events/wide-event-field.decorator.spec.d.ts +1 -0
- package/lib/wide-events/wide-event-field.decorator.spec.js +144 -0
- package/lib/wide-events/wide-event.context.d.ts +4 -0
- package/lib/wide-events/wide-event.context.js +9 -0
- package/lib/wide-events/wide-event.interceptor.d.ts +20 -0
- package/lib/wide-events/wide-event.interceptor.js +104 -0
- package/lib/wide-events/wide-event.interceptor.spec.d.ts +1 -0
- package/lib/wide-events/wide-event.interceptor.spec.js +145 -0
- package/lib/wide-events/wide-event.service.d.ts +29 -0
- package/lib/wide-events/wide-event.service.js +73 -0
- package/lib/wide-events/wide-event.service.spec.d.ts +1 -0
- package/lib/wide-events/wide-event.service.spec.js +105 -0
- package/package.json +3 -2
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Bash",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "CMD=$(python3 -c \"import json,sys; d=json.load(sys.stdin); print(d.get('tool_input',d).get('command',''))\" 2>/dev/null || true); case \"$CMD\" in *grep*|*rg\\ *|*ripgrep*|*find\\ *|*fd\\ *|*ack\\ *|*ag\\ *) [ -f graphify-out/graph.json ] && echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"MANDATORY: graphify-out/graph.json exists. You MUST run `graphify query \\\"<question>\\\"` before grepping raw files. Only grep after graphify has oriented you, or to modify/debug specific lines.\"}}' || true ;; esac"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"matcher": "Read|Glob",
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "HIT=$(python3 -c \"import json,sys;d=json.load(sys.stdin);t=d.get('tool_input',d);s=(str(t.get('file_path') or '')+' '+str(t.get('pattern') or '')+' '+str(t.get('path') or '')).lower().replace(chr(92),'/');exts=('.py','.js','.ts','.tsx','.jsx','.go','.rs','.java','.rb','.c','.h','.cpp','.hpp','.cc','.cs','.kt','.swift','.php','.scala','.lua','.sh','.md','.rst','.txt','.mdx');sys.stdout.write('1' if 'graphify-out/' not in s and any(e in s for e in exts) else '')\" 2>/dev/null || true); if [ \"$HIT\" = 1 ] && [ -f graphify-out/graph.json ]; then echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"MANDATORY: graphify-out/graph.json exists. You MUST run graphify before reading source files. Use: `graphify query \\\"<question>\\\"` (scoped subgraph), `graphify explain \\\"<concept>\\\"`, or `graphify path \\\"<A>\\\" \\\"<B>\\\"`. Only read raw files after graphify has oriented you, or to modify/debug specific lines. This rule applies to subagents too \u2014 include it in every subagent prompt involving code exploration.\"}}'; fi || true"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(cp tests/e2e/wide-events/wide-event.spec.ts /tmp/we.bak)",
|
|
5
|
+
"Bash(cp /tmp/we.bak tests/e2e/wide-events/wide-event.spec.ts)",
|
|
6
|
+
"Bash(graphify query *)",
|
|
7
|
+
"Bash(rtk npm *)",
|
|
8
|
+
"Bash(rtk jest *)",
|
|
9
|
+
"WebFetch(domain:jeremymorrell.dev)",
|
|
10
|
+
"WebFetch(domain:boristane.com)",
|
|
11
|
+
"WebFetch(domain:isburmistrov.substack.com)"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
package/.tmp_build.out
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
`nestjs-otel` — NestJS module wrapping OpenTelemetry (`@opentelemetry/api`). Published library (`main: lib/index.js`). Provides tracing, metrics, and wide-events to NestJS apps. Node >= 22. NestJS 11 peer dep.
|
|
8
|
+
|
|
9
|
+
The library does **not** start the OTEL SDK. Consumers create their own `NodeSDK` (`tracing.ts`) and call `otelSDK.start()` before `NestFactory.create`. This module reads the global tracer/meter providers the SDK registers (`trace.getTracer`, `metrics.getMeterProvider`).
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm run build # tsc → lib/ (prebuild rimraf's lib first)
|
|
15
|
+
npm run lint # ultracite check (biome wrapper)
|
|
16
|
+
npm run format # ultracite fix (auto-fix lint)
|
|
17
|
+
npm test # unit + e2e
|
|
18
|
+
npm run test:unit # jest, *.spec.ts under src/
|
|
19
|
+
npm run test:e2e # jest tests/jest-e2e.json, --runInBand
|
|
20
|
+
npm run test:coverage
|
|
21
|
+
npm run test:watch
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Run a single test: `npx jest src/wide-events/wide-event.service.spec.ts` (or `-t "<test name>"`). E2E single: `npx jest --config ./tests/jest-e2e.json tests/e2e/<file>.e2e-spec.ts`.
|
|
25
|
+
|
|
26
|
+
Unit specs live next to source under `src/`. E2E specs in `tests/e2e/` run against `tests/fixture-app/` (a real NestJS app). Commits use Conventional Commits (commitlint + husky). `lint-staged` runs `ultracite fix` on staged files.
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
`OpenTelemetryModule.forRoot(options)` / `forRootAsync(options)` (`src/opentelemetry.module.ts`) are thin shells delegating to `OpenTelemetryCoreModule` (`src/opentelemetry-core.module.ts`). The core module is `@Global`, registers + exports `TraceService`, `MetricService`, `WideEventService`, `WideEventInterceptor`, and the `OPENTELEMETRY_MODULE_OPTIONS` token. `onApplicationBootstrap` is the only runtime side effect — it starts `HostMetrics` when `options.metrics.hostMetrics` is true. `forRootAsync` supports `useFactory` / `useClass` / `useExisting` via `OpenTelemetryOptionsFactory`.
|
|
31
|
+
|
|
32
|
+
Three feature areas, each exported through `src/index.ts`:
|
|
33
|
+
|
|
34
|
+
- **tracing** (`src/tracing/`): `TraceService` is a thin accessor over the global tracer. The real work is in decorators (`src/tracing/decorators/`): `@Span(name?, options?)` wraps a method in `startActiveSpan`, handles sync + Promise returns, records exceptions, supports an `onResult` callback to set attributes from the return value. `@Traceable` applies `@Span` to every method of a class. `@Baggage` / `@CurrentSpan` are param decorators. Decorators preserve the original function name/metadata via a `Proxy` + `copyMetadataFromFunctionToFunction` (`src/opentelemetry.utils.ts`) — critical so OpenAPI/Nest reflection still works.
|
|
35
|
+
|
|
36
|
+
- **metrics** (`src/metrics/`): `MetricService` exposes `getCounter`/`getHistogram`/`getGauge`/observable variants, all delegating to `getOrCreate*` in `src/metrics/metric-data.ts`, which caches instruments by name in a module-level map (idempotent re-fetch). `@InjectMetric(name)` (`src/metrics/injector.ts`) injects a named instrument via a DI token from `getToken`. Class/method decorators in `src/metrics/decorators/` (`OtelInstanceCounter`, `OtelMethodCounter`, etc.) auto-instrument.
|
|
37
|
+
|
|
38
|
+
- **wide-events** (`src/wide-events/`): one structured event (a wide span) per request. `WideEventInterceptor` opens a `WideEventBag` (a `Map`) stored on the active OTEL context under `WIDE_EVENT_CONTEXT_KEY`, then on `finalize` flushes all accumulated attributes onto the span that was active when the request entered. `WideEventService` (`set`/`setMany`/`increment`/`startTimer`) and the `@WideEventField` decorator mutate that bag via `getWideEventBag()` — all **no-ops outside an intercepted request**. The interceptor seeds `code.function.name` plus an optional `options.wideEvents.seed(executionContext)`, and records `error.type`/`error.message` on failure. Register globally with `APP_INTERCEPTOR` or per-controller with `@UseInterceptors`.
|
|
39
|
+
|
|
40
|
+
Options/interfaces in `src/interfaces/`. Constants (token, tracer name `OTEL_TRACER_NAME`) in `src/opentelemetry.constants.ts`.
|
|
41
|
+
|
|
42
|
+
## Conventions
|
|
43
|
+
|
|
44
|
+
- Lint is `ultracite` (extends biome). Config in `biome.jsonc` already disables `noExplicitAny`, `useAwait`, barrel-file warnings — `any` is used freely in decorator code by design. Run `npm run format` before committing.
|
|
45
|
+
- Public API symbols are tagged `@publicApi`; internal ones `@internal`. Keep new exports wired through `src/index.ts`.
|
|
46
|
+
- Decorators must not break function identity — when adding/altering a method decorator, preserve name + metadata as the existing ones do.
|
|
47
|
+
|
|
48
|
+
## graphify
|
|
49
|
+
|
|
50
|
+
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
|
|
51
|
+
|
|
52
|
+
Rules:
|
|
53
|
+
- For codebase questions, first run `graphify query "<question>"` when graphify-out/graph.json exists. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
|
|
54
|
+
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
|
|
55
|
+
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
|
|
56
|
+
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
|
package/README.md
CHANGED
|
@@ -306,6 +306,125 @@ export class BookService {
|
|
|
306
306
|
}
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
+
## Wide Events
|
|
310
|
+
|
|
311
|
+
Wide events (also known as canonical log lines) emit one context-rich event per request, with attributes accumulated across the whole request lifecycle. See [A Practitioner's Guide to Wide Events](https://jeremymorrell.dev/blog/a-practitioners-guide-to-wide-events/) for the pattern.
|
|
312
|
+
|
|
313
|
+
This library implements the pattern on top of OpenTelemetry: the `WideEventInterceptor` opens an attribute bag per request and, when the request finishes, flushes everything onto the span that was active when the request entered the interceptor (usually the root HTTP span created by your instrumentation). The `WideEventService` lets any provider enrich that bag from anywhere in the request's async call chain — no request-scoped injection needed.
|
|
314
|
+
|
|
315
|
+
1. Register the interceptor globally:
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
319
|
+
import { OpenTelemetryModule, WideEventInterceptor } from 'nestjs-otel';
|
|
320
|
+
|
|
321
|
+
@Module({
|
|
322
|
+
imports: [OpenTelemetryModule.forRoot()],
|
|
323
|
+
providers: [
|
|
324
|
+
{
|
|
325
|
+
provide: APP_INTERCEPTOR,
|
|
326
|
+
useClass: WideEventInterceptor,
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
})
|
|
330
|
+
export class AppModule {}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
The example above opens a wide event for **every** request in the application. To limit wide events to specific controllers instead, skip the `APP_INTERCEPTOR` provider and apply the interceptor directly with `@UseInterceptors`:
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
|
337
|
+
import { WideEventInterceptor } from 'nestjs-otel';
|
|
338
|
+
|
|
339
|
+
@Controller('checkout')
|
|
340
|
+
@UseInterceptors(WideEventInterceptor)
|
|
341
|
+
export class CheckoutController {
|
|
342
|
+
// every route in this controller now emits a wide event
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
2. Enrich the event from anywhere in the request:
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
import { WideEventService } from 'nestjs-otel';
|
|
350
|
+
|
|
351
|
+
@Injectable()
|
|
352
|
+
export class CheckoutService {
|
|
353
|
+
constructor(private readonly wideEvent: WideEventService) {}
|
|
354
|
+
|
|
355
|
+
async checkout(cart: Cart) {
|
|
356
|
+
this.wideEvent.setMany({
|
|
357
|
+
'user.id': cart.userId,
|
|
358
|
+
'cart.items': cart.items.length,
|
|
359
|
+
'cart.total': cart.total,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
const stopTimer = this.wideEvent.startTimer('payment.duration_ms');
|
|
363
|
+
await this.paymentGateway.charge(cart);
|
|
364
|
+
stopTimer();
|
|
365
|
+
|
|
366
|
+
this.wideEvent.increment('db.queries');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
All accumulated attributes land on the root span as a single wide event:
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
http_request
|
|
375
|
+
├── code.function.name: CheckoutController.checkout
|
|
376
|
+
├── user.id: u-123
|
|
377
|
+
├── cart.items: 3
|
|
378
|
+
├── cart.total: 42.5
|
|
379
|
+
├── payment.duration_ms: 132.7
|
|
380
|
+
├── db.queries: 1
|
|
381
|
+
├── error.type: PaymentDeclinedError (set automatically on errors)
|
|
382
|
+
└── error.message: card declined (set automatically on errors)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Notes:
|
|
386
|
+
|
|
387
|
+
- The interceptor seeds `code.function.name` (`<Controller>.<handler>`) automatically and records `error.type`/`error.message` when the handler throws.
|
|
388
|
+
- `WideEventService` methods are safe no-ops outside a request handled by the interceptor.
|
|
389
|
+
- An async-context-aware context manager is required (the default with `NodeSDK` / `AsyncLocalStorageContextManager`), same as for tracing in general.
|
|
390
|
+
|
|
391
|
+
### Seeding baseline attributes
|
|
392
|
+
|
|
393
|
+
Use the `seed` option to populate baseline attributes on every request (e.g. ids derived from the authenticated request). It runs after guards, so `req.user` is available. A throwing seed never breaks the request — the error is recorded under `wide_event.seed.error`.
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
OpenTelemetryModule.forRoot({
|
|
397
|
+
wideEvents: {
|
|
398
|
+
seed: (ctx) => {
|
|
399
|
+
const req = ctx.switchToHttp().getRequest();
|
|
400
|
+
return {
|
|
401
|
+
'app.version': process.env.BUILD_SHA,
|
|
402
|
+
'user.id': req.user?.id,
|
|
403
|
+
};
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Static values (version, region, ...) are often better modeled as OpenTelemetry [Resource](https://opentelemetry.io/docs/specs/otel/resource/sdk/) attributes; reserve `seed` for per-request derivations.
|
|
410
|
+
|
|
411
|
+
### `@WideEventField` decorator
|
|
412
|
+
|
|
413
|
+
Capture a method's return value (resolved value for async methods) onto the current wide event without calling the service manually. Works on any provider method that runs within the request's async context. A failing projection or a non-attribute value is silently skipped.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
import { WideEventField } from 'nestjs-otel';
|
|
417
|
+
|
|
418
|
+
@Injectable()
|
|
419
|
+
export class BooksService {
|
|
420
|
+
// records `books.count` = result.length
|
|
421
|
+
@WideEventField('books.count', (books: string[]) => books.length)
|
|
422
|
+
async getBooks() {
|
|
423
|
+
return ['Book 1', 'Book 2'];
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
309
428
|
## Metric Service
|
|
310
429
|
|
|
311
430
|
[OpenTelemetry Metrics](https://www.npmjs.com/package/@opentelemetry/api) allow a user to collect data and export it to metrics backend like Prometheus.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"0": "Metric Decorators & Data",
|
|
3
|
+
"1": "Span Decorator & Tests",
|
|
4
|
+
"2": "Module Bootstrap & Tracing",
|
|
5
|
+
"3": "Wide Events",
|
|
6
|
+
"4": "Traceable Decorator",
|
|
7
|
+
"5": "Counter Decorators & Metadata Utils",
|
|
8
|
+
"6": "Test Service Fixtures",
|
|
9
|
+
"7": "Metric Injection Tokens",
|
|
10
|
+
"8": "Baggage Decorator",
|
|
11
|
+
"9": "CurrentSpan Decorator"
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/Users/pragmaticivan/.local/share/mise/installs/python/3.14.6/bin/python3.14
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/Users/pragmaticivan/Code/pragmaticivan/nestjs-otel
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Graph Report - . (2026-06-15)
|
|
2
|
+
|
|
3
|
+
## Corpus Check
|
|
4
|
+
- Corpus is ~6,192 words - fits in a single context window. You may not need a graph.
|
|
5
|
+
|
|
6
|
+
## Summary
|
|
7
|
+
- 157 nodes · 286 edges · 10 communities (6 shown, 4 thin omitted)
|
|
8
|
+
- Extraction: 100% EXTRACTED · 0% INFERRED · 0% AMBIGUOUS
|
|
9
|
+
- Token cost: 0 input · 0 output
|
|
10
|
+
|
|
11
|
+
## Community Hubs (Navigation)
|
|
12
|
+
- [[_COMMUNITY_Metric Decorators & Data|Metric Decorators & Data]]
|
|
13
|
+
- [[_COMMUNITY_Span Decorator & Tests|Span Decorator & Tests]]
|
|
14
|
+
- [[_COMMUNITY_Module Bootstrap & Tracing|Module Bootstrap & Tracing]]
|
|
15
|
+
- [[_COMMUNITY_Wide Events|Wide Events]]
|
|
16
|
+
- [[_COMMUNITY_Traceable Decorator|Traceable Decorator]]
|
|
17
|
+
- [[_COMMUNITY_Counter Decorators & Metadata Utils|Counter Decorators & Metadata Utils]]
|
|
18
|
+
- [[_COMMUNITY_Test Service Fixtures|Test Service Fixtures]]
|
|
19
|
+
- [[_COMMUNITY_Metric Injection Tokens|Metric Injection Tokens]]
|
|
20
|
+
- [[_COMMUNITY_Baggage Decorator|Baggage Decorator]]
|
|
21
|
+
- [[_COMMUNITY_CurrentSpan Decorator|CurrentSpan Decorator]]
|
|
22
|
+
|
|
23
|
+
## God Nodes (most connected - your core abstractions)
|
|
24
|
+
1. `TestSpan` - 17 edges
|
|
25
|
+
2. `OtelMetricOptions` - 12 edges
|
|
26
|
+
3. `OpenTelemetryModuleOptions` - 9 edges
|
|
27
|
+
4. `MetricService` - 9 edges
|
|
28
|
+
5. `getOrCreate()` - 8 edges
|
|
29
|
+
6. `OpenTelemetryCoreModule` - 8 edges
|
|
30
|
+
7. `WideEventService` - 8 edges
|
|
31
|
+
8. `OpenTelemetryModuleAsyncOptions` - 7 edges
|
|
32
|
+
9. `TestService` - 7 edges
|
|
33
|
+
10. `getWideEventBag()` - 7 edges
|
|
34
|
+
|
|
35
|
+
## Surprising Connections (you probably didn't know these)
|
|
36
|
+
- `InjectMetric()` --calls--> `getToken()` [EXTRACTED]
|
|
37
|
+
src/metrics/injector.ts → src/metrics/utils.ts
|
|
38
|
+
- `record()` --calls--> `getWideEventBag()` [EXTRACTED]
|
|
39
|
+
src/wide-events/wide-event-field.decorator.ts → src/wide-events/wide-event.context.ts
|
|
40
|
+
|
|
41
|
+
## Import Cycles
|
|
42
|
+
- None detected.
|
|
43
|
+
|
|
44
|
+
## Communities (10 total, 4 thin omitted)
|
|
45
|
+
|
|
46
|
+
### Community 0 - "Metric Decorators & Data"
|
|
47
|
+
Cohesion: 0.14
|
|
48
|
+
Nodes (21): MetricParamDecorator, OtelCounter, OtelGauge, OtelHistogram, OtelObservableCounter, OtelObservableGauge, OtelObservableUpDownCounter, OtelUpDownCounter (+13 more)
|
|
49
|
+
|
|
50
|
+
### Community 1 - "Span Decorator & Tests"
|
|
51
|
+
Cohesion: 0.08
|
|
52
|
+
Nodes (10): ExtendedSpanOptions, handleOnResult(), recordException(), Span(), SpanDecoratorOptions, LazyThenable, makeFailingLazyThenable(), makeLazyThenable() (+2 more)
|
|
53
|
+
|
|
54
|
+
### Community 2 - "Module Bootstrap & Tracing"
|
|
55
|
+
Cohesion: 0.15
|
|
56
|
+
Nodes (8): OpenTelemetryMetrics, OpenTelemetryModuleAsyncOptions, OpenTelemetryModuleOptions, OpenTelemetryOptionsFactory, OpenTelemetryWideEvents, OpenTelemetryCoreModule, OpenTelemetryModule, TraceService
|
|
57
|
+
|
|
58
|
+
### Community 3 - "Wide Events"
|
|
59
|
+
Cohesion: 0.13
|
|
60
|
+
Nodes (10): getWideEventBag(), WIDE_EVENT_CONTEXT_KEY, WideEventBag, isAttributeValue(), record(), WideEventField(), CatsController, executionContext (+2 more)
|
|
61
|
+
|
|
62
|
+
### Community 4 - "Traceable Decorator"
|
|
63
|
+
Cohesion: 0.22
|
|
64
|
+
Nodes (3): TestTraceable, TestTraceableWithOptions, Traceable()
|
|
65
|
+
|
|
66
|
+
### Community 5 - "Counter Decorators & Metadata Utils"
|
|
67
|
+
Cohesion: 0.27
|
|
68
|
+
Nodes (4): OtelInstanceCounter(), OtelMethodCounter(), TestClass, copyMetadataFromFunctionToFunction()
|
|
69
|
+
|
|
70
|
+
## Knowledge Gaps
|
|
71
|
+
- **20 isolated node(s):** `OpenTelemetryMetrics`, `OpenTelemetryWideEvents`, `MetricParamDecorator`, `OtelCounter`, `OtelUpDownCounter` (+15 more)
|
|
72
|
+
These have ≤1 connection - possible missing edges or undocumented components.
|
|
73
|
+
- **4 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
|
74
|
+
|
|
75
|
+
## Suggested Questions
|
|
76
|
+
_Questions this graph is uniquely positioned to answer:_
|
|
77
|
+
|
|
78
|
+
- **Why does `TestService` connect `Test Service Fixtures` to `Wide Events`?**
|
|
79
|
+
_High betweenness centrality (0.076) - this node is a cross-community bridge._
|
|
80
|
+
- **What connects `OpenTelemetryMetrics`, `OpenTelemetryWideEvents`, `MetricParamDecorator` to the rest of the system?**
|
|
81
|
+
_20 weakly-connected nodes found - possible documentation gaps or missing edges._
|
|
82
|
+
- **Should `Metric Decorators & Data` be split into smaller, more focused modules?**
|
|
83
|
+
_Cohesion score 0.13636363636363635 - nodes in this community are weakly interconnected._
|
|
84
|
+
- **Should `Span Decorator & Tests` be split into smaller, more focused modules?**
|
|
85
|
+
_Cohesion score 0.08374384236453201 - nodes in this community are weakly interconnected._
|
|
86
|
+
- **Should `Module Bootstrap & Tracing` be split into smaller, more focused modules?**
|
|
87
|
+
_Cohesion score 0.14814814814814814 - nodes in this community are weakly interconnected._
|
|
88
|
+
- **Should `Wide Events` be split into smaller, more focused modules?**
|
|
89
|
+
_Cohesion score 0.1282051282051282 - nodes in this community are weakly interconnected._
|