@principal-ai/principal-studio-cli 0.35.3
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 +172 -0
- package/dist/commands/agent-session.d.ts +3 -0
- package/dist/commands/agent-session.d.ts.map +1 -0
- package/dist/commands/agent-session.js +67 -0
- package/dist/commands/agent-sessions.d.ts +11 -0
- package/dist/commands/agent-sessions.d.ts.map +1 -0
- package/dist/commands/agent-sessions.js +39 -0
- package/dist/commands/auxiliary/index.d.ts +3 -0
- package/dist/commands/auxiliary/index.d.ts.map +1 -0
- package/dist/commands/auxiliary/index.js +9 -0
- package/dist/commands/auxiliary/validate.d.ts +3 -0
- package/dist/commands/auxiliary/validate.d.ts.map +1 -0
- package/dist/commands/auxiliary/validate.js +123 -0
- package/dist/commands/collector/check.d.ts +6 -0
- package/dist/commands/collector/check.d.ts.map +1 -0
- package/dist/commands/collector/check.js +153 -0
- package/dist/commands/collector/diagnose.d.ts +6 -0
- package/dist/commands/collector/diagnose.d.ts.map +1 -0
- package/dist/commands/collector/diagnose.js +229 -0
- package/dist/commands/collector/index.d.ts +6 -0
- package/dist/commands/collector/index.d.ts.map +1 -0
- package/dist/commands/collector/index.js +16 -0
- package/dist/commands/collector/status.d.ts +6 -0
- package/dist/commands/collector/status.d.ts.map +1 -0
- package/dist/commands/collector/status.js +77 -0
- package/dist/commands/collector/utils.d.ts +92 -0
- package/dist/commands/collector/utils.d.ts.map +1 -0
- package/dist/commands/collector/utils.js +154 -0
- package/dist/commands/coverage.d.ts +9 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +252 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +50 -0
- package/dist/commands/events/index.d.ts +3 -0
- package/dist/commands/events/index.d.ts.map +1 -0
- package/dist/commands/events/index.js +9 -0
- package/dist/commands/events/validate.d.ts +3 -0
- package/dist/commands/events/validate.d.ts.map +1 -0
- package/dist/commands/events/validate.js +124 -0
- package/dist/commands/formats.d.ts +6 -0
- package/dist/commands/formats.d.ts.map +1 -0
- package/dist/commands/formats.js +1118 -0
- package/dist/commands/hooks.d.ts +9 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +295 -0
- package/dist/commands/inbox.d.ts +13 -0
- package/dist/commands/inbox.d.ts.map +1 -0
- package/dist/commands/inbox.js +179 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +220 -0
- package/dist/commands/lint.d.ts +11 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +71 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +78 -0
- package/dist/commands/migrate-nodes.d.ts +9 -0
- package/dist/commands/migrate-nodes.d.ts.map +1 -0
- package/dist/commands/migrate-nodes.js +363 -0
- package/dist/commands/migrate-scopes-to-canvas.d.ts +3 -0
- package/dist/commands/migrate-scopes-to-canvas.d.ts.map +1 -0
- package/dist/commands/migrate-scopes-to-canvas.js +143 -0
- package/dist/commands/migration.d.ts +6 -0
- package/dist/commands/migration.d.ts.map +1 -0
- package/dist/commands/migration.js +247 -0
- package/dist/commands/open-studio.d.ts +10 -0
- package/dist/commands/open-studio.d.ts.map +1 -0
- package/dist/commands/open-studio.js +32 -0
- package/dist/commands/opencode/fetch.d.ts +3 -0
- package/dist/commands/opencode/fetch.d.ts.map +1 -0
- package/dist/commands/opencode/fetch.js +25 -0
- package/dist/commands/opencode/index.d.ts +3 -0
- package/dist/commands/opencode/index.d.ts.map +1 -0
- package/dist/commands/opencode/index.js +11 -0
- package/dist/commands/opencode/list-sessions.d.ts +3 -0
- package/dist/commands/opencode/list-sessions.d.ts.map +1 -0
- package/dist/commands/opencode/list-sessions.js +20 -0
- package/dist/commands/repo.d.ts +18 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +233 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +367 -0
- package/dist/commands/scopes/index.d.ts +3 -0
- package/dist/commands/scopes/index.d.ts.map +1 -0
- package/dist/commands/scopes/index.js +9 -0
- package/dist/commands/scopes/validate.d.ts +3 -0
- package/dist/commands/scopes/validate.d.ts.map +1 -0
- package/dist/commands/scopes/validate.js +187 -0
- package/dist/commands/setup.d.ts +6 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +406 -0
- package/dist/commands/starred-collections.d.ts +12 -0
- package/dist/commands/starred-collections.d.ts.map +1 -0
- package/dist/commands/starred-collections.js +310 -0
- package/dist/commands/subsystem-model.d.ts +11 -0
- package/dist/commands/subsystem-model.d.ts.map +1 -0
- package/dist/commands/subsystem-model.js +249 -0
- package/dist/commands/topic.d.ts +15 -0
- package/dist/commands/topic.d.ts.map +1 -0
- package/dist/commands/topic.js +683 -0
- package/dist/commands/tour.d.ts +23 -0
- package/dist/commands/tour.d.ts.map +1 -0
- package/dist/commands/tour.js +783 -0
- package/dist/commands/trace/flow.d.ts +6 -0
- package/dist/commands/trace/flow.d.ts.map +1 -0
- package/dist/commands/trace/flow.js +158 -0
- package/dist/commands/trace/index.d.ts +6 -0
- package/dist/commands/trace/index.d.ts.map +1 -0
- package/dist/commands/trace/index.js +20 -0
- package/dist/commands/trace/inspect.d.ts +6 -0
- package/dist/commands/trace/inspect.d.ts.map +1 -0
- package/dist/commands/trace/inspect.js +187 -0
- package/dist/commands/trace/list.d.ts +6 -0
- package/dist/commands/trace/list.d.ts.map +1 -0
- package/dist/commands/trace/list.js +145 -0
- package/dist/commands/trace/registrations.d.ts +6 -0
- package/dist/commands/trace/registrations.d.ts.map +1 -0
- package/dist/commands/trace/registrations.js +81 -0
- package/dist/commands/trace/validate.d.ts +6 -0
- package/dist/commands/trace/validate.d.ts.map +1 -0
- package/dist/commands/trace/validate.js +276 -0
- package/dist/commands/trail.d.ts +36 -0
- package/dist/commands/trail.d.ts.map +1 -0
- package/dist/commands/trail.js +622 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +3334 -0
- package/dist/commands/workflow/implementation.d.ts +3 -0
- package/dist/commands/workflow/implementation.d.ts.map +1 -0
- package/dist/commands/workflow/implementation.js +51 -0
- package/dist/commands/workflow/index.d.ts +3 -0
- package/dist/commands/workflow/index.d.ts.map +1 -0
- package/dist/commands/workflow/index.js +19 -0
- package/dist/commands/workflow/inspect.d.ts +3 -0
- package/dist/commands/workflow/inspect.d.ts.map +1 -0
- package/dist/commands/workflow/inspect.js +123 -0
- package/dist/commands/workflow/list.d.ts +3 -0
- package/dist/commands/workflow/list.d.ts.map +1 -0
- package/dist/commands/workflow/list.js +95 -0
- package/dist/commands/workflow/render.d.ts +3 -0
- package/dist/commands/workflow/render.d.ts.map +1 -0
- package/dist/commands/workflow/render.js +88 -0
- package/dist/commands/workflow/test.d.ts +3 -0
- package/dist/commands/workflow/test.d.ts.map +1 -0
- package/dist/commands/workflow/test.js +141 -0
- package/dist/commands/workflow/utils.d.ts +49 -0
- package/dist/commands/workflow/utils.d.ts.map +1 -0
- package/dist/commands/workflow/utils.js +164 -0
- package/dist/commands/workflow/validate.d.ts +3 -0
- package/dist/commands/workflow/validate.d.ts.map +1 -0
- package/dist/commands/workflow/validate.js +344 -0
- package/dist/file-utils.d.ts +15 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/file-utils.js +29 -0
- package/dist/index.cjs +285718 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/lib/bridge-ipc.d.ts +29 -0
- package/dist/lib/bridge-ipc.d.ts.map +1 -0
- package/dist/lib/bridge-ipc.js +128 -0
- package/dist/lib/github-user.d.ts +17 -0
- package/dist/lib/github-user.d.ts.map +1 -0
- package/dist/lib/github-user.js +53 -0
- package/dist/lib/open-url.d.ts +11 -0
- package/dist/lib/open-url.d.ts.map +1 -0
- package/dist/lib/open-url.js +45 -0
- package/dist/lib/subsystem-model-store.d.ts +74 -0
- package/dist/lib/subsystem-model-store.d.ts.map +1 -0
- package/dist/lib/subsystem-model-store.js +292 -0
- package/dist/lib/tour-cache.d.ts +26 -0
- package/dist/lib/tour-cache.d.ts.map +1 -0
- package/dist/lib/tour-cache.js +46 -0
- package/dist/lib/trail-cache.d.ts +40 -0
- package/dist/lib/trail-cache.d.ts.map +1 -0
- package/dist/lib/trail-cache.js +97 -0
- package/dist/lib/viewer-ipc.d.ts +44 -0
- package/dist/lib/viewer-ipc.d.ts.map +1 -0
- package/dist/lib/viewer-ipc.js +68 -0
- package/package.json +68 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collector diagnose - Comprehensive diagnostic for troubleshooting collector issues
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { DEFAULT_COLLECTOR_PORT, checkHealth, getServiceStats, checkPort, createTestTrace, sendTestTrace, formatRelativeTime, } from './utils.js';
|
|
7
|
+
export function createDiagnoseCommand() {
|
|
8
|
+
const command = new Command('diagnose');
|
|
9
|
+
command
|
|
10
|
+
.description('Run comprehensive diagnostics on the OTEL collector')
|
|
11
|
+
.option('-p, --port <port>', `Collector port (default: ${DEFAULT_COLLECTOR_PORT})`)
|
|
12
|
+
.option('--json', 'Output as JSON')
|
|
13
|
+
.action(async (options) => {
|
|
14
|
+
try {
|
|
15
|
+
const port = options.port ? parseInt(options.port, 10) : DEFAULT_COLLECTOR_PORT;
|
|
16
|
+
// Port checks
|
|
17
|
+
const portChecks = [];
|
|
18
|
+
const portsToCheck = [
|
|
19
|
+
{ port, name: 'OTLP' },
|
|
20
|
+
{ port: port + 1, name: 'wrapper' },
|
|
21
|
+
{ port: port + 2, name: 'internal' },
|
|
22
|
+
];
|
|
23
|
+
for (const { port: p, name } of portsToCheck) {
|
|
24
|
+
const result = await checkPort(p);
|
|
25
|
+
portChecks.push({
|
|
26
|
+
port: p,
|
|
27
|
+
name,
|
|
28
|
+
status: result.open ? 'listening' : 'closed',
|
|
29
|
+
service: result.service,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Endpoint checks
|
|
33
|
+
const endpointChecks = [];
|
|
34
|
+
const mainPortOpen = portChecks[0].status === 'listening';
|
|
35
|
+
// Health endpoint
|
|
36
|
+
if (mainPortOpen) {
|
|
37
|
+
const health = await checkHealth(port);
|
|
38
|
+
endpointChecks.push({
|
|
39
|
+
method: 'GET',
|
|
40
|
+
path: '/health',
|
|
41
|
+
status: health ? 'ok' : 'error',
|
|
42
|
+
statusCode: health ? 200 : undefined,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
endpointChecks.push({
|
|
47
|
+
method: 'GET',
|
|
48
|
+
path: '/health',
|
|
49
|
+
status: 'skipped',
|
|
50
|
+
note: 'Port not open',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// Services stats endpoint
|
|
54
|
+
if (mainPortOpen) {
|
|
55
|
+
const stats = await getServiceStats(port);
|
|
56
|
+
endpointChecks.push({
|
|
57
|
+
method: 'GET',
|
|
58
|
+
path: '/services/stats',
|
|
59
|
+
status: stats ? 'ok' : 'error',
|
|
60
|
+
statusCode: stats ? 200 : undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
endpointChecks.push({
|
|
65
|
+
method: 'GET',
|
|
66
|
+
path: '/services/stats',
|
|
67
|
+
status: 'skipped',
|
|
68
|
+
note: 'Port not open',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Traces endpoint
|
|
72
|
+
if (mainPortOpen) {
|
|
73
|
+
const trace = createTestTrace('principal-cli-diagnose');
|
|
74
|
+
const result = await sendTestTrace(port, trace);
|
|
75
|
+
endpointChecks.push({
|
|
76
|
+
method: 'POST',
|
|
77
|
+
path: '/v1/traces',
|
|
78
|
+
status: result.success ? 'ok' : 'error',
|
|
79
|
+
statusCode: result.statusCode,
|
|
80
|
+
note: result.success ? 'test trace accepted' : result.error,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
endpointChecks.push({
|
|
85
|
+
method: 'POST',
|
|
86
|
+
path: '/v1/traces',
|
|
87
|
+
status: 'skipped',
|
|
88
|
+
note: 'Port not open',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// Logs endpoint (just check if it responds, don't actually send)
|
|
92
|
+
if (mainPortOpen) {
|
|
93
|
+
try {
|
|
94
|
+
const response = await fetch(`http://localhost:${port}/v1/logs`, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { 'Content-Type': 'application/json' },
|
|
97
|
+
body: JSON.stringify({ resourceLogs: [] }),
|
|
98
|
+
signal: AbortSignal.timeout(2000),
|
|
99
|
+
});
|
|
100
|
+
endpointChecks.push({
|
|
101
|
+
method: 'POST',
|
|
102
|
+
path: '/v1/logs',
|
|
103
|
+
status: response.ok ? 'ok' : 'error',
|
|
104
|
+
statusCode: response.status,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
endpointChecks.push({
|
|
109
|
+
method: 'POST',
|
|
110
|
+
path: '/v1/logs',
|
|
111
|
+
status: 'error',
|
|
112
|
+
note: 'Request failed',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
endpointChecks.push({
|
|
118
|
+
method: 'POST',
|
|
119
|
+
path: '/v1/logs',
|
|
120
|
+
status: 'skipped',
|
|
121
|
+
note: 'Port not open',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Get recent activity
|
|
125
|
+
const stats = mainPortOpen ? await getServiceStats(port) : null;
|
|
126
|
+
const health = mainPortOpen ? await checkHealth(port) : null;
|
|
127
|
+
let recentActivity = null;
|
|
128
|
+
if (stats && health) {
|
|
129
|
+
const sortedServices = Object.entries(stats.services)
|
|
130
|
+
.sort((a, b) => new Date(b[1].lastSeen).getTime() - new Date(a[1].lastSeen).getTime())
|
|
131
|
+
.slice(0, 5);
|
|
132
|
+
recentActivity = {
|
|
133
|
+
lastTrace: sortedServices.length > 0 ? formatRelativeTime(sortedServices[0][1].lastSeen) : undefined,
|
|
134
|
+
tracesTotal: health.tracesReceived ?? 0,
|
|
135
|
+
logsTotal: health.logsReceived ?? 0,
|
|
136
|
+
services: sortedServices.map(([name, info]) => ({
|
|
137
|
+
name,
|
|
138
|
+
lastSeen: formatRelativeTime(info.lastSeen),
|
|
139
|
+
traces: info.totalTraces,
|
|
140
|
+
})),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// Determine issues
|
|
144
|
+
const issues = [];
|
|
145
|
+
if (!mainPortOpen) {
|
|
146
|
+
issues.push(`Main OTLP port (${port}) is not responding`);
|
|
147
|
+
}
|
|
148
|
+
const failedEndpoints = endpointChecks.filter((e) => e.status === 'error');
|
|
149
|
+
for (const endpoint of failedEndpoints) {
|
|
150
|
+
issues.push(`${endpoint.method} ${endpoint.path} failed: ${endpoint.note || `HTTP ${endpoint.statusCode}`}`);
|
|
151
|
+
}
|
|
152
|
+
if (options.json) {
|
|
153
|
+
console.log(JSON.stringify({
|
|
154
|
+
ports: portChecks,
|
|
155
|
+
endpoints: endpointChecks,
|
|
156
|
+
recentActivity,
|
|
157
|
+
issues,
|
|
158
|
+
healthy: issues.length === 0,
|
|
159
|
+
}, null, 2));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(chalk.bold('\nCollector Diagnostics'));
|
|
163
|
+
console.log('━'.repeat(60));
|
|
164
|
+
// Port availability
|
|
165
|
+
console.log(chalk.bold('\nPort Availability:'));
|
|
166
|
+
for (const check of portChecks) {
|
|
167
|
+
const icon = check.status === 'listening' ? chalk.green('✓') : chalk.red('✗');
|
|
168
|
+
const status = check.status === 'listening'
|
|
169
|
+
? chalk.green('listening') + chalk.gray(` (${check.service})`)
|
|
170
|
+
: chalk.red('closed');
|
|
171
|
+
console.log(` ${check.port} (${check.name}).......... ${icon} ${status}`);
|
|
172
|
+
}
|
|
173
|
+
// Endpoints
|
|
174
|
+
console.log(chalk.bold('\nEndpoints:'));
|
|
175
|
+
for (const check of endpointChecks) {
|
|
176
|
+
const icon = check.status === 'ok'
|
|
177
|
+
? chalk.green('✓')
|
|
178
|
+
: check.status === 'skipped'
|
|
179
|
+
? chalk.gray('─')
|
|
180
|
+
: chalk.red('✗');
|
|
181
|
+
const status = check.status === 'ok'
|
|
182
|
+
? chalk.green(`${check.statusCode} OK`)
|
|
183
|
+
: check.status === 'skipped'
|
|
184
|
+
? chalk.gray('skipped')
|
|
185
|
+
: chalk.red(check.note || `${check.statusCode}`);
|
|
186
|
+
const note = check.status === 'ok' && check.note ? chalk.gray(` (${check.note})`) : '';
|
|
187
|
+
console.log(` ${check.method.padEnd(4)} ${check.path.padEnd(15)} ${icon} ${status}${note}`);
|
|
188
|
+
}
|
|
189
|
+
// Recent activity
|
|
190
|
+
if (recentActivity) {
|
|
191
|
+
console.log(chalk.bold('\nRecent Activity:'));
|
|
192
|
+
if (recentActivity.lastTrace) {
|
|
193
|
+
console.log(` Last trace: ${recentActivity.lastTrace}`);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(chalk.gray(' Last trace: no traces received'));
|
|
197
|
+
}
|
|
198
|
+
console.log(` Traces total: ${recentActivity.tracesTotal}`);
|
|
199
|
+
console.log(` Logs total: ${recentActivity.logsTotal}`);
|
|
200
|
+
if (recentActivity.services.length > 0) {
|
|
201
|
+
console.log(chalk.bold('\n Recent Services:'));
|
|
202
|
+
for (const svc of recentActivity.services) {
|
|
203
|
+
console.log(chalk.gray(` • ${svc.name}: ${svc.traces} traces, last seen ${svc.lastSeen}`));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
console.log('\n' + '━'.repeat(60));
|
|
208
|
+
if (issues.length === 0) {
|
|
209
|
+
console.log(chalk.green('No issues detected.'));
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
console.log(chalk.red(`${issues.length} issue(s) detected:`));
|
|
213
|
+
for (const issue of issues) {
|
|
214
|
+
console.log(chalk.yellow(` • ${issue}`));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
console.log();
|
|
218
|
+
}
|
|
219
|
+
if (issues.length > 0) {
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
console.error(chalk.red('Error:'), error.message);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
return command;
|
|
229
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/collector/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collector commands - Check OTEL collector status and connectivity
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { createStatusCommand } from './status.js';
|
|
6
|
+
import { createCheckCommand } from './check.js';
|
|
7
|
+
import { createDiagnoseCommand } from './diagnose.js';
|
|
8
|
+
export function createCollectorCommand() {
|
|
9
|
+
const command = new Command('collector');
|
|
10
|
+
command
|
|
11
|
+
.description('Check OTEL collector status and connectivity')
|
|
12
|
+
.addCommand(createStatusCommand())
|
|
13
|
+
.addCommand(createCheckCommand())
|
|
14
|
+
.addCommand(createDiagnoseCommand());
|
|
15
|
+
return command;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/collector/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,mBAAmB,IAAI,OAAO,CAyF7C"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collector status - Check OTEL collector health and service statistics
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { DEFAULT_COLLECTOR_PORT, checkHealth, getServiceStats, formatRelativeTime, } from './utils.js';
|
|
7
|
+
export function createStatusCommand() {
|
|
8
|
+
const command = new Command('status');
|
|
9
|
+
command
|
|
10
|
+
.description('Check OTEL collector health and active services')
|
|
11
|
+
.option('-p, --port <port>', `Collector port (default: ${DEFAULT_COLLECTOR_PORT})`)
|
|
12
|
+
.option('--json', 'Output as JSON')
|
|
13
|
+
.action(async (options) => {
|
|
14
|
+
try {
|
|
15
|
+
const port = options.port ? parseInt(options.port, 10) : DEFAULT_COLLECTOR_PORT;
|
|
16
|
+
const endpoint = `http://localhost:${port}`;
|
|
17
|
+
// Get health status
|
|
18
|
+
const health = await checkHealth(port);
|
|
19
|
+
const stats = health ? await getServiceStats(port) : null;
|
|
20
|
+
if (options.json) {
|
|
21
|
+
console.log(JSON.stringify({
|
|
22
|
+
endpoint,
|
|
23
|
+
healthy: health !== null,
|
|
24
|
+
tracesReceived: health?.tracesReceived ?? 0,
|
|
25
|
+
logsReceived: health?.logsReceived ?? 0,
|
|
26
|
+
services: stats ?? null,
|
|
27
|
+
}, null, 2));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(chalk.bold('\nOTEL Collector Status'));
|
|
31
|
+
console.log('━'.repeat(60));
|
|
32
|
+
console.log(`\n Endpoint: ${endpoint}`);
|
|
33
|
+
if (health) {
|
|
34
|
+
console.log(` Status: ${chalk.green('✓ healthy')}`);
|
|
35
|
+
console.log(` Traces received: ${health.tracesReceived ?? 0}`);
|
|
36
|
+
console.log(` Logs received: ${health.logsReceived ?? 0}`);
|
|
37
|
+
if (stats && stats.summary.totalServices > 0) {
|
|
38
|
+
console.log(`\n Services (${stats.summary.aliveServices} active, ${stats.summary.totalServices} total):`);
|
|
39
|
+
const sortedServices = Object.entries(stats.services).sort((a, b) => {
|
|
40
|
+
// Sort by lastSeen (most recent first)
|
|
41
|
+
return new Date(b[1].lastSeen).getTime() - new Date(a[1].lastSeen).getTime();
|
|
42
|
+
});
|
|
43
|
+
for (const [serviceName, info] of sortedServices) {
|
|
44
|
+
const statusIcon = info.isAlive ? chalk.green('✓') : chalk.gray('○');
|
|
45
|
+
const lastSeen = formatRelativeTime(info.lastSeen);
|
|
46
|
+
const traceCount = `(${info.totalTraces} traces)`;
|
|
47
|
+
console.log(` ${statusIcon} ${serviceName.padEnd(20)} ${chalk.gray(`last seen ${lastSeen}`)} ${chalk.gray(traceCount)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(chalk.gray('\n No services have sent traces yet.'));
|
|
52
|
+
}
|
|
53
|
+
console.log('\n' + '━'.repeat(60));
|
|
54
|
+
console.log(chalk.green('Collector is ready to receive traces.'));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(` Status: ${chalk.red('✗ unreachable')}`);
|
|
58
|
+
console.log('\n' + '━'.repeat(60));
|
|
59
|
+
console.log(chalk.bold('\n Troubleshooting:'));
|
|
60
|
+
console.log(chalk.gray(' • Verify the collector is running'));
|
|
61
|
+
console.log(chalk.gray(` • Check if port ${port} is in use by another process`));
|
|
62
|
+
console.log(chalk.gray(` • Try: curl ${endpoint}/health`));
|
|
63
|
+
}
|
|
64
|
+
console.log();
|
|
65
|
+
}
|
|
66
|
+
// Exit with error if not healthy
|
|
67
|
+
if (!health) {
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error(chalk.red('Error:'), error.message);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return command;
|
|
77
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for collector commands
|
|
3
|
+
*/
|
|
4
|
+
export declare const DEFAULT_COLLECTOR_PORT = 4318;
|
|
5
|
+
export interface HealthResponse {
|
|
6
|
+
status: string;
|
|
7
|
+
tracesReceived?: number;
|
|
8
|
+
logsReceived?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ServiceStats {
|
|
11
|
+
summary: {
|
|
12
|
+
totalServices: number;
|
|
13
|
+
aliveServices: number;
|
|
14
|
+
totalTraces: number;
|
|
15
|
+
};
|
|
16
|
+
services: Record<string, ServiceInfo>;
|
|
17
|
+
}
|
|
18
|
+
export interface ServiceInfo {
|
|
19
|
+
firstSeen: string;
|
|
20
|
+
lastSeen: string;
|
|
21
|
+
totalTraces: number;
|
|
22
|
+
isAlive: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface OTLPTracePayload {
|
|
25
|
+
resourceSpans: Array<{
|
|
26
|
+
resource: {
|
|
27
|
+
attributes: Array<{
|
|
28
|
+
key: string;
|
|
29
|
+
value: {
|
|
30
|
+
stringValue?: string;
|
|
31
|
+
boolValue?: boolean;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
scopeSpans: Array<{
|
|
36
|
+
scope: {
|
|
37
|
+
name: string;
|
|
38
|
+
};
|
|
39
|
+
spans: Array<{
|
|
40
|
+
traceId: string;
|
|
41
|
+
spanId: string;
|
|
42
|
+
name: string;
|
|
43
|
+
kind: number;
|
|
44
|
+
startTimeUnixNano: string;
|
|
45
|
+
endTimeUnixNano: string;
|
|
46
|
+
attributes: Array<{
|
|
47
|
+
key: string;
|
|
48
|
+
value: {
|
|
49
|
+
stringValue?: string;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
status: {
|
|
53
|
+
code: number;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if the collector is healthy
|
|
61
|
+
*/
|
|
62
|
+
export declare function checkHealth(port: number): Promise<HealthResponse | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Get service statistics from the collector
|
|
65
|
+
*/
|
|
66
|
+
export declare function getServiceStats(port: number): Promise<ServiceStats | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Create a minimal test trace payload
|
|
69
|
+
*/
|
|
70
|
+
export declare function createTestTrace(serviceName: string): OTLPTracePayload;
|
|
71
|
+
export interface SendTraceResult {
|
|
72
|
+
success: boolean;
|
|
73
|
+
statusCode?: number;
|
|
74
|
+
latencyMs: number;
|
|
75
|
+
error?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Send a test trace to the collector
|
|
79
|
+
*/
|
|
80
|
+
export declare function sendTestTrace(port: number, trace: OTLPTracePayload, authToken?: string): Promise<SendTraceResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Format relative time (e.g., "30s ago", "2m ago")
|
|
83
|
+
*/
|
|
84
|
+
export declare function formatRelativeTime(isoString: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Check if a port is responding (basic connectivity check)
|
|
87
|
+
*/
|
|
88
|
+
export declare function checkPort(port: number): Promise<{
|
|
89
|
+
open: boolean;
|
|
90
|
+
service?: string;
|
|
91
|
+
}>;
|
|
92
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/commands/collector/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAG3C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE;QACP,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,KAAK,CAAC;QACnB,QAAQ,EAAE;YACR,UAAU,EAAE,KAAK,CAAC;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE;oBAAE,WAAW,CAAC,EAAE,MAAM,CAAC;oBAAC,SAAS,CAAC,EAAE,OAAO,CAAA;iBAAE,CAAA;aAAE,CAAC,CAAC;SAC1F,CAAC;QACF,UAAU,EAAE,KAAK,CAAC;YAChB,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC;YACxB,KAAK,EAAE,KAAK,CAAC;gBACX,OAAO,EAAE,MAAM,CAAC;gBAChB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE,MAAM,CAAC;gBACb,IAAI,EAAE,MAAM,CAAC;gBACb,iBAAiB,EAAE,MAAM,CAAC;gBAC1B,eAAe,EAAE,MAAM,CAAC;gBACxB,UAAU,EAAE,KAAK,CAAC;oBAAE,GAAG,EAAE,MAAM,CAAC;oBAAC,KAAK,EAAE;wBAAE,WAAW,CAAC,EAAE,MAAM,CAAA;qBAAE,CAAA;iBAAE,CAAC,CAAC;gBACpE,MAAM,EAAE;oBAAE,IAAI,EAAE,MAAM,CAAA;iBAAE,CAAC;aAC1B,CAAC,CAAC;SACJ,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAc9E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAchF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAuCrE;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,gBAAgB,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAkC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAkB5D;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAc1F"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for collector commands
|
|
3
|
+
*/
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
export const DEFAULT_COLLECTOR_PORT = 4318;
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = 2000;
|
|
7
|
+
/**
|
|
8
|
+
* Check if the collector is healthy
|
|
9
|
+
*/
|
|
10
|
+
export async function checkHealth(port) {
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch(`http://localhost:${port}/health`, {
|
|
13
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return (await response.json());
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get service statistics from the collector
|
|
26
|
+
*/
|
|
27
|
+
export async function getServiceStats(port) {
|
|
28
|
+
try {
|
|
29
|
+
const response = await fetch(`http://localhost:${port}/services/stats`, {
|
|
30
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return (await response.json());
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a minimal test trace payload
|
|
43
|
+
*/
|
|
44
|
+
export function createTestTrace(serviceName) {
|
|
45
|
+
const traceId = crypto.randomUUID().replace(/-/g, '');
|
|
46
|
+
const spanId = crypto.randomUUID().replace(/-/g, '').slice(0, 16);
|
|
47
|
+
const now = Date.now() * 1_000_000; // Convert to nanoseconds
|
|
48
|
+
return {
|
|
49
|
+
resourceSpans: [
|
|
50
|
+
{
|
|
51
|
+
resource: {
|
|
52
|
+
attributes: [
|
|
53
|
+
{ key: 'service.name', value: { stringValue: serviceName } },
|
|
54
|
+
{ key: 'principal.cli.test', value: { boolValue: true } },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
scopeSpans: [
|
|
58
|
+
{
|
|
59
|
+
scope: { name: 'principal-cli-check' },
|
|
60
|
+
spans: [
|
|
61
|
+
{
|
|
62
|
+
traceId,
|
|
63
|
+
spanId,
|
|
64
|
+
name: 'cli.connectivity.test',
|
|
65
|
+
kind: 1, // INTERNAL
|
|
66
|
+
startTimeUnixNano: String(now),
|
|
67
|
+
endTimeUnixNano: String(now + 1_000_000), // 1ms duration
|
|
68
|
+
attributes: [
|
|
69
|
+
{
|
|
70
|
+
key: 'test.timestamp',
|
|
71
|
+
value: { stringValue: new Date().toISOString() },
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
status: { code: 1 }, // OK
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Send a test trace to the collector
|
|
85
|
+
*/
|
|
86
|
+
export async function sendTestTrace(port, trace, authToken) {
|
|
87
|
+
const start = Date.now();
|
|
88
|
+
try {
|
|
89
|
+
const headers = {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
};
|
|
92
|
+
if (authToken) {
|
|
93
|
+
headers['Authorization'] = `Bearer ${authToken}`;
|
|
94
|
+
}
|
|
95
|
+
const response = await fetch(`http://localhost:${port}/v1/traces`, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
headers,
|
|
98
|
+
body: JSON.stringify(trace),
|
|
99
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
|
|
100
|
+
});
|
|
101
|
+
const latencyMs = Date.now() - start;
|
|
102
|
+
return {
|
|
103
|
+
success: response.ok,
|
|
104
|
+
statusCode: response.status,
|
|
105
|
+
latencyMs,
|
|
106
|
+
error: response.ok ? undefined : `HTTP ${response.status}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
latencyMs: Date.now() - start,
|
|
113
|
+
error: error.message,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Format relative time (e.g., "30s ago", "2m ago")
|
|
119
|
+
*/
|
|
120
|
+
export function formatRelativeTime(isoString) {
|
|
121
|
+
const date = new Date(isoString);
|
|
122
|
+
const now = Date.now();
|
|
123
|
+
const diffMs = now - date.getTime();
|
|
124
|
+
if (diffMs < 0)
|
|
125
|
+
return 'just now';
|
|
126
|
+
const seconds = Math.floor(diffMs / 1000);
|
|
127
|
+
if (seconds < 60)
|
|
128
|
+
return `${seconds}s ago`;
|
|
129
|
+
const minutes = Math.floor(seconds / 60);
|
|
130
|
+
if (minutes < 60)
|
|
131
|
+
return `${minutes}m ago`;
|
|
132
|
+
const hours = Math.floor(minutes / 60);
|
|
133
|
+
if (hours < 24)
|
|
134
|
+
return `${hours}h ago`;
|
|
135
|
+
const days = Math.floor(hours / 24);
|
|
136
|
+
return `${days}d ago`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if a port is responding (basic connectivity check)
|
|
140
|
+
*/
|
|
141
|
+
export async function checkPort(port) {
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch(`http://localhost:${port}/health`, {
|
|
144
|
+
signal: AbortSignal.timeout(1000),
|
|
145
|
+
});
|
|
146
|
+
if (response.ok) {
|
|
147
|
+
return { open: true, service: 'collector' };
|
|
148
|
+
}
|
|
149
|
+
return { open: true, service: 'unknown' };
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return { open: false };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage command - Measure telemetry coverage for canvas nodes
|
|
3
|
+
*
|
|
4
|
+
* This command analyzes .otel.canvas files and checks which implementation files
|
|
5
|
+
* contain the OpenTelemetry events documented in canvas nodes.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
export declare function createCoverageCommand(): Command;
|
|
9
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuNpC,wBAAgB,qBAAqB,IAAI,OAAO,CAkE/C"}
|