@calltelemetry/cli 0.7.5 → 0.7.8

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.
Files changed (142) hide show
  1. package/README.md +104 -2
  2. package/dist/commands/config.d.ts.map +1 -1
  3. package/dist/commands/config.js +13 -0
  4. package/dist/commands/config.js.map +1 -1
  5. package/dist/commands/db.d.ts.map +1 -1
  6. package/dist/commands/db.js +33 -0
  7. package/dist/commands/db.js.map +1 -1
  8. package/dist/commands/diag.d.ts.map +1 -1
  9. package/dist/commands/diag.js +3 -0
  10. package/dist/commands/diag.js.map +1 -1
  11. package/dist/commands/health.d.ts +3 -0
  12. package/dist/commands/health.d.ts.map +1 -0
  13. package/dist/commands/health.js +34 -0
  14. package/dist/commands/health.js.map +1 -0
  15. package/dist/commands/migrate.d.ts.map +1 -1
  16. package/dist/commands/migrate.js +7 -0
  17. package/dist/commands/migrate.js.map +1 -1
  18. package/dist/commands/self-update.d.ts.map +1 -1
  19. package/dist/commands/self-update.js +1 -0
  20. package/dist/commands/self-update.js.map +1 -1
  21. package/dist/commands/syslog.d.ts +3 -0
  22. package/dist/commands/syslog.d.ts.map +1 -0
  23. package/dist/commands/syslog.js +159 -0
  24. package/dist/commands/syslog.js.map +1 -0
  25. package/dist/commands/update.d.ts.map +1 -1
  26. package/dist/commands/update.js +143 -3
  27. package/dist/commands/update.js.map +1 -1
  28. package/dist/index.js +13 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/lib/bundle.d.ts +3 -1
  31. package/dist/lib/bundle.d.ts.map +1 -1
  32. package/dist/lib/bundle.js +90 -15
  33. package/dist/lib/bundle.js.map +1 -1
  34. package/dist/lib/compose.d.ts +10 -0
  35. package/dist/lib/compose.d.ts.map +1 -1
  36. package/dist/lib/compose.js +251 -13
  37. package/dist/lib/compose.js.map +1 -1
  38. package/dist/lib/db-backup.d.ts +23 -0
  39. package/dist/lib/db-backup.d.ts.map +1 -0
  40. package/dist/lib/db-backup.js +80 -0
  41. package/dist/lib/db-backup.js.map +1 -0
  42. package/dist/lib/health-report.d.ts +93 -0
  43. package/dist/lib/health-report.d.ts.map +1 -0
  44. package/dist/lib/health-report.js +391 -0
  45. package/dist/lib/health-report.js.map +1 -0
  46. package/dist/lib/migration-003-nm-heal.js +5 -5
  47. package/dist/lib/migration-003-nm-heal.js.map +1 -1
  48. package/dist/lib/migration-009-bind-mount-files.d.ts +5 -4
  49. package/dist/lib/migration-009-bind-mount-files.d.ts.map +1 -1
  50. package/dist/lib/migration-009-bind-mount-files.js +15 -7
  51. package/dist/lib/migration-009-bind-mount-files.js.map +1 -1
  52. package/dist/lib/migration-010-jtapi-state.js +2 -2
  53. package/dist/lib/migration-010-jtapi-state.js.map +1 -1
  54. package/dist/lib/migration-011-docker-memory-limit.js +2 -2
  55. package/dist/lib/migration-011-docker-memory-limit.js.map +1 -1
  56. package/dist/lib/migration-012-db-pool-sizes.d.ts.map +1 -1
  57. package/dist/lib/migration-012-db-pool-sizes.js +5 -14
  58. package/dist/lib/migration-012-db-pool-sizes.js.map +1 -1
  59. package/dist/lib/migration-013-grafana-password.d.ts.map +1 -1
  60. package/dist/lib/migration-013-grafana-password.js +5 -13
  61. package/dist/lib/migration-013-grafana-password.js.map +1 -1
  62. package/dist/lib/postgres-performance.d.ts +51 -0
  63. package/dist/lib/postgres-performance.d.ts.map +1 -0
  64. package/dist/lib/postgres-performance.js +279 -0
  65. package/dist/lib/postgres-performance.js.map +1 -0
  66. package/dist/lib/release-migration-progress.d.ts +48 -0
  67. package/dist/lib/release-migration-progress.d.ts.map +1 -0
  68. package/dist/lib/release-migration-progress.js +223 -0
  69. package/dist/lib/release-migration-progress.js.map +1 -0
  70. package/dist/lib/services.d.ts.map +1 -1
  71. package/dist/lib/services.js +70 -1
  72. package/dist/lib/services.js.map +1 -1
  73. package/dist/lib/showtech-steps.d.ts +5 -1
  74. package/dist/lib/showtech-steps.d.ts.map +1 -1
  75. package/dist/lib/showtech-steps.js +44 -13
  76. package/dist/lib/showtech-steps.js.map +1 -1
  77. package/dist/lib/syslog.d.ts +5 -0
  78. package/dist/lib/syslog.d.ts.map +1 -0
  79. package/dist/lib/syslog.js +21 -0
  80. package/dist/lib/syslog.js.map +1 -0
  81. package/dist/lib/update-steps.d.ts.map +1 -1
  82. package/dist/lib/update-steps.js +119 -1
  83. package/dist/lib/update-steps.js.map +1 -1
  84. package/dist/lib/update.d.ts +8 -0
  85. package/dist/lib/update.d.ts.map +1 -1
  86. package/dist/lib/update.js +36 -4
  87. package/dist/lib/update.js.map +1 -1
  88. package/dist/lib/version.d.ts +1 -1
  89. package/dist/lib/version.js +1 -1
  90. package/dist/shell/commands/db.d.ts +1 -0
  91. package/dist/shell/commands/db.d.ts.map +1 -1
  92. package/dist/shell/commands/db.js +18 -0
  93. package/dist/shell/commands/db.js.map +1 -1
  94. package/dist/shell/commands/registry.d.ts.map +1 -1
  95. package/dist/shell/commands/registry.js +3 -1
  96. package/dist/shell/commands/registry.js.map +1 -1
  97. package/dist/shell/commands/show.d.ts +1 -0
  98. package/dist/shell/commands/show.d.ts.map +1 -1
  99. package/dist/shell/commands/show.js +37 -1
  100. package/dist/shell/commands/show.js.map +1 -1
  101. package/dist/ui/components/PostgresPerformanceLines.d.ts +7 -0
  102. package/dist/ui/components/PostgresPerformanceLines.d.ts.map +1 -0
  103. package/dist/ui/components/PostgresPerformanceLines.js +7 -0
  104. package/dist/ui/components/PostgresPerformanceLines.js.map +1 -0
  105. package/dist/ui/components/index.d.ts +1 -0
  106. package/dist/ui/components/index.d.ts.map +1 -1
  107. package/dist/ui/components/index.js +1 -0
  108. package/dist/ui/components/index.js.map +1 -1
  109. package/dist/ui/views/DbBackupView.d.ts.map +1 -1
  110. package/dist/ui/views/DbBackupView.js +11 -27
  111. package/dist/ui/views/DbBackupView.js.map +1 -1
  112. package/dist/ui/views/DbHealthView.d.ts.map +1 -1
  113. package/dist/ui/views/DbHealthView.js +10 -3
  114. package/dist/ui/views/DbHealthView.js.map +1 -1
  115. package/dist/ui/views/DbStatusView.d.ts.map +1 -1
  116. package/dist/ui/views/DbStatusView.js +5 -3
  117. package/dist/ui/views/DbStatusView.js.map +1 -1
  118. package/dist/ui/views/DiagDatabaseView.d.ts.map +1 -1
  119. package/dist/ui/views/DiagDatabaseView.js +3 -1
  120. package/dist/ui/views/DiagDatabaseView.js.map +1 -1
  121. package/dist/ui/views/DiagShowTechView.d.ts +3 -1
  122. package/dist/ui/views/DiagShowTechView.d.ts.map +1 -1
  123. package/dist/ui/views/DiagShowTechView.js +3 -3
  124. package/dist/ui/views/DiagShowTechView.js.map +1 -1
  125. package/dist/ui/views/HealthReportView.d.ts +6 -0
  126. package/dist/ui/views/HealthReportView.d.ts.map +1 -0
  127. package/dist/ui/views/HealthReportView.js +82 -0
  128. package/dist/ui/views/HealthReportView.js.map +1 -0
  129. package/dist/ui/views/MainMenu.d.ts.map +1 -1
  130. package/dist/ui/views/MainMenu.js +4 -1
  131. package/dist/ui/views/MainMenu.js.map +1 -1
  132. package/dist/ui/views/MigrateDrainView.d.ts +6 -0
  133. package/dist/ui/views/MigrateDrainView.d.ts.map +1 -0
  134. package/dist/ui/views/MigrateDrainView.js +77 -0
  135. package/dist/ui/views/MigrateDrainView.js.map +1 -0
  136. package/dist/ui/views/MigrateStatusView.d.ts.map +1 -1
  137. package/dist/ui/views/MigrateStatusView.js +16 -7
  138. package/dist/ui/views/MigrateStatusView.js.map +1 -1
  139. package/dist/ui/views/MigrateWatchView.d.ts.map +1 -1
  140. package/dist/ui/views/MigrateWatchView.js +17 -12
  141. package/dist/ui/views/MigrateWatchView.js.map +1 -1
  142. package/package.json +1 -1
@@ -0,0 +1,80 @@
1
+ import { readdir, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { composeExec, composeExecToFile } from './compose.js';
4
+ import { DB_NAME, DB_USER, PG_ENV } from './db.js';
5
+ import { mkdirSafe, removeSafe } from './fs.js';
6
+ import { getPaths } from './paths.js';
7
+ export function databaseBackupTimestamp(date = new Date()) {
8
+ return date.toISOString().replace(/[:.]/g, '-').slice(0, 19);
9
+ }
10
+ export function databaseBackupPath(timestamp = databaseBackupTimestamp()) {
11
+ const { dbDumpsDir } = getPaths();
12
+ const fileName = `dump-${timestamp}.sql`;
13
+ return {
14
+ directory: dbDumpsDir,
15
+ fileName,
16
+ filePath: join(dbDumpsDir, fileName),
17
+ };
18
+ }
19
+ export async function ensureDatabaseBackupDirectory() {
20
+ const { dbDumpsDir } = getPaths();
21
+ await mkdirSafe(dbDumpsDir);
22
+ return dbDumpsDir;
23
+ }
24
+ export async function assertDatabaseReady() {
25
+ await composeExec('db', ['pg_isready', '-U', DB_USER, '-d', DB_NAME], { pipe: true });
26
+ }
27
+ export async function writeDatabaseDump(filePath) {
28
+ await composeExecToFile('db', [
29
+ 'sh',
30
+ '-lc',
31
+ 'IFS= read -r PGPASSWORD; export PGPASSWORD; pg_dump -U "$1" -d "$2"',
32
+ 'pg_dump',
33
+ DB_USER,
34
+ DB_NAME,
35
+ ], filePath, { stdin: `${PG_ENV.PGPASSWORD}\n` });
36
+ const written = await stat(filePath);
37
+ if (written.size === 0) {
38
+ await removeSafe(filePath);
39
+ throw new Error('pg_dump returned empty output');
40
+ }
41
+ }
42
+ export async function cleanupOldDatabaseBackups(keep = 5) {
43
+ const parsedKeep = Number.isFinite(keep) ? Math.trunc(keep) : 1;
44
+ const safeKeep = Math.max(1, parsedKeep);
45
+ const { dbDumpsDir } = getPaths();
46
+ let entries;
47
+ try {
48
+ entries = await readdir(dbDumpsDir);
49
+ }
50
+ catch (err) {
51
+ if (err?.code === 'ENOENT')
52
+ return 0;
53
+ throw err;
54
+ }
55
+ const files = (await Promise.all(entries
56
+ .filter(f => /^dump-.*\.sql$/.test(f))
57
+ .map(async (name) => {
58
+ try {
59
+ return { name, time: (await stat(join(dbDumpsDir, name))).mtimeMs };
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }))).filter((file) => file !== null);
65
+ files.sort((a, b) => b.time - a.time);
66
+ const removed = files.slice(safeKeep);
67
+ for (const f of removed) {
68
+ await removeSafe(join(dbDumpsDir, f.name));
69
+ }
70
+ return removed.length;
71
+ }
72
+ export async function createDatabaseBackup(options = {}) {
73
+ const backup = databaseBackupPath(databaseBackupTimestamp(options.timestamp));
74
+ await ensureDatabaseBackupDirectory();
75
+ await assertDatabaseReady();
76
+ await writeDatabaseDump(backup.filePath);
77
+ const removedCount = await cleanupOldDatabaseBackups(options.keep ?? 5);
78
+ return { ...backup, removedCount };
79
+ }
80
+ //# sourceMappingURL=db-backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-backup.js","sourceRoot":"","sources":["../../src/lib/db-backup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { type DiskCheckSeriesResult } from './hardware.js';
2
+ import { getNetworkInterfaceList, getPlatformInfo } from './network.js';
3
+ import { type PostgresPerformance } from './postgres-performance.js';
4
+ import { type AppHealthDetail } from './rpc.js';
5
+ import { type ServiceInfo } from './services.js';
6
+ import { type SystemMetrics } from './system.js';
7
+ export type HealthReportStatus = 'ok' | 'warn' | 'fail' | 'unavailable' | 'skipped';
8
+ export type HealthReportOverallStatus = 'ok' | 'warn' | 'fail';
9
+ export interface HealthReportFinding {
10
+ status: HealthReportStatus;
11
+ label: string;
12
+ detail?: string;
13
+ recommendation?: string;
14
+ }
15
+ export interface HealthReportSection<TData = unknown> {
16
+ id: string;
17
+ title: string;
18
+ status: HealthReportStatus;
19
+ durationMs: number;
20
+ findings: HealthReportFinding[];
21
+ data?: TData;
22
+ }
23
+ export interface HealthReportSummary {
24
+ status: HealthReportOverallStatus;
25
+ failures: number;
26
+ warnings: number;
27
+ unavailable: number;
28
+ skipped: number;
29
+ sections: number;
30
+ recommendations: string[];
31
+ }
32
+ export interface DiskUsageRecord {
33
+ path: string;
34
+ filesystem: string;
35
+ sizeBytes: number;
36
+ usedBytes: number;
37
+ availableBytes: number;
38
+ usedPercent: number;
39
+ mount: string;
40
+ inodeUsedPercent?: number;
41
+ }
42
+ export interface DatabaseHealthData {
43
+ ready: boolean;
44
+ databaseSize: string | null;
45
+ activeConnections: number | null;
46
+ migrationCount: number | null;
47
+ latestMigration: string | null;
48
+ }
49
+ export interface HealthReport {
50
+ schemaVersion: 1;
51
+ reportId: string;
52
+ generatedAt: string;
53
+ cliVersion: string;
54
+ hostname: string;
55
+ platform: ReturnType<typeof getPlatformInfo>;
56
+ deploymentMode: string;
57
+ installDir: string;
58
+ options: {
59
+ includeDiskBenchmark: boolean;
60
+ };
61
+ summary: HealthReportSummary;
62
+ sections: {
63
+ system: HealthReportSection<SystemMetrics>;
64
+ diskUsage: HealthReportSection<DiskUsageRecord[]>;
65
+ diskBenchmark: HealthReportSection<DiskCheckSeriesResult | null>;
66
+ containers: HealthReportSection<ServiceInfo[]>;
67
+ appHealth: HealthReportSection<AppHealthDetail | null>;
68
+ database: HealthReportSection<DatabaseHealthData | null>;
69
+ postgresPerformance: HealthReportSection<PostgresPerformance | null>;
70
+ network: HealthReportSection<{
71
+ hostname: string;
72
+ gateway: string | null;
73
+ interfaces: ReturnType<typeof getNetworkInterfaceList>;
74
+ }>;
75
+ };
76
+ }
77
+ export interface BuildHealthReportOptions {
78
+ includeDiskBenchmark?: boolean;
79
+ diskBenchmark?: {
80
+ directory?: string;
81
+ size?: string;
82
+ runtimeSec?: number;
83
+ sampleCount?: number;
84
+ };
85
+ reportId?: string;
86
+ generatedAt?: string;
87
+ }
88
+ export declare function buildHealthReport(options?: BuildHealthReportOptions): Promise<HealthReport>;
89
+ export declare function renderHealthReportText(report: HealthReport): string;
90
+ export declare function defaultHealthReportJsonPath(report: HealthReport): string;
91
+ export declare function writeHealthReportJson(report: HealthReport, path?: string): Promise<string>;
92
+ export declare function writeHealthReportText(report: HealthReport, path: string): Promise<string>;
93
+ //# sourceMappingURL=health-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-report.d.ts","sourceRoot":"","sources":["../../src/lib/health-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,391 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { dirname, join } from 'node:path';
4
+ import { uptime as osUptime } from 'node:os';
5
+ import { execa } from 'execa';
6
+ import { VERSION } from './version.js';
7
+ import { composeExec } from './compose.js';
8
+ import { DB_NAME, DB_USER, PG_ENV } from './db.js';
9
+ import { detectDeploymentMode } from './deployment.js';
10
+ import { DEFAULT_DISK_CHECK_DIRECTORY, DEFAULT_DISK_CHECK_SIZE, formatBandwidth, formatIops, runDiskCheckSeries, } from './hardware.js';
11
+ import { getNetworkInterfaceList, getDefaultGateway, getPlatformInfo, getSystemHostname } from './network.js';
12
+ import { getPaths } from './paths.js';
13
+ import { fetchPostgresPerformance, postgresPerformanceLines } from './postgres-performance.js';
14
+ import { redactSecrets } from './redact.js';
15
+ import { getAppHealth } from './rpc.js';
16
+ import { getServiceListSafe } from './services.js';
17
+ import { formatBytes, getDockerVersion, getSystemMetrics } from './system.js';
18
+ const HEALTH_DISK_RUNTIME_SEC = 1;
19
+ const HEALTH_DISK_SAMPLE_COUNT = 3;
20
+ const RANK = {
21
+ skipped: 0,
22
+ ok: 1,
23
+ unavailable: 2,
24
+ warn: 3,
25
+ fail: 4,
26
+ };
27
+ function statusRank(status) {
28
+ return RANK[status];
29
+ }
30
+ function rollupFindings(findings) {
31
+ if (findings.length === 0)
32
+ return 'unavailable';
33
+ if (findings.every((finding) => finding.status === 'skipped'))
34
+ return 'skipped';
35
+ return findings.reduce((current, finding) => statusRank(finding.status) > statusRank(current) ? finding.status : current, 'ok');
36
+ }
37
+ function overallFromSections(sections) {
38
+ if (sections.some((section) => section.status === 'fail'))
39
+ return 'fail';
40
+ if (sections.some((section) => section.status === 'warn' || section.status === 'unavailable'))
41
+ return 'warn';
42
+ return 'ok';
43
+ }
44
+ async function timedSection(id, title, run) {
45
+ const start = Date.now();
46
+ try {
47
+ const result = await run();
48
+ return {
49
+ id,
50
+ title,
51
+ status: rollupFindings(result.findings),
52
+ durationMs: Date.now() - start,
53
+ findings: result.findings,
54
+ data: result.data,
55
+ };
56
+ }
57
+ catch (err) {
58
+ return {
59
+ id,
60
+ title,
61
+ status: 'unavailable',
62
+ durationMs: Date.now() - start,
63
+ findings: [{
64
+ status: 'unavailable',
65
+ label: title,
66
+ detail: redactSecrets(err.message ?? String(err)),
67
+ recommendation: 'Run ct diag showtech and share the bundle with support if this persists.',
68
+ }],
69
+ };
70
+ }
71
+ }
72
+ function simpleFinding(status, label, detail, recommendation) {
73
+ return { status, label, detail: detail ? redactSecrets(detail) : undefined, recommendation };
74
+ }
75
+ function pctStatus(percent, warnAt, failAt) {
76
+ if (percent >= failAt)
77
+ return 'fail';
78
+ if (percent >= warnAt)
79
+ return 'warn';
80
+ return 'ok';
81
+ }
82
+ function statusFromBool(ok, label, okDetail, failDetail, recommendation) {
83
+ return simpleFinding(ok ? 'ok' : 'fail', label, ok ? okDetail : failDetail, ok ? undefined : recommendation);
84
+ }
85
+ function parseMaybeNumber(value) {
86
+ const parsed = Number(value.trim());
87
+ return Number.isFinite(parsed) ? parsed : null;
88
+ }
89
+ async function psqlTerse(sql) {
90
+ const result = await composeExec('db', ['psql', '-U', DB_USER, '-d', DB_NAME, '-t', '-A', '-c', sql], { env: PG_ENV, pipe: true });
91
+ return (result.stdout ?? '').trim();
92
+ }
93
+ async function readDiskUsage(path) {
94
+ const [{ stdout: usageOut }, inodeResult] = await Promise.all([
95
+ execa('df', ['-Pk', path], { stdout: 'pipe', stderr: 'pipe' }),
96
+ execa('df', ['-Pi', path], { stdout: 'pipe', stderr: 'pipe' }).catch(() => null),
97
+ ]);
98
+ const lines = usageOut.trim().split('\n');
99
+ const parts = lines[1]?.trim().split(/\s+/);
100
+ if (!parts || parts.length < 6) {
101
+ throw new Error(`Could not parse disk usage for ${path}`);
102
+ }
103
+ let inodeUsedPercent;
104
+ if (inodeResult) {
105
+ const inodeParts = inodeResult.stdout.trim().split('\n')[1]?.trim().split(/\s+/);
106
+ const inodePct = inodeParts?.find((part) => part.endsWith('%'));
107
+ if (inodePct)
108
+ inodeUsedPercent = Number(inodePct.replace('%', ''));
109
+ }
110
+ return {
111
+ path,
112
+ filesystem: parts[0],
113
+ sizeBytes: Number(parts[1]) * 1024,
114
+ usedBytes: Number(parts[2]) * 1024,
115
+ availableBytes: Number(parts[3]) * 1024,
116
+ usedPercent: Number(parts[4].replace('%', '')),
117
+ mount: parts.slice(5).join(' '),
118
+ inodeUsedPercent,
119
+ };
120
+ }
121
+ async function collectSystemSection() {
122
+ return timedSection('system', 'System Resources', async () => {
123
+ const [metrics, dockerVersion] = await Promise.all([
124
+ getSystemMetrics(),
125
+ getDockerVersion().catch(() => null),
126
+ ]);
127
+ const findings = [
128
+ simpleFinding(pctStatus(metrics.cpu.percent, 85, 125), 'CPU load', `${metrics.cpu.label} (${metrics.cpu.percent}% of cores)`, metrics.cpu.percent >= 125 ? 'Sustained CPU saturation can delay ingestion and alert processing.' : undefined),
129
+ simpleFinding(pctStatus(metrics.ram.percent, 85, 95), 'RAM usage', `${metrics.ram.label} (${metrics.ram.percent}% used)`, metrics.ram.percent >= 95 ? 'Reduce load or increase appliance memory.' : undefined),
130
+ simpleFinding(metrics.swap ? pctStatus(metrics.swap.percent, 50, 80) : 'ok', 'Swap usage', metrics.swap ? `${metrics.swap.label} (${metrics.swap.percent}% used)` : 'no swap configured', metrics.swap && metrics.swap.percent >= 80 ? 'High swap usage can cause database latency and missed ingest windows.' : undefined),
131
+ simpleFinding(dockerVersion && dockerVersion >= 24 ? 'ok' : 'warn', 'Docker version', dockerVersion ? `major ${dockerVersion}` : 'unavailable', dockerVersion && dockerVersion < 24 ? 'Upgrade Docker during the next maintenance window.' : undefined),
132
+ simpleFinding('ok', 'System uptime', `${Math.floor(osUptime() / 60)} minutes`),
133
+ ];
134
+ return { findings, data: metrics };
135
+ });
136
+ }
137
+ async function collectDiskUsageSection() {
138
+ return timedSection('disk_usage', 'Disk Usage', async () => {
139
+ const paths = getPaths();
140
+ const targets = [...new Set(['/', paths.installDir, paths.postgresDataDir].filter(Boolean))];
141
+ const settled = await Promise.allSettled(targets.map((target) => readDiskUsage(target)));
142
+ const records = settled
143
+ .filter((result) => result.status === 'fulfilled')
144
+ .map((result) => result.value);
145
+ const findings = [];
146
+ for (const record of records) {
147
+ findings.push(simpleFinding(pctStatus(record.usedPercent, 80, 90), `Disk ${record.path}`, `${formatBytes(record.usedBytes)}/${formatBytes(record.sizeBytes)} used (${record.usedPercent}%), ${formatBytes(record.availableBytes)} free`, record.usedPercent >= 90 ? 'Free disk space before ingestion, database writes, or WAL growth are affected.' : undefined));
148
+ if (record.inodeUsedPercent !== undefined) {
149
+ findings.push(simpleFinding(pctStatus(record.inodeUsedPercent, 80, 90), `Inodes ${record.path}`, `${record.inodeUsedPercent}% used`, record.inodeUsedPercent >= 90 ? 'Clean up small files or expand the filesystem inode capacity.' : undefined));
150
+ }
151
+ }
152
+ for (const [index, result] of settled.entries()) {
153
+ if (result.status === 'rejected') {
154
+ findings.push(simpleFinding('unavailable', `Disk ${targets[index]}`, result.reason?.message ?? String(result.reason)));
155
+ }
156
+ }
157
+ return { findings, data: records };
158
+ });
159
+ }
160
+ function average(values) {
161
+ if (values.length === 0)
162
+ return 0;
163
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
164
+ }
165
+ async function collectDiskBenchmarkSection(options) {
166
+ return timedSection('disk_benchmark', 'Disk Benchmark', async () => {
167
+ if (options.includeDiskBenchmark === false) {
168
+ return {
169
+ data: null,
170
+ findings: [simpleFinding('skipped', 'fio benchmark', 'skipped by option', 'Run ct health report without --skip-disk-benchmark for active disk speed data.')],
171
+ };
172
+ }
173
+ const result = await runDiskCheckSeries({
174
+ directory: options.diskBenchmark?.directory ?? DEFAULT_DISK_CHECK_DIRECTORY,
175
+ size: options.diskBenchmark?.size ?? DEFAULT_DISK_CHECK_SIZE,
176
+ runtimeSec: options.diskBenchmark?.runtimeSec ?? HEALTH_DISK_RUNTIME_SEC,
177
+ sampleCount: options.diskBenchmark?.sampleCount ?? HEALTH_DISK_SAMPLE_COUNT,
178
+ });
179
+ const randomRead = average(result.randomReadIopsHistory);
180
+ const randomWrite = average(result.randomWriteIopsHistory);
181
+ const sequentialRead = average(result.sequentialReadBandwidthHistory);
182
+ const sequentialWrite = average(result.sequentialWriteBandwidthHistory);
183
+ const mibWrite = sequentialWrite / (1024 * 1024);
184
+ return {
185
+ data: result,
186
+ findings: [
187
+ simpleFinding(randomRead < 500 ? 'fail' : randomRead < 1500 ? 'warn' : 'ok', 'Random read IOPS', formatIops(randomRead), randomRead < 1500 ? 'Low random read IOPS can slow report queries and database maintenance.' : undefined),
188
+ simpleFinding(randomWrite < 500 ? 'fail' : randomWrite < 1500 ? 'warn' : 'ok', 'Random write IOPS', formatIops(randomWrite), randomWrite < 1500 ? 'Low random write IOPS can increase WAL and ingest latency.' : undefined),
189
+ simpleFinding(mibWrite < 50 ? 'fail' : mibWrite < 150 ? 'warn' : 'ok', 'Sequential write bandwidth', formatBandwidth(sequentialWrite), mibWrite < 150 ? 'Slow sequential writes can make backups, restores, and WAL flushes risky.' : undefined),
190
+ simpleFinding('ok', 'Sequential read bandwidth', formatBandwidth(sequentialRead)),
191
+ ],
192
+ };
193
+ });
194
+ }
195
+ async function collectContainersSection() {
196
+ return timedSection('containers', 'Containers', async () => {
197
+ const result = await getServiceListSafe();
198
+ if (result.error) {
199
+ return {
200
+ data: [],
201
+ findings: [simpleFinding('unavailable', 'Docker Compose services', result.error)],
202
+ };
203
+ }
204
+ const findings = result.services.map((service) => {
205
+ const running = service.state === 'running';
206
+ const unhealthy = service.health === 'unhealthy';
207
+ const status = !running || unhealthy ? 'fail' : 'ok';
208
+ const detail = `${service.state}${service.health ? ` (${service.health})` : ''}${service.status ? ` - ${service.status}` : ''}`;
209
+ return simpleFinding(status, service.service, detail, status === 'fail' ? `Inspect logs for ${service.service} and restart the service if needed.` : undefined);
210
+ });
211
+ if (findings.length === 0) {
212
+ findings.push(simpleFinding('unavailable', 'Docker Compose services', 'no services returned'));
213
+ }
214
+ return { findings, data: result.services };
215
+ });
216
+ }
217
+ async function collectAppHealthSection() {
218
+ return timedSection('app_health', 'Application Health', async () => {
219
+ const health = await getAppHealth();
220
+ const findings = [
221
+ statusFromBool(health.api, 'Admin API', 'responding', health.apiError ?? 'not responding'),
222
+ statusFromBool(health.curri, 'CURRI/XCC API', 'responding', health.curriError ?? 'not responding'),
223
+ statusFromBool(health.rpc, 'Elixir RPC', 'connected', health.rpcError ?? 'not connected'),
224
+ statusFromBool(health.dbConnected, 'Ecto DB pool', 'connected', health.dbError ?? 'not connected'),
225
+ statusFromBool(health.dbDirect, 'Direct PostgreSQL', 'accepting connections', health.dbDirectError ?? 'not accepting connections'),
226
+ statusFromBool(health.adminProxy, 'Admin HTTPS proxy', 'responding', health.adminProxyError ?? 'not responding'),
227
+ statusFromBool(health.curriProxy, 'CURRI HTTP proxy', 'responding', health.curriProxyError ?? 'not responding'),
228
+ statusFromBool(health.sftp, 'CDR SFTP', 'running', health.sftpError ?? 'not running'),
229
+ ];
230
+ return { findings, data: health };
231
+ });
232
+ }
233
+ async function collectDatabaseSection() {
234
+ return timedSection('database', 'Database', async () => {
235
+ const readyResult = await composeExec('db', ['pg_isready', '-U', DB_USER, '-d', DB_NAME], { pipe: true })
236
+ .then(() => true)
237
+ .catch(() => false);
238
+ const [size, connections, migrationCount, latestMigration] = await Promise.all([
239
+ psqlTerse('SELECT pg_size_pretty(pg_database_size(current_database()));').catch(() => null),
240
+ psqlTerse(`SELECT count(*) FROM pg_stat_activity WHERE datname = current_database();`).then(parseMaybeNumber).catch(() => null),
241
+ psqlTerse('SELECT count(*) FROM schema_migrations;').then(parseMaybeNumber).catch(() => null),
242
+ psqlTerse('SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;').catch(() => null),
243
+ ]);
244
+ const data = {
245
+ ready: readyResult,
246
+ databaseSize: size,
247
+ activeConnections: connections,
248
+ migrationCount,
249
+ latestMigration,
250
+ };
251
+ const findings = [
252
+ statusFromBool(readyResult, 'PostgreSQL readiness', 'pg_isready accepted', 'pg_isready failed'),
253
+ simpleFinding(size ? 'ok' : 'unavailable', 'Database size', size ?? 'unavailable'),
254
+ simpleFinding(connections !== null ? 'ok' : 'unavailable', 'Active connections', connections !== null ? String(connections) : 'unavailable'),
255
+ simpleFinding(migrationCount !== null ? 'ok' : 'warn', 'Applied migrations', migrationCount !== null ? String(migrationCount) : 'unavailable'),
256
+ simpleFinding(latestMigration ? 'ok' : 'warn', 'Latest migration', latestMigration ?? 'unavailable'),
257
+ ];
258
+ return { findings, data };
259
+ });
260
+ }
261
+ async function collectPostgresPerformanceSection() {
262
+ return timedSection('postgres_performance', 'PostgreSQL Performance', async () => {
263
+ const performance = await fetchPostgresPerformance();
264
+ const findings = postgresPerformanceLines(performance).map((line) => ({
265
+ status: line.status === 'info' ? 'ok' : line.status,
266
+ label: line.label,
267
+ detail: line.value,
268
+ recommendation: line.status === 'fail'
269
+ ? 'Review PostgreSQL timing settings, disk IO, and WAL latency alarms.'
270
+ : line.status === 'warn'
271
+ ? 'Monitor this metric and correlate it with ingest or query latency.'
272
+ : undefined,
273
+ }));
274
+ return { findings, data: performance };
275
+ });
276
+ }
277
+ async function collectNetworkSection() {
278
+ return timedSection('network', 'Network', async () => {
279
+ const [gateway, interfaces] = await Promise.all([
280
+ getDefaultGateway().catch(() => null),
281
+ Promise.resolve(getNetworkInterfaceList()),
282
+ ]);
283
+ const external = interfaces.filter((iface) => !iface.internal);
284
+ const externalV4 = external.filter((iface) => iface.family === 'IPv4');
285
+ const hostname = getSystemHostname();
286
+ return {
287
+ data: { hostname, gateway, interfaces },
288
+ findings: [
289
+ simpleFinding(hostname ? 'ok' : 'warn', 'Hostname', hostname || 'unavailable'),
290
+ simpleFinding(gateway ? 'ok' : 'warn', 'Default gateway', gateway ?? 'unavailable'),
291
+ simpleFinding(external.length > 0 ? 'ok' : 'warn', 'Network interfaces', `${external.length} non-loopback interfaces`),
292
+ simpleFinding(externalV4.length > 0 ? 'ok' : 'warn', 'IPv4 addresses', `${externalV4.length} non-loopback IPv4 addresses`),
293
+ ],
294
+ };
295
+ });
296
+ }
297
+ function summarize(sections) {
298
+ const allFindings = sections.flatMap((section) => section.findings);
299
+ const recommendations = [...new Set(allFindings
300
+ .map((finding) => finding.recommendation)
301
+ .filter((value) => Boolean(value)))];
302
+ return {
303
+ status: overallFromSections(sections),
304
+ failures: allFindings.filter((finding) => finding.status === 'fail').length,
305
+ warnings: allFindings.filter((finding) => finding.status === 'warn').length,
306
+ unavailable: allFindings.filter((finding) => finding.status === 'unavailable').length,
307
+ skipped: allFindings.filter((finding) => finding.status === 'skipped').length,
308
+ sections: sections.length,
309
+ recommendations,
310
+ };
311
+ }
312
+ export async function buildHealthReport(options = {}) {
313
+ const paths = getPaths();
314
+ const generatedAt = options.generatedAt ?? new Date().toISOString();
315
+ const reportId = options.reportId ?? `health-${generatedAt.replace(/[^0-9]/g, '').slice(0, 14)}-${randomUUID().slice(0, 8)}`;
316
+ const [system, diskUsage, diskBenchmark, containers, appHealth, database, postgresPerformance, network,] = await Promise.all([
317
+ collectSystemSection(),
318
+ collectDiskUsageSection(),
319
+ collectDiskBenchmarkSection(options),
320
+ collectContainersSection(),
321
+ collectAppHealthSection(),
322
+ collectDatabaseSection(),
323
+ collectPostgresPerformanceSection(),
324
+ collectNetworkSection(),
325
+ ]);
326
+ const sections = {
327
+ system,
328
+ diskUsage,
329
+ diskBenchmark,
330
+ containers,
331
+ appHealth,
332
+ database,
333
+ postgresPerformance,
334
+ network,
335
+ };
336
+ return {
337
+ schemaVersion: 1,
338
+ reportId,
339
+ generatedAt,
340
+ cliVersion: VERSION,
341
+ hostname: getSystemHostname(),
342
+ platform: getPlatformInfo(),
343
+ deploymentMode: detectDeploymentMode(),
344
+ installDir: paths.installDir,
345
+ options: {
346
+ includeDiskBenchmark: options.includeDiskBenchmark !== false,
347
+ },
348
+ summary: summarize(Object.values(sections)),
349
+ sections,
350
+ };
351
+ }
352
+ export function renderHealthReportText(report) {
353
+ const lines = [
354
+ `CallTelemetry Health Report`,
355
+ `Report ID: ${report.reportId}`,
356
+ `Generated: ${report.generatedAt}`,
357
+ `Hostname: ${report.hostname}`,
358
+ `CLI Version: ${report.cliVersion}`,
359
+ `Deployment: ${report.deploymentMode}`,
360
+ `Overall: ${report.summary.status.toUpperCase()} (${report.summary.failures} fail, ${report.summary.warnings} warn, ${report.summary.unavailable} unavailable, ${report.summary.skipped} skipped)`,
361
+ '',
362
+ 'Sections:',
363
+ ];
364
+ for (const section of Object.values(report.sections)) {
365
+ lines.push(`- [${section.status.toUpperCase()}] ${section.title} (${section.durationMs}ms)`);
366
+ for (const finding of section.findings) {
367
+ lines.push(` - [${finding.status.toUpperCase()}] ${finding.label}${finding.detail ? `: ${finding.detail}` : ''}`);
368
+ }
369
+ }
370
+ if (report.summary.recommendations.length > 0) {
371
+ lines.push('', 'Recommendations:');
372
+ for (const recommendation of report.summary.recommendations) {
373
+ lines.push(`- ${recommendation}`);
374
+ }
375
+ }
376
+ return `${lines.join('\n')}\n`;
377
+ }
378
+ export function defaultHealthReportJsonPath(report) {
379
+ return join(getPaths().installDir, `${report.reportId}.json`);
380
+ }
381
+ export async function writeHealthReportJson(report, path = defaultHealthReportJsonPath(report)) {
382
+ await mkdir(dirname(path), { recursive: true });
383
+ await writeFile(path, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
384
+ return path;
385
+ }
386
+ export async function writeHealthReportText(report, path) {
387
+ await mkdir(dirname(path), { recursive: true });
388
+ await writeFile(path, renderHealthReportText(report), 'utf8');
389
+ return path;
390
+ }
391
+ //# sourceMappingURL=health-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-report.js","sourceRoot":"","sources":["../../src/lib/health-report.ts"],"names":[],"mappings":"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"}