@kabran-tecnologia/kabran-config 1.6.0 → 1.8.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/README.md +283 -0
- package/package.json +63 -8
- package/src/schemas/ci-result.v2.schema.json +125 -0
- package/src/scripts/ci/ci-core.sh +131 -1
- package/src/scripts/ci/ci-runner.sh +88 -0
- package/src/scripts/ci-result-history.mjs +245 -0
- package/src/scripts/ci-result-trends.mjs +296 -0
- package/src/scripts/ci-result-utils.mjs +104 -0
- package/src/scripts/generate-ci-result.mjs +92 -11
- package/src/scripts/pr-quality-comment.mjs +36 -0
- package/src/scripts/setup.mjs +91 -4
- package/src/telemetry/README.md +407 -0
- package/src/telemetry/config/defaults.mjs +421 -0
- package/src/telemetry/config/index.mjs +132 -0
- package/src/telemetry/edge/index.mjs +446 -0
- package/src/telemetry/frontend/index.mjs +366 -0
- package/src/telemetry/logger/index.mjs +236 -0
- package/src/telemetry/node/index.mjs +386 -0
- package/src/telemetry/shared/helpers.mjs +133 -0
- package/src/telemetry/shared/index.mjs +15 -0
- package/src/telemetry/shared/types.d.ts +123 -0
- package/templates/telemetry/.env.telemetry.example +118 -0
package/src/scripts/setup.mjs
CHANGED
|
@@ -79,6 +79,7 @@ export function parseArgs(args) {
|
|
|
79
79
|
skipQualityStandard: false,
|
|
80
80
|
syncWorkflows: false,
|
|
81
81
|
syncHusky: false,
|
|
82
|
+
telemetryEnv: false,
|
|
82
83
|
force: false,
|
|
83
84
|
dryRun: false,
|
|
84
85
|
help: false,
|
|
@@ -97,6 +98,8 @@ export function parseArgs(args) {
|
|
|
97
98
|
options.syncWorkflows = true;
|
|
98
99
|
} else if (arg === '--sync-husky') {
|
|
99
100
|
options.syncHusky = true;
|
|
101
|
+
} else if (arg === '--telemetry-env') {
|
|
102
|
+
options.telemetryEnv = true;
|
|
100
103
|
} else if (arg === '--force') {
|
|
101
104
|
options.force = true;
|
|
102
105
|
} else if (arg === '--dry-run') {
|
|
@@ -132,6 +135,7 @@ ${colors.yellow}OPTIONS:${colors.reset}
|
|
|
132
135
|
--skip-quality-standard Don't create quality-standard.md
|
|
133
136
|
--sync-workflows Overwrite existing workflow files
|
|
134
137
|
--sync-husky Overwrite existing husky hooks
|
|
138
|
+
--telemetry-env Generate .env.example with telemetry variables
|
|
135
139
|
--force Overwrite all existing files
|
|
136
140
|
--dry-run Preview changes without modifying files
|
|
137
141
|
--help, -h Show this help message
|
|
@@ -146,6 +150,9 @@ ${colors.yellow}EXAMPLES:${colors.reset}
|
|
|
146
150
|
# Update workflows only
|
|
147
151
|
npx kabran-setup --sync-workflows
|
|
148
152
|
|
|
153
|
+
# Generate telemetry .env.example
|
|
154
|
+
npx kabran-setup --telemetry-env
|
|
155
|
+
|
|
149
156
|
# Preview changes without modifying
|
|
150
157
|
npx kabran-setup --dry-run
|
|
151
158
|
|
|
@@ -547,6 +554,79 @@ export function setupQualityStandard(projectDir, templatesDir, options) {
|
|
|
547
554
|
return results;
|
|
548
555
|
}
|
|
549
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Setup telemetry .env.example
|
|
559
|
+
* @param {string} projectDir - Project directory
|
|
560
|
+
* @param {string} templatesDir - Templates directory
|
|
561
|
+
* @param {object} options - Setup options
|
|
562
|
+
* @returns {object} Results
|
|
563
|
+
*/
|
|
564
|
+
export function setupTelemetryEnv(projectDir, templatesDir, options) {
|
|
565
|
+
const {force = false, dryRun = false} = options;
|
|
566
|
+
|
|
567
|
+
const results = {
|
|
568
|
+
created: 0,
|
|
569
|
+
overwritten: 0,
|
|
570
|
+
skipped: 0,
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
logInfo('Setting up telemetry .env.example...');
|
|
574
|
+
|
|
575
|
+
const src = join(templatesDir, 'telemetry', '.env.telemetry.example');
|
|
576
|
+
const dest = join(projectDir, '.env.example');
|
|
577
|
+
|
|
578
|
+
// Check if source template exists
|
|
579
|
+
if (!existsSync(src)) {
|
|
580
|
+
logWarn('Template not found: templates/telemetry/.env.telemetry.example');
|
|
581
|
+
return results;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Check if destination exists
|
|
585
|
+
const destExists = existsSync(dest);
|
|
586
|
+
|
|
587
|
+
if (destExists && !force) {
|
|
588
|
+
// If .env.example exists, append telemetry section if not present
|
|
589
|
+
const existingContent = readFileSync(dest, 'utf-8');
|
|
590
|
+
|
|
591
|
+
if (existingContent.includes('Kabran Telemetry Configuration')) {
|
|
592
|
+
if (dryRun) {
|
|
593
|
+
logDry('Would skip .env.example (telemetry section already present)');
|
|
594
|
+
} else {
|
|
595
|
+
logSkip('.env.example (telemetry section already present)');
|
|
596
|
+
}
|
|
597
|
+
results.skipped = 1;
|
|
598
|
+
return results;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Append telemetry section
|
|
602
|
+
const telemetryContent = readFileSync(src, 'utf-8');
|
|
603
|
+
|
|
604
|
+
if (dryRun) {
|
|
605
|
+
logDry('Would append telemetry section to .env.example');
|
|
606
|
+
results.overwritten = 1;
|
|
607
|
+
return results;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const newContent = existingContent.trimEnd() + '\n\n' + telemetryContent;
|
|
611
|
+
writeFileSync(dest, newContent, 'utf-8');
|
|
612
|
+
logSuccess('Appended telemetry section to: .env.example');
|
|
613
|
+
results.overwritten = 1;
|
|
614
|
+
return results;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const status = copyFile(src, dest, {overwrite: force, dryRun});
|
|
618
|
+
|
|
619
|
+
if (status === 'created' || status === 'would_create') {
|
|
620
|
+
results.created = 1;
|
|
621
|
+
} else if (status === 'overwritten' || status === 'would_overwrite') {
|
|
622
|
+
results.overwritten = 1;
|
|
623
|
+
} else {
|
|
624
|
+
results.skipped = 1;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
return results;
|
|
628
|
+
}
|
|
629
|
+
|
|
550
630
|
/**
|
|
551
631
|
* Run setup
|
|
552
632
|
* @param {string} projectDir - Project directory
|
|
@@ -561,6 +641,7 @@ export function runSetup(projectDir, options) {
|
|
|
561
641
|
husky: {created: 0, overwritten: 0, skipped: 0},
|
|
562
642
|
configs: {created: 0, overwritten: 0, skipped: 0},
|
|
563
643
|
qualityStandard: {created: 0, overwritten: 0, skipped: 0},
|
|
644
|
+
telemetryEnv: {created: 0, overwritten: 0, skipped: 0},
|
|
564
645
|
};
|
|
565
646
|
|
|
566
647
|
console.log('');
|
|
@@ -592,11 +673,17 @@ export function runSetup(projectDir, options) {
|
|
|
592
673
|
}
|
|
593
674
|
|
|
594
675
|
// Setup quality-standard.md (unless skipped or in sync mode)
|
|
595
|
-
if (!options.skipQualityStandard && !isSyncMode) {
|
|
676
|
+
if (!options.skipQualityStandard && !isSyncMode && !options.telemetryEnv) {
|
|
596
677
|
summary.qualityStandard = setupQualityStandard(projectDir, templatesDir, options);
|
|
597
678
|
console.log('');
|
|
598
679
|
}
|
|
599
680
|
|
|
681
|
+
// Setup telemetry .env.example (only when explicitly requested)
|
|
682
|
+
if (options.telemetryEnv) {
|
|
683
|
+
summary.telemetryEnv = setupTelemetryEnv(projectDir, templatesDir, options);
|
|
684
|
+
console.log('');
|
|
685
|
+
}
|
|
686
|
+
|
|
600
687
|
return summary;
|
|
601
688
|
}
|
|
602
689
|
|
|
@@ -609,10 +696,10 @@ export function printSummary(summary) {
|
|
|
609
696
|
console.log(`${colors.cyan}=== Setup Summary ===${colors.reset}`);
|
|
610
697
|
|
|
611
698
|
const total = {
|
|
612
|
-
created: summary.workflows.created + summary.husky.created + summary.configs.created + summary.qualityStandard.created,
|
|
699
|
+
created: summary.workflows.created + summary.husky.created + summary.configs.created + summary.qualityStandard.created + summary.telemetryEnv.created,
|
|
613
700
|
overwritten:
|
|
614
|
-
summary.workflows.overwritten + summary.husky.overwritten + summary.configs.overwritten + summary.qualityStandard.overwritten,
|
|
615
|
-
skipped: summary.workflows.skipped + summary.husky.skipped + summary.configs.skipped + summary.qualityStandard.skipped,
|
|
701
|
+
summary.workflows.overwritten + summary.husky.overwritten + summary.configs.overwritten + summary.qualityStandard.overwritten + summary.telemetryEnv.overwritten,
|
|
702
|
+
skipped: summary.workflows.skipped + summary.husky.skipped + summary.configs.skipped + summary.qualityStandard.skipped + summary.telemetryEnv.skipped,
|
|
616
703
|
};
|
|
617
704
|
|
|
618
705
|
if (total.created > 0) {
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# @kabran-tecnologia/kabran-config/telemetry
|
|
2
|
+
|
|
3
|
+
Unified telemetry package for Kabran projects using OpenTelemetry.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-runtime support**: Node.js, Frontend (Browser), Edge/Serverless
|
|
8
|
+
- **OpenTelemetry integration**: W3C Trace Context, OTLP export
|
|
9
|
+
- **Zero-config defaults**: Works out of the box with sensible defaults
|
|
10
|
+
- **Structured logging**: Logger with automatic trace correlation
|
|
11
|
+
- **Tree-shakeable**: Import only what you need
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
The telemetry modules are included in `@kabran-tecnologia/kabran-config`. Install the package and the required OpenTelemetry peer dependencies:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install kabran-config
|
|
19
|
+
npm install @kabran-tecnologia/kabran-config
|
|
20
|
+
|
|
21
|
+
# Install required peer dependencies (pick based on your runtime)
|
|
22
|
+
|
|
23
|
+
# For Node.js:
|
|
24
|
+
npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions
|
|
25
|
+
|
|
26
|
+
# For Frontend:
|
|
27
|
+
npm install @opentelemetry/api @opentelemetry/sdk-trace-web @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/instrumentation-fetch @opentelemetry/instrumentation-document-load @opentelemetry/instrumentation-user-interaction
|
|
28
|
+
|
|
29
|
+
# For Edge/Serverless:
|
|
30
|
+
npm install @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources @opentelemetry/semantic-conventions
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Node.js (Express/Fastify)
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// instrumentation.js - Import this FIRST in your app
|
|
39
|
+
import { initTelemetry, telemetryMiddleware, shutdownTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/node'
|
|
40
|
+
|
|
41
|
+
// Initialize telemetry
|
|
42
|
+
initTelemetry({
|
|
43
|
+
serviceName: 'my-api',
|
|
44
|
+
serviceVersion: '1.0.0',
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// In your Express app
|
|
48
|
+
import express from 'express'
|
|
49
|
+
const app = express()
|
|
50
|
+
|
|
51
|
+
// Add telemetry middleware (creates spans for each request)
|
|
52
|
+
app.use(telemetryMiddleware())
|
|
53
|
+
|
|
54
|
+
app.get('/api/users', (req, res) => {
|
|
55
|
+
// Your handler - automatically traced
|
|
56
|
+
res.json({ users: [] })
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Graceful shutdown
|
|
60
|
+
process.on('SIGTERM', async () => {
|
|
61
|
+
await shutdownTelemetry()
|
|
62
|
+
process.exit(0)
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Frontend (React/Vite)
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// main.tsx
|
|
70
|
+
import { initTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/frontend'
|
|
71
|
+
|
|
72
|
+
// Initialize before rendering
|
|
73
|
+
initTelemetry({
|
|
74
|
+
serviceName: 'my-frontend',
|
|
75
|
+
serviceVersion: '1.0.0',
|
|
76
|
+
// Optional: customize which events to trace
|
|
77
|
+
instrumentation: {
|
|
78
|
+
userInteractionEvents: ['click', 'submit'],
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// Your React app renders normally
|
|
83
|
+
import { createRoot } from 'react-dom/client'
|
|
84
|
+
import App from './App'
|
|
85
|
+
|
|
86
|
+
createRoot(document.getElementById('root')!).render(<App />)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Edge/Serverless (Supabase Functions)
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// supabase/functions/my-function/index.ts
|
|
93
|
+
import { withTelemetry, traceSupabaseQuery } from '@kabran-tecnologia/kabran-config/telemetry/edge'
|
|
94
|
+
import { createClient } from '@supabase/supabase-js'
|
|
95
|
+
|
|
96
|
+
const supabase = createClient(
|
|
97
|
+
Deno.env.get('SUPABASE_URL')!,
|
|
98
|
+
Deno.env.get('SUPABASE_ANON_KEY')!
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
// Wrap your handler with telemetry
|
|
102
|
+
Deno.serve(withTelemetry(
|
|
103
|
+
{
|
|
104
|
+
serviceName: 'my-edge-function',
|
|
105
|
+
serviceVersion: '1.0.0',
|
|
106
|
+
},
|
|
107
|
+
async (req) => {
|
|
108
|
+
// Trace Supabase queries
|
|
109
|
+
const { data, error } = await traceSupabaseQuery(
|
|
110
|
+
'select-users',
|
|
111
|
+
() => supabase.from('users').select('*')
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return new Response(JSON.stringify({ data, error }), {
|
|
115
|
+
headers: { 'Content-Type': 'application/json' },
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Structured Logging
|
|
122
|
+
|
|
123
|
+
The logger automatically includes trace context in log output:
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
import { createLogger } from '@kabran-tecnologia/kabran-config/telemetry/logger'
|
|
127
|
+
|
|
128
|
+
const log = createLogger()
|
|
129
|
+
|
|
130
|
+
log.info('User logged in', { userId: '123' })
|
|
131
|
+
// Output (JSON in production):
|
|
132
|
+
// {"level":"info","message":"User logged in","userId":"123","trace_id":"abc123...","span_id":"def456...","timestamp":"2024-01-13T..."}
|
|
133
|
+
|
|
134
|
+
// Output (pretty in development):
|
|
135
|
+
// 2024-01-13T12:00:00.000Z [INFO] User logged in [trace:abc123...] {"userId":"123"}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Span-bound Logger
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
import { trace } from '@opentelemetry/api'
|
|
142
|
+
import { createSpanLogger } from '@kabran-tecnologia/kabran-config/telemetry/logger'
|
|
143
|
+
|
|
144
|
+
const span = trace.getActiveSpan()
|
|
145
|
+
const log = createSpanLogger(span)
|
|
146
|
+
|
|
147
|
+
log.info('Processing order', { orderId: '456' })
|
|
148
|
+
// Logs are also added as span events for visibility in traces
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Configuration
|
|
152
|
+
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
All configuration can be set via environment variables:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Core
|
|
159
|
+
SERVICE_NAME=my-service # Required: Your service name
|
|
160
|
+
SERVICE_VERSION=1.0.0 # Service version (default: 1.0.0)
|
|
161
|
+
ENVIRONMENT=production # Environment name (default: from NODE_ENV)
|
|
162
|
+
OTEL_NAMESPACE=kabran # Service namespace (default: kabran)
|
|
163
|
+
|
|
164
|
+
# OTLP Exporter
|
|
165
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.kabran.com.br # Collector endpoint
|
|
166
|
+
OTEL_EXPORTER_OTLP_TIMEOUT=10000 # Export timeout in ms (default: 10000)
|
|
167
|
+
|
|
168
|
+
# Sampling
|
|
169
|
+
OTEL_SAMPLE_RATE=0.1 # Sampling rate 0.0-1.0 (default: 0.1 = 10%)
|
|
170
|
+
|
|
171
|
+
# Enable/Disable
|
|
172
|
+
OTEL_ENABLED=true # Enable telemetry (default: true in production)
|
|
173
|
+
|
|
174
|
+
# Logger
|
|
175
|
+
OTEL_LOG_TRACE_ID_LENGTH=8 # Trace ID length in logs (default: 8)
|
|
176
|
+
NO_COLOR=1 # Disable ANSI colors in logs
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Programmatic Configuration
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
import { initTelemetry } from '@kabran-tecnologia/kabran-config/telemetry/node'
|
|
183
|
+
|
|
184
|
+
initTelemetry({
|
|
185
|
+
// Required
|
|
186
|
+
serviceName: 'my-service',
|
|
187
|
+
|
|
188
|
+
// Optional (all have sensible defaults)
|
|
189
|
+
serviceVersion: '1.0.0',
|
|
190
|
+
environment: 'production',
|
|
191
|
+
endpoint: 'https://otel.kabran.com.br',
|
|
192
|
+
sampleRate: 0.1,
|
|
193
|
+
enabled: true,
|
|
194
|
+
|
|
195
|
+
// Resource attributes (added to all spans)
|
|
196
|
+
resourceAttributes: {
|
|
197
|
+
'deployment.environment': 'production',
|
|
198
|
+
'service.instance.id': process.env.POD_NAME,
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
// Batch processor settings (Node.js only)
|
|
202
|
+
batchProcessor: {
|
|
203
|
+
maxQueueSize: 2048,
|
|
204
|
+
maxExportBatchSize: 512,
|
|
205
|
+
scheduledDelayMillis: 5000,
|
|
206
|
+
},
|
|
207
|
+
})
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Module Reference
|
|
211
|
+
|
|
212
|
+
### `telemetry/node`
|
|
213
|
+
|
|
214
|
+
For Node.js servers and long-running processes.
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
import {
|
|
218
|
+
initTelemetry, // Initialize the tracer
|
|
219
|
+
shutdownTelemetry, // Graceful shutdown
|
|
220
|
+
telemetryMiddleware,// Express/Fastify middleware
|
|
221
|
+
isInitialized, // Check if initialized
|
|
222
|
+
getTracer, // Get the tracer instance
|
|
223
|
+
getConfig, // Get resolved config
|
|
224
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/node'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### `telemetry/frontend`
|
|
228
|
+
|
|
229
|
+
For browser applications (React, Vue, vanilla JS).
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
import {
|
|
233
|
+
initTelemetry, // Initialize the tracer
|
|
234
|
+
shutdownTelemetry, // Flush pending spans
|
|
235
|
+
isInitialized, // Check if initialized
|
|
236
|
+
getTracer, // Get the tracer instance
|
|
237
|
+
getConfig, // Get resolved config
|
|
238
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/frontend'
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### `telemetry/edge`
|
|
242
|
+
|
|
243
|
+
For Edge Functions and serverless (Supabase, Deno Deploy, Cloudflare Workers).
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
import {
|
|
247
|
+
withTelemetry, // Handler wrapper with auto-tracing
|
|
248
|
+
traceSupabaseQuery, // Trace Supabase queries
|
|
249
|
+
shutdownTelemetry, // Flush pending spans
|
|
250
|
+
isInitialized, // Check if initialized
|
|
251
|
+
getConfig, // Get resolved config
|
|
252
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/edge'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### `telemetry/logger`
|
|
256
|
+
|
|
257
|
+
Structured logger with trace correlation.
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
import {
|
|
261
|
+
createLogger, // Create a logger instance
|
|
262
|
+
createSpanLogger, // Create a span-bound logger
|
|
263
|
+
log, // Default logger instance
|
|
264
|
+
getTraceContext, // Get current trace context
|
|
265
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/logger'
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### `telemetry/config`
|
|
269
|
+
|
|
270
|
+
Configuration utilities.
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
import {
|
|
274
|
+
defineTelemetryConfig, // Create a type-safe config
|
|
275
|
+
resolveConfig, // Resolve config with defaults and env vars
|
|
276
|
+
validateConfig, // Validate config object
|
|
277
|
+
detectEnabled, // Check if telemetry should be enabled
|
|
278
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/config'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### `telemetry/shared`
|
|
282
|
+
|
|
283
|
+
Shared utilities and types.
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
import {
|
|
287
|
+
setAttributes, // Set multiple span attributes
|
|
288
|
+
formatDuration, // Format milliseconds to human-readable
|
|
289
|
+
generateInvocationId, // Generate unique invocation ID
|
|
290
|
+
safeWarn, // Safe console.warn
|
|
291
|
+
safeLog, // Safe console.log
|
|
292
|
+
} from '@kabran-tecnologia/kabran-config/telemetry/shared'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Integration with Kosmos Observability
|
|
296
|
+
|
|
297
|
+
This package is designed to work with the Kosmos observability stack:
|
|
298
|
+
|
|
299
|
+
- **Traces** → Grafana Tempo
|
|
300
|
+
- **Logs** → Grafana Loki (via stdout/Promtail or direct export)
|
|
301
|
+
- **Metrics** → Prometheus (planned, see [GAP-006])
|
|
302
|
+
|
|
303
|
+
Default endpoint: `https://otel.kabran.com.br`
|
|
304
|
+
|
|
305
|
+
### Viewing Traces
|
|
306
|
+
|
|
307
|
+
1. Open Grafana at your Kosmos instance
|
|
308
|
+
2. Go to Explore → Select Tempo
|
|
309
|
+
3. Search by service name or trace ID
|
|
310
|
+
|
|
311
|
+
## Best Practices
|
|
312
|
+
|
|
313
|
+
### 1. Initialize Early
|
|
314
|
+
|
|
315
|
+
Initialize telemetry as early as possible in your application:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
// This should be the FIRST import
|
|
319
|
+
import './instrumentation.js'
|
|
320
|
+
|
|
321
|
+
// Then your app code
|
|
322
|
+
import express from 'express'
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 2. Use Meaningful Span Names
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
// Good
|
|
329
|
+
span.updateName('user.create')
|
|
330
|
+
span.updateName('order.process')
|
|
331
|
+
|
|
332
|
+
// Bad
|
|
333
|
+
span.updateName('handler')
|
|
334
|
+
span.updateName('function1')
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 3. Add Relevant Attributes
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
import { trace } from '@opentelemetry/api'
|
|
341
|
+
|
|
342
|
+
const span = trace.getActiveSpan()
|
|
343
|
+
span?.setAttributes({
|
|
344
|
+
'user.id': userId,
|
|
345
|
+
'order.id': orderId,
|
|
346
|
+
'order.total': total,
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 4. Handle Errors Properly
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
import { trace, SpanStatusCode } from '@opentelemetry/api'
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
// Your code
|
|
357
|
+
} catch (error) {
|
|
358
|
+
const span = trace.getActiveSpan()
|
|
359
|
+
span?.recordException(error)
|
|
360
|
+
span?.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
|
|
361
|
+
throw error
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 5. Graceful Shutdown
|
|
366
|
+
|
|
367
|
+
Always flush pending spans before shutdown:
|
|
368
|
+
|
|
369
|
+
```javascript
|
|
370
|
+
process.on('SIGTERM', async () => {
|
|
371
|
+
await shutdownTelemetry()
|
|
372
|
+
process.exit(0)
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Troubleshooting
|
|
377
|
+
|
|
378
|
+
### Traces not appearing
|
|
379
|
+
|
|
380
|
+
1. Check `OTEL_ENABLED` is not set to `false`
|
|
381
|
+
2. Verify `SERVICE_NAME` is set
|
|
382
|
+
3. Check network connectivity to the collector endpoint
|
|
383
|
+
4. Verify sampling rate (default is 10%)
|
|
384
|
+
|
|
385
|
+
### Missing trace correlation in logs
|
|
386
|
+
|
|
387
|
+
1. Ensure telemetry is initialized before logging
|
|
388
|
+
2. Check that you're within an active span context
|
|
389
|
+
|
|
390
|
+
### High memory usage
|
|
391
|
+
|
|
392
|
+
Reduce batch processor queue size:
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
initTelemetry({
|
|
396
|
+
serviceName: 'my-service',
|
|
397
|
+
batchProcessor: {
|
|
398
|
+
maxQueueSize: 512, // Lower from default 2048
|
|
399
|
+
},
|
|
400
|
+
})
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Related Documentation
|
|
404
|
+
|
|
405
|
+
- [OpenTelemetry JavaScript](https://opentelemetry.io/docs/languages/js/)
|
|
406
|
+
- [W3C Trace Context](https://www.w3.org/TR/trace-context/)
|
|
407
|
+
- [Kosmos Observability Stack](https://github.com/kabran-owner/kosmos/tree/main/services/observability)
|