@breadstone/archipel-mcp 0.0.10 → 0.0.11
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/data/guides/ai-text-generation.md +361 -0
- package/data/guides/analytics-and-error-tracking.md +189 -0
- package/data/guides/authentication-and-authorization.md +657 -0
- package/data/guides/blob-storage.md +242 -0
- package/data/guides/caching.md +255 -0
- package/data/guides/cryptography-and-otp.md +240 -0
- package/data/guides/document-generation.md +174 -0
- package/data/guides/email-delivery.md +196 -0
- package/data/guides/esigning-integration.md +231 -0
- package/data/guides/getting-started.md +351 -0
- package/data/guides/implementing-ports.md +317 -0
- package/data/guides/index.md +61 -0
- package/data/guides/mcp-server.md +222 -0
- package/data/guides/openapi-and-feature-discovery.md +266 -0
- package/data/guides/payments-and-feature-gating.md +244 -0
- package/data/guides/resource-management.md +352 -0
- package/data/guides/telemetry-and-observability.md +190 -0
- package/data/guides/testing.md +319 -0
- package/data/guides/tsdoc-guidelines.md +45 -0
- package/data/packages/platform-openapi/api/Class.SwaggerFeatureDiscovery.md +10 -6
- package/package.json +1 -1
- package/src/GuidesLoader.d.ts +13 -0
- package/src/GuidesLoader.js +81 -0
- package/src/main.js +36 -198
- package/src/models/IGuideDoc.d.ts +15 -0
- package/src/models/IGuideDoc.js +3 -0
- package/src/tools/registerGetConfigPatternTool.d.ts +5 -0
- package/src/tools/registerGetConfigPatternTool.js +15 -0
- package/src/tools/registerGetDtoPatternTool.d.ts +5 -0
- package/src/tools/registerGetDtoPatternTool.js +15 -0
- package/src/tools/registerGetErrorHandlingPatternTool.d.ts +5 -0
- package/src/tools/registerGetErrorHandlingPatternTool.js +15 -0
- package/src/tools/registerGetGuardPatternTool.d.ts +5 -0
- package/src/tools/registerGetGuardPatternTool.js +15 -0
- package/src/tools/registerGetGuideTool.d.ts +6 -0
- package/src/tools/registerGetGuideTool.js +32 -0
- package/src/tools/registerGetMappingPatternTool.d.ts +5 -0
- package/src/tools/registerGetMappingPatternTool.js +34 -0
- package/src/tools/registerGetModulePatternTool.d.ts +5 -0
- package/src/tools/registerGetModulePatternTool.js +29 -0
- package/src/tools/registerGetPackageDocTool.d.ts +6 -0
- package/src/tools/registerGetPackageDocTool.js +43 -0
- package/src/tools/registerGetQueryPatternTool.d.ts +5 -0
- package/src/tools/registerGetQueryPatternTool.js +29 -0
- package/src/tools/registerGetRepositoryPatternTool.d.ts +5 -0
- package/src/tools/registerGetRepositoryPatternTool.js +29 -0
- package/src/tools/registerGetTestingPatternTool.d.ts +5 -0
- package/src/tools/registerGetTestingPatternTool.js +15 -0
- package/src/tools/registerListGuidesTool.d.ts +6 -0
- package/src/tools/registerListGuidesTool.js +22 -0
- package/src/tools/registerListPackagesTool.d.ts +6 -0
- package/src/tools/registerListPackagesTool.js +20 -0
- package/src/tools/registerSearchDocsTool.d.ts +6 -0
- package/src/tools/registerSearchDocsTool.js +35 -0
- package/src/tools/registerSearchGuidesTool.d.ts +6 -0
- package/src/tools/registerSearchGuidesTool.js +28 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Resource Management
|
|
3
|
+
description: Register and load files (templates, assets, configs) from disk, blob storage, or memory using the strategy-based ResourceManager.
|
|
4
|
+
order: 17
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Resource Management
|
|
8
|
+
|
|
9
|
+
This guide covers working with `ResourceManager` from `platform-core`: registering file strategies, loading resources at runtime, and using the built-in caching layer. If your application ships email templates, HTML pages, CSS/JS assets, or any other file-based content, this is how you make it available to services.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
`ResourceManager` is part of `platform-core` — no extra package needed.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add @breadstone/archipel-platform-core
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Overview: Strategy Pattern
|
|
24
|
+
|
|
25
|
+
`ResourceManager` does not load files directly. It delegates to one or more **strategies**, tried in priority order. The first strategy that can resolve the key wins.
|
|
26
|
+
|
|
27
|
+
| Strategy | Source | Sync | Async | When to use |
|
|
28
|
+
| -------------------------- | ------------------ | ---- | ----- | -------------------------------------- |
|
|
29
|
+
| `FileResourceStrategy` | Local filesystem | Yes | Yes | Templates, assets bundled with the app |
|
|
30
|
+
| `BlobResourceStrategy` | Cloud blob storage | No | Yes | User-uploaded templates, dynamic files |
|
|
31
|
+
| `EmbeddedResourceStrategy` | In-memory map | Yes | Yes | Fallback content, test fixtures |
|
|
32
|
+
|
|
33
|
+
Strategies are evaluated in the order you provide them. A typical setup:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
FileResourceStrategy → BlobResourceStrategy → EmbeddedResourceStrategy
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If the file exists on disk, it's served immediately. If not, blob storage is checked. If that also misses, the embedded fallback is returned. If nothing matches, a `ResourceNotFoundError` is thrown.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Module Registration
|
|
44
|
+
|
|
45
|
+
`ResourceModule` is a global module. Register it once in your root module with `forRoot()`:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Module } from '@nestjs/common';
|
|
49
|
+
import { join } from 'node:path';
|
|
50
|
+
import { ResourceModule, FileResourceStrategy, EmbeddedResourceStrategy } from '@breadstone/archipel-platform-core';
|
|
51
|
+
|
|
52
|
+
@Module({
|
|
53
|
+
imports: [
|
|
54
|
+
ResourceModule.forRoot({
|
|
55
|
+
strategies: [
|
|
56
|
+
new FileResourceStrategy({
|
|
57
|
+
basePaths: [
|
|
58
|
+
join(__dirname, 'assets'),
|
|
59
|
+
join(__dirname, '..', 'node_modules', '@breadstone', 'archipel-platform-core', 'assets'),
|
|
60
|
+
join(__dirname, '..', 'node_modules', '@breadstone', 'archipel-platform-openapi', 'assets'),
|
|
61
|
+
join(__dirname, '..', 'node_modules', '@breadstone', 'archipel-platform-mailing', 'assets'),
|
|
62
|
+
],
|
|
63
|
+
includeSubfolders: true,
|
|
64
|
+
}),
|
|
65
|
+
new EmbeddedResourceStrategy({
|
|
66
|
+
'fallback.html': '<html><body>Service unavailable</body></html>',
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
debug: false,
|
|
70
|
+
}),
|
|
71
|
+
],
|
|
72
|
+
})
|
|
73
|
+
export class AppModule {}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Configuration Options
|
|
77
|
+
|
|
78
|
+
| Option | Type | Default | Description |
|
|
79
|
+
| ------------ | ---------------------------------------- | ------- | ------------------------------------------------ |
|
|
80
|
+
| `strategies` | `IResourceStrategy[]` | — | Strategies in priority order. Required. |
|
|
81
|
+
| `cache` | `ILayeredCache<string, IResourceResult>` | — | Optional cache instance from `platform-caching`. |
|
|
82
|
+
| `cacheTtl` | `number` (seconds) | `3600` | TTL for cached resources. |
|
|
83
|
+
| `debug` | `boolean` | `false` | Log all available resources on startup. |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Loading Resources
|
|
88
|
+
|
|
89
|
+
Inject `ResourceManager` and call its load methods. Every method has a `try*` variant that returns `undefined` instead of throwing.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { Injectable } from '@nestjs/common';
|
|
93
|
+
import { ResourceManager } from '@breadstone/archipel-platform-core';
|
|
94
|
+
|
|
95
|
+
@Injectable()
|
|
96
|
+
export class InvoiceService {
|
|
97
|
+
private readonly _resourceManager: ResourceManager;
|
|
98
|
+
|
|
99
|
+
constructor(resourceManager: ResourceManager) {
|
|
100
|
+
this._resourceManager = resourceManager;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public async generateInvoice(): Promise<string> {
|
|
104
|
+
// Load an HTML template as string
|
|
105
|
+
const template = await this._resourceManager.loadAsStringAsync('invoice-template.html');
|
|
106
|
+
|
|
107
|
+
// ... fill template with data
|
|
108
|
+
return template;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Method Reference
|
|
114
|
+
|
|
115
|
+
| Method | Returns | Throws on miss | Notes |
|
|
116
|
+
| ------------------------- | --------------------------------------- | -------------- | ----------------------------- |
|
|
117
|
+
| `load(key)` | `IResourceResult` | Yes | Sync |
|
|
118
|
+
| `tryLoad(key)` | `IResourceResult \| undefined` | No | Sync |
|
|
119
|
+
| `loadAsync(key)` | `Promise<IResourceResult>` | Yes | Required for blob strategy |
|
|
120
|
+
| `tryLoadAsync(key)` | `Promise<IResourceResult \| undefined>` | No | |
|
|
121
|
+
| `loadAsString(key, enc?)` | `string` | Yes | Defaults to `utf-8` |
|
|
122
|
+
| `loadAsStringAsync(key)` | `Promise<string>` | Yes | |
|
|
123
|
+
| `loadAsBuffer(key)` | `Buffer \| undefined` | No | |
|
|
124
|
+
| `loadAsBufferAsync(key)` | `Promise<Buffer \| undefined>` | No | |
|
|
125
|
+
| `exists(key)` | `boolean` | — | Sync |
|
|
126
|
+
| `existsAsync(key)` | `Promise<boolean>` | — | |
|
|
127
|
+
| `invalidate(key)` | `void` | — | Clears cache for key |
|
|
128
|
+
| `invalidateAsync(key)` | `Promise<void>` | — | |
|
|
129
|
+
| `whatDoIHave()` | `void` | — | Logs all resources to console |
|
|
130
|
+
|
|
131
|
+
### The `IResourceResult` Object
|
|
132
|
+
|
|
133
|
+
When you use the full `load()` / `tryLoad()` methods you get rich metadata alongside the content:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
interface IResourceResult {
|
|
137
|
+
content: Buffer;
|
|
138
|
+
metadata: IResourceMetadata;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface IResourceMetadata {
|
|
142
|
+
key: string; // Resource identifier you requested
|
|
143
|
+
path: string; // Resolved file / blob path
|
|
144
|
+
mimeType: string; // e.g. 'text/html', 'application/pdf'
|
|
145
|
+
size: number; // Size in bytes
|
|
146
|
+
encoding?: string; // e.g. 'utf-8'
|
|
147
|
+
source: string; // Strategy name that resolved it (e.g. 'file')
|
|
148
|
+
cachedAt?: Date; // Present when served from cache
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Strategy Details
|
|
155
|
+
|
|
156
|
+
### FileResourceStrategy
|
|
157
|
+
|
|
158
|
+
Searches one or more base paths on the filesystem. Each path is tried in order. If `includeSubfolders` is enabled, a recursive glob search runs as fallback when the direct lookup misses.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
new FileResourceStrategy({
|
|
162
|
+
basePaths: [join(__dirname, 'assets'), join(__dirname, 'templates')],
|
|
163
|
+
includeSubfolders: true,
|
|
164
|
+
defaultEncoding: 'utf-8',
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The key you pass to `load()` is the **filename** (e.g. `'invoice-template.html'`). The strategy joins it with each base path and checks if the file exists.
|
|
169
|
+
|
|
170
|
+
### BlobResourceStrategy
|
|
171
|
+
|
|
172
|
+
Loads from cloud blob storage via a minimal `IBlobServiceAdapter` interface. This is **async-only** — calling `load()` (sync) will throw.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { BlobResourceStrategy, IBlobServiceAdapter } from '@breadstone/archipel-platform-core';
|
|
176
|
+
|
|
177
|
+
const blobAdapter: IBlobServiceAdapter = {
|
|
178
|
+
async downloadFile(key: string) {
|
|
179
|
+
// Your blob storage client logic here
|
|
180
|
+
return { data: buffer, contentType: 'text/html' };
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
new BlobResourceStrategy(blobAdapter, {
|
|
185
|
+
keyPrefix: 'templates/',
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
With `keyPrefix: 'templates/'`, a call to `loadAsync('invoice.html')` resolves to the blob key `templates/invoice.html`.
|
|
190
|
+
|
|
191
|
+
### EmbeddedResourceStrategy
|
|
192
|
+
|
|
193
|
+
Stores resources as plain strings in memory. Useful for fallback content or test fixtures.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
new EmbeddedResourceStrategy({
|
|
197
|
+
'maintenance.html': '<h1>We are down for maintenance</h1>',
|
|
198
|
+
'default-logo.svg': '<svg>...</svg>',
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
You can also register resources dynamically after construction:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const embedded = new EmbeddedResourceStrategy();
|
|
206
|
+
embedded.register('dynamic-content.txt', 'Hello World');
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Real-World Examples
|
|
212
|
+
|
|
213
|
+
### Email Templates
|
|
214
|
+
|
|
215
|
+
`platform-mailing` uses `ResourceManager` to load HTML email templates:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// In MailModule.ts — factory creates the strategy
|
|
219
|
+
ResourceModule.forRoot({
|
|
220
|
+
strategies: [
|
|
221
|
+
new FileResourceStrategy({
|
|
222
|
+
basePaths: [
|
|
223
|
+
join(__dirname, 'assets'), // App-level overrides
|
|
224
|
+
join(__dirname, '..', 'node_modules', '@breadstone', 'archipel-platform-mailing', 'assets'),
|
|
225
|
+
],
|
|
226
|
+
}),
|
|
227
|
+
],
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Templates like `AuthVerify.html`, `AuthRegister.html`, and `AuthForgotPassword.html` are loaded by key:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
const template = await this._resourceManager.loadAsStringAsync('AuthVerify.html');
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
By listing your own `assets/` first, you can override built-in templates without modifying the library.
|
|
238
|
+
|
|
239
|
+
### Swagger UI Assets
|
|
240
|
+
|
|
241
|
+
`platform-openapi` loads its theme files (`swagger.css`, `swagger.js`, `swagger.html`) through the same mechanism:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
const css = this._resourceManager.loadAsString('swagger.css');
|
|
245
|
+
const js = this._resourceManager.loadAsString('swagger.js');
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Application Index Page
|
|
249
|
+
|
|
250
|
+
`platform-core`'s `HostService` loads `index.html` as a template for the root route:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const html = await this._resourceManager.loadAsStringAsync('index.html');
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Caching
|
|
259
|
+
|
|
260
|
+
Pass a cache instance from `platform-caching` to avoid repeated file reads or blob downloads:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { LayeredCacheFactory } from '@breadstone/archipel-platform-caching';
|
|
264
|
+
|
|
265
|
+
ResourceModule.forRoot({
|
|
266
|
+
strategies: [
|
|
267
|
+
new FileResourceStrategy({ basePaths: [...] }),
|
|
268
|
+
],
|
|
269
|
+
cache: LayeredCacheFactory.create<string, IResourceResult>({
|
|
270
|
+
maxSize: 100,
|
|
271
|
+
}),
|
|
272
|
+
cacheTtl: 1800, // 30 minutes
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
- On load: cache is checked first. On hit, the resource is returned immediately.
|
|
277
|
+
- On miss: strategies are tried, and the result is cached for future requests.
|
|
278
|
+
- Use `invalidate(key)` or `invalidateAsync(key)` to clear a cached resource (e.g. after an upload replaces a template).
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Debugging
|
|
283
|
+
|
|
284
|
+
Enable `debug: true` in the module config to have `ResourceManager` call `whatDoIHave()` at startup. This logs every resource available through every strategy — helpful when a resource isn't found and you need to verify the base paths.
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
[ResourceManager] ResourceManager initialized with 2 strategies: file, embedded
|
|
288
|
+
[FileResourceStrategy] Available resources:
|
|
289
|
+
- index.html (text/html, 2.4 KB) → /app/dist/assets/index.html
|
|
290
|
+
- swagger.css (text/css, 1.1 KB) → /app/dist/assets/swagger.css
|
|
291
|
+
...
|
|
292
|
+
[EmbeddedResourceStrategy] Available resources:
|
|
293
|
+
- fallback.html (text/html, 52 B) → embedded
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Writing a Custom Strategy
|
|
299
|
+
|
|
300
|
+
Implement `IResourceStrategy` to support a new source (e.g. a database, S3 directly, or a remote API):
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { IResourceStrategy, IResourceResult } from '@breadstone/archipel-platform-core';
|
|
304
|
+
|
|
305
|
+
export class DatabaseResourceStrategy implements IResourceStrategy {
|
|
306
|
+
public get name(): string {
|
|
307
|
+
return 'database';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public load(key: string): IResourceResult | undefined {
|
|
311
|
+
// Sync lookup — return undefined if not found
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public async loadAsync(key: string): Promise<IResourceResult | undefined> {
|
|
315
|
+
// Async lookup — return undefined if not found
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
public exists(key: string): boolean {
|
|
319
|
+
// ...
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public async existsAsync(key: string): Promise<boolean> {
|
|
323
|
+
// ...
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public whatDoIHave(): void {
|
|
327
|
+
// Log available resources for debugging
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Then add it to the strategies array:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
ResourceModule.forRoot({
|
|
336
|
+
strategies: [
|
|
337
|
+
new FileResourceStrategy({ basePaths: [...] }),
|
|
338
|
+
new DatabaseResourceStrategy(prisma),
|
|
339
|
+
],
|
|
340
|
+
})
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Checklist
|
|
346
|
+
|
|
347
|
+
- [ ] `ResourceModule.forRoot()` registered in the root module
|
|
348
|
+
- [ ] Base paths include library asset directories for all used packages
|
|
349
|
+
- [ ] App-level overrides listed **before** library paths in `basePaths`
|
|
350
|
+
- [ ] Async methods used when `BlobResourceStrategy` is in the chain
|
|
351
|
+
- [ ] Cache configured for production (avoids repeated disk/network reads)
|
|
352
|
+
- [ ] `debug: true` used during development to verify resource availability
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Telemetry & Observability
|
|
3
|
+
description: Add OpenTelemetry-based metrics, tracing, and structured logging to your NestJS application.
|
|
4
|
+
order: 10
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Telemetry & Observability
|
|
8
|
+
|
|
9
|
+
This guide covers adding observability to your application with `platform-telemetry`: setup, metrics recording, distributed tracing, structured logging, and graceful shutdown.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
yarn add @breadstone/archipel-platform-telemetry
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Module Registration
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Module } from '@nestjs/common';
|
|
25
|
+
import { TelemetryModule } from '@breadstone/archipel-platform-telemetry';
|
|
26
|
+
|
|
27
|
+
@Module({
|
|
28
|
+
imports: [
|
|
29
|
+
TelemetryModule.register({
|
|
30
|
+
enabled: true,
|
|
31
|
+
interceptor: {
|
|
32
|
+
operation: true, // auto-instrument controller operations
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
export class AppModule {}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
When `enabled` is `false`, the module provides a no-op facade (`NoopTelemetryFacade`) that silently discards all telemetry calls. This means you can instrument your code once and toggle telemetry via configuration.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
```env
|
|
47
|
+
TELEMETRY_ENABLED=true
|
|
48
|
+
TELEMETRY_SERVICE_NAME=my-api
|
|
49
|
+
TELEMETRY_EXPORTER_ENDPOINT=https://otel-collector.example.com:4318
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Recording Metrics
|
|
55
|
+
|
|
56
|
+
Use `TelemetryFacade` to record application metrics:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { Injectable } from '@nestjs/common';
|
|
60
|
+
import { TelemetryFacade } from '@breadstone/archipel-platform-telemetry';
|
|
61
|
+
|
|
62
|
+
@Injectable()
|
|
63
|
+
export class OrderService {
|
|
64
|
+
private readonly _telemetry: TelemetryFacade;
|
|
65
|
+
|
|
66
|
+
constructor(telemetry: TelemetryFacade) {
|
|
67
|
+
this._telemetry = telemetry;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public async createOrder(userId: string): Promise<void> {
|
|
71
|
+
const start = Date.now();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// ... business logic
|
|
75
|
+
|
|
76
|
+
this._telemetry.recordCounter('domain_command_total', 1, {
|
|
77
|
+
command: 'create_order',
|
|
78
|
+
status: 'success',
|
|
79
|
+
});
|
|
80
|
+
} catch (error) {
|
|
81
|
+
this._telemetry.recordCounter('domain_command_total', 1, {
|
|
82
|
+
command: 'create_order',
|
|
83
|
+
status: 'failure',
|
|
84
|
+
});
|
|
85
|
+
throw error;
|
|
86
|
+
} finally {
|
|
87
|
+
this._telemetry.recordHistogram('order_processing_duration_ms', Date.now() - start, {
|
|
88
|
+
command: 'create_order',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Recommended Baseline Metrics
|
|
96
|
+
|
|
97
|
+
| Metric | Type | Labels |
|
|
98
|
+
| ----------------------------------------- | --------- | ----------------------------- |
|
|
99
|
+
| `db_query_duration_ms` | Histogram | `model`, `operation` |
|
|
100
|
+
| `cache_hits_total` / `cache_misses_total` | Counter | `cache` |
|
|
101
|
+
| `domain_command_total` | Counter | `command`, `status` |
|
|
102
|
+
| `external_http_request_duration_ms` | Histogram | `service`, `action`, `status` |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Structured Logging
|
|
107
|
+
|
|
108
|
+
`TelemetryLoggerService` provides structured logging with automatic correlation:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { Injectable } from '@nestjs/common';
|
|
112
|
+
import { TelemetryLoggerService } from '@breadstone/archipel-platform-telemetry';
|
|
113
|
+
|
|
114
|
+
@Injectable()
|
|
115
|
+
export class PaymentService {
|
|
116
|
+
private readonly _logger: TelemetryLoggerService;
|
|
117
|
+
|
|
118
|
+
constructor(logger: TelemetryLoggerService) {
|
|
119
|
+
this._logger = logger;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async processPayment(orderId: string): Promise<void> {
|
|
123
|
+
this._logger.log('Processing payment', { orderId });
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
// ... payment logic
|
|
127
|
+
this._logger.log('Payment processed successfully', { orderId });
|
|
128
|
+
} catch (error) {
|
|
129
|
+
this._logger.error('Payment processing failed', { orderId, error });
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
All log entries automatically include `requestId` for request-level correlation.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Automatic Operation Instrumentation
|
|
141
|
+
|
|
142
|
+
When you set `interceptor.operation: true`, every controller method is automatically traced. The interceptor records:
|
|
143
|
+
|
|
144
|
+
- Operation name (controller + method)
|
|
145
|
+
- Duration
|
|
146
|
+
- HTTP status code
|
|
147
|
+
- Error details on failure
|
|
148
|
+
|
|
149
|
+
This gives you endpoint-level performance visibility without manual instrumentation.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Rule Engine
|
|
154
|
+
|
|
155
|
+
`TelemetryRuleEngine` lets you configure sampling and filtering rules:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
TelemetryModule.register({
|
|
159
|
+
enabled: true,
|
|
160
|
+
interceptor: { operation: true },
|
|
161
|
+
rules: [
|
|
162
|
+
{ pattern: '/health', action: 'drop' }, // Don't trace health checks
|
|
163
|
+
{ pattern: '/api/v1/**', action: 'sample', rate: 0.1 }, // Sample 10% of API traffic
|
|
164
|
+
],
|
|
165
|
+
}),
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This prevents noisy endpoints (health checks, readiness probes) from overwhelming your telemetry backend.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Graceful Shutdown
|
|
173
|
+
|
|
174
|
+
The module registers a shutdown hook that flushes all pending telemetry data before the process exits. This ensures you don't lose metrics or traces during deployments or scaling events.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Development Tips
|
|
179
|
+
|
|
180
|
+
- Set `TELEMETRY_ENABLED=false` in local development to avoid telemetry overhead.
|
|
181
|
+
- Use the `log` exporter during development to see traces in the console.
|
|
182
|
+
- Add metrics incrementally — start with the baseline metrics and expand as you identify bottlenecks.
|
|
183
|
+
- Include `requestId` in all log entries. The telemetry module handles this automatically for HTTP requests.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Next Steps
|
|
188
|
+
|
|
189
|
+
- Browse the [platform-telemetry API reference](/packages/platform-telemetry/api/) for complete method signatures
|
|
190
|
+
- See the [Testing](/guides/testing) guide for verifying telemetry calls in unit tests
|