@amiable-dev/docusaurus-plugin-stentorosaur 0.16.3 → 0.17.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 +72 -1
- package/lib/hooks/index.d.ts +2 -1
- package/lib/hooks/index.d.ts.map +1 -1
- package/lib/hooks/index.js +4 -2
- package/lib/hooks/useDailySummary.d.ts +38 -0
- package/lib/hooks/useDailySummary.d.ts.map +1 -0
- package/lib/hooks/useDailySummary.js +194 -0
- package/lib/theme/StatusItem/MiniHeatmap.d.ts +1 -1
- package/lib/theme/StatusItem/MiniHeatmap.d.ts.map +1 -1
- package/lib/theme/StatusItem/MiniHeatmap.js +1 -1
- package/lib/theme/StatusItem/index.d.ts +5 -1
- package/lib/theme/StatusItem/index.d.ts.map +1 -1
- package/lib/theme/StatusItem/index.js +58 -2
- package/lib/theme/StatusPage/index.d.ts.map +1 -1
- package/lib/theme/StatusPage/index.js +6 -2
- package/lib/types.d.ts +40 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -2
- package/scripts/bootstrap-summary.js +252 -0
- package/scripts/monitor.js +173 -1
- package/tsconfig.tsbuildinfo +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A Docusaurus plugin that creates an Upptime-like status monitoring dashboard pow
|
|
|
16
16
|
- Bar charts and heatmaps for uptime visualization
|
|
17
17
|
- Multiple time period views (24h, 7d, 30d, 90d)
|
|
18
18
|
- Automatic dark/light theme support
|
|
19
|
-
- Mini heatmaps on system cards:
|
|
19
|
+
- Mini heatmaps on system cards: 14-day default, expandable to 90-day with daily-summary.json
|
|
20
20
|
- Extensible annotation system: Display maintenance windows and incidents as chart annotations
|
|
21
21
|
- Markdown rendering support: Full GitHub-flavored markdown in incident and maintenance descriptions
|
|
22
22
|
- 💾 **Dataset Download**: Export chart data for offline analysis
|
|
@@ -955,6 +955,7 @@ The plugin uses an **append-only monitoring architecture** that eliminates Git h
|
|
|
955
955
|
```text
|
|
956
956
|
status-data/ # Committed to Git
|
|
957
957
|
├── current.json # Hot file (rolling 14-day window)
|
|
958
|
+
├── daily-summary.json # 90-day aggregated stats (v0.17.0+)
|
|
958
959
|
└── archives/
|
|
959
960
|
└── 2025/11/
|
|
960
961
|
├── history-2025-11-01.jsonl.gz # Compressed (yesterday and older)
|
|
@@ -962,6 +963,76 @@ status-data/ # Committed to Git
|
|
|
962
963
|
└── history-2025-11-03.jsonl # Uncompressed (today)
|
|
963
964
|
```
|
|
964
965
|
|
|
966
|
+
### Historical Data Aggregation (v0.17.0+)
|
|
967
|
+
|
|
968
|
+
The plugin supports **90-day heatmap visualization** through a daily summary file that aggregates historical data from archives.
|
|
969
|
+
|
|
970
|
+
**The Problem:** The 90-day heatmap was 84% empty because it relied only on `current.json` (14-day rolling window), ignoring the archived historical data.
|
|
971
|
+
|
|
972
|
+
**The Solution:** A `daily-summary.json` file is generated during each monitor run, aggregating daily stats from both `current.json` and archive files.
|
|
973
|
+
|
|
974
|
+
**Schema (v1):**
|
|
975
|
+
|
|
976
|
+
```json
|
|
977
|
+
{
|
|
978
|
+
"version": 1,
|
|
979
|
+
"lastUpdated": "2025-12-31T22:00:00Z",
|
|
980
|
+
"windowDays": 90,
|
|
981
|
+
"services": {
|
|
982
|
+
"api": [
|
|
983
|
+
{
|
|
984
|
+
"date": "2025-12-30",
|
|
985
|
+
"uptimePct": 0.998,
|
|
986
|
+
"avgLatencyMs": 145,
|
|
987
|
+
"p95LatencyMs": 320,
|
|
988
|
+
"checksTotal": 144,
|
|
989
|
+
"checksPassed": 143,
|
|
990
|
+
"incidentCount": 0
|
|
991
|
+
}
|
|
992
|
+
]
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
**Key Features:**
|
|
998
|
+
|
|
999
|
+
- **Hybrid Read Pattern**: Today's live data from `current.json` is merged with historical data from `daily-summary.json`
|
|
1000
|
+
- **Automatic Generation**: The summary file is regenerated on every monitor run
|
|
1001
|
+
- **Atomic Writes**: Uses temp file + rename pattern to prevent corruption
|
|
1002
|
+
- **Efficient**: ~10KB for 2 services × 90 days (vs ~15MB if storing raw data)
|
|
1003
|
+
|
|
1004
|
+
**Bootstrap Existing Data:**
|
|
1005
|
+
|
|
1006
|
+
If you're upgrading from an older version, run the bootstrap script to generate the initial summary from existing archives:
|
|
1007
|
+
|
|
1008
|
+
```bash
|
|
1009
|
+
npx bootstrap-summary --output-dir status-data --window 90
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
**TypeScript Types:**
|
|
1013
|
+
|
|
1014
|
+
```typescript
|
|
1015
|
+
import { DailySummaryFile, DailySummaryEntry } from '@amiable-dev/docusaurus-plugin-stentorosaur';
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
**React Hook:**
|
|
1019
|
+
|
|
1020
|
+
```typescript
|
|
1021
|
+
import { useDailySummary } from '@amiable-dev/docusaurus-plugin-stentorosaur';
|
|
1022
|
+
|
|
1023
|
+
function MyComponent() {
|
|
1024
|
+
const { data, loading, error } = useDailySummary({
|
|
1025
|
+
baseUrl: '/status-data',
|
|
1026
|
+
serviceName: 'api',
|
|
1027
|
+
days: 90,
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
// data is DailySummaryEntry[] with merged today + historical data
|
|
1031
|
+
}
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
See [ADR-002](./docs/adrs/ADR-002-historical-data-aggregation.md) for detailed architecture documentation.
|
|
1035
|
+
|
|
965
1036
|
**Setup:**
|
|
966
1037
|
|
|
967
1038
|
```bash
|
package/lib/hooks/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ADR-001: Client-side hooks for status data
|
|
2
|
+
* ADR-001 & ADR-002: Client-side hooks for status data
|
|
3
3
|
*
|
|
4
4
|
* Export all React hooks for use in theme components.
|
|
5
5
|
*/
|
|
6
6
|
export { useStatusData, type UseStatusDataOptions, type UseStatusDataResult } from './useStatusData';
|
|
7
|
+
export { useDailySummary, type UseDailySummaryOptions, type UseDailySummaryResult } from './useDailySummary';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/hooks/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/lib/hooks/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* ADR-001: Client-side hooks for status data
|
|
3
|
+
* ADR-001 & ADR-002: Client-side hooks for status data
|
|
4
4
|
*
|
|
5
5
|
* Export all React hooks for use in theme components.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.useStatusData = void 0;
|
|
8
|
+
exports.useDailySummary = exports.useStatusData = void 0;
|
|
9
9
|
var useStatusData_1 = require("./useStatusData");
|
|
10
10
|
Object.defineProperty(exports, "useStatusData", { enumerable: true, get: function () { return useStatusData_1.useStatusData; } });
|
|
11
|
+
var useDailySummary_1 = require("./useDailySummary");
|
|
12
|
+
Object.defineProperty(exports, "useDailySummary", { enumerable: true, get: function () { return useDailySummary_1.useDailySummary; } });
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Your Organization
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { DailySummaryEntry } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* Options for useDailySummary hook
|
|
10
|
+
*/
|
|
11
|
+
export interface UseDailySummaryOptions {
|
|
12
|
+
/** Base URL for fetching data (e.g., '/status-data') */
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
/** Service name to get data for */
|
|
15
|
+
serviceName: string;
|
|
16
|
+
/** Number of days to return (default: 90) */
|
|
17
|
+
days?: number;
|
|
18
|
+
/** Whether to enable fetching (default: true) */
|
|
19
|
+
enabled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Result type for useDailySummary hook
|
|
23
|
+
*/
|
|
24
|
+
export interface UseDailySummaryResult {
|
|
25
|
+
/** Array of daily summary entries (null while loading) */
|
|
26
|
+
data: DailySummaryEntry[] | null;
|
|
27
|
+
/** Whether data is currently being fetched */
|
|
28
|
+
loading: boolean;
|
|
29
|
+
/** Error message if fetch failed */
|
|
30
|
+
error: string | null;
|
|
31
|
+
/** ISO timestamp of last data update */
|
|
32
|
+
lastUpdated: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Hook for fetching and merging daily summary data with live data
|
|
36
|
+
*/
|
|
37
|
+
export declare function useDailySummary(options: UseDailySummaryOptions): UseDailySummaryResult;
|
|
38
|
+
//# sourceMappingURL=useDailySummary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDailySummary.d.ts","sourceRoot":"","sources":["../../src/hooks/useDailySummary.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAcpE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0DAA0D;IAC1D,IAAI,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC;IACjC,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wCAAwC;IACxC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAwED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB,CA2HtF"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Your Organization
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.useDailySummary = useDailySummary;
|
|
10
|
+
/**
|
|
11
|
+
* ADR-002: useDailySummary Hook
|
|
12
|
+
*
|
|
13
|
+
* Implements the hybrid read pattern for 90-day heatmap data:
|
|
14
|
+
* - Fetches daily-summary.json and current.json in parallel
|
|
15
|
+
* - Merges today's live data with historical summary
|
|
16
|
+
* - Falls back gracefully when files are missing
|
|
17
|
+
*
|
|
18
|
+
* @see docs/adrs/ADR-002-historical-data-aggregation.md
|
|
19
|
+
*/
|
|
20
|
+
const react_1 = require("react");
|
|
21
|
+
/**
|
|
22
|
+
* Calculate p95 latency from an array of latency values
|
|
23
|
+
*/
|
|
24
|
+
function calculateP95(latencies) {
|
|
25
|
+
if (latencies.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
const sorted = [...latencies].sort((a, b) => a - b);
|
|
28
|
+
const index = Math.ceil(sorted.length * 0.95) - 1;
|
|
29
|
+
return sorted[Math.max(0, index)];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Aggregate readings for a specific day into a DailySummaryEntry
|
|
33
|
+
*/
|
|
34
|
+
function aggregateDayReadings(date, readings) {
|
|
35
|
+
const checksTotal = readings.length;
|
|
36
|
+
const checksPassed = readings.filter(r => r.state === 'up' || r.state === 'maintenance').length;
|
|
37
|
+
const uptimePct = checksTotal > 0 ? checksPassed / checksTotal : 0;
|
|
38
|
+
const latencies = readings
|
|
39
|
+
.filter(r => r.state === 'up')
|
|
40
|
+
.map(r => r.lat);
|
|
41
|
+
const avgLatencyMs = latencies.length > 0
|
|
42
|
+
? Math.round(latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length)
|
|
43
|
+
: null;
|
|
44
|
+
const p95LatencyMs = calculateP95(latencies);
|
|
45
|
+
// Count incidents (transitions from up to down)
|
|
46
|
+
let incidentCount = 0;
|
|
47
|
+
for (let i = 1; i < readings.length; i++) {
|
|
48
|
+
if (readings[i - 1].state === 'up' && readings[i].state === 'down') {
|
|
49
|
+
incidentCount++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
date,
|
|
54
|
+
uptimePct,
|
|
55
|
+
avgLatencyMs,
|
|
56
|
+
p95LatencyMs,
|
|
57
|
+
checksTotal,
|
|
58
|
+
checksPassed,
|
|
59
|
+
incidentCount,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Group readings by date (for aggregating current.json)
|
|
64
|
+
*/
|
|
65
|
+
function groupReadingsByDate(readings, serviceName) {
|
|
66
|
+
const groups = new Map();
|
|
67
|
+
const lowerServiceName = serviceName.toLowerCase();
|
|
68
|
+
for (const reading of readings) {
|
|
69
|
+
if (reading.svc.toLowerCase() !== lowerServiceName)
|
|
70
|
+
continue;
|
|
71
|
+
const date = new Date(reading.t).toISOString().split('T')[0];
|
|
72
|
+
if (!groups.has(date)) {
|
|
73
|
+
groups.set(date, []);
|
|
74
|
+
}
|
|
75
|
+
groups.get(date).push(reading);
|
|
76
|
+
}
|
|
77
|
+
return groups;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Hook for fetching and merging daily summary data with live data
|
|
81
|
+
*/
|
|
82
|
+
function useDailySummary(options) {
|
|
83
|
+
const { baseUrl, serviceName, days = 90, enabled = true } = options;
|
|
84
|
+
const [summaryData, setSummaryData] = (0, react_1.useState)(null);
|
|
85
|
+
const [currentData, setCurrentData] = (0, react_1.useState)(null);
|
|
86
|
+
const [loading, setLoading] = (0, react_1.useState)(enabled);
|
|
87
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
88
|
+
const [summaryFailed, setSummaryFailed] = (0, react_1.useState)(false);
|
|
89
|
+
const [currentFailed, setCurrentFailed] = (0, react_1.useState)(false);
|
|
90
|
+
(0, react_1.useEffect)(() => {
|
|
91
|
+
if (!enabled) {
|
|
92
|
+
setLoading(false);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
let cancelled = false;
|
|
96
|
+
async function fetchData() {
|
|
97
|
+
setLoading(true);
|
|
98
|
+
setError(null);
|
|
99
|
+
setSummaryFailed(false);
|
|
100
|
+
setCurrentFailed(false);
|
|
101
|
+
try {
|
|
102
|
+
// Fetch both files in parallel
|
|
103
|
+
const [summaryResponse, currentResponse] = await Promise.all([
|
|
104
|
+
fetch(`${baseUrl}/daily-summary.json`).catch(() => null),
|
|
105
|
+
fetch(`${baseUrl}/current.json`).catch(() => null),
|
|
106
|
+
]);
|
|
107
|
+
if (cancelled)
|
|
108
|
+
return;
|
|
109
|
+
// Handle summary response
|
|
110
|
+
if (summaryResponse?.ok) {
|
|
111
|
+
try {
|
|
112
|
+
const data = await summaryResponse.json();
|
|
113
|
+
setSummaryData(data);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
setSummaryFailed(true);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
setSummaryFailed(true);
|
|
121
|
+
}
|
|
122
|
+
// Handle current response
|
|
123
|
+
if (currentResponse?.ok) {
|
|
124
|
+
try {
|
|
125
|
+
const data = await currentResponse.json();
|
|
126
|
+
// Handle both array and object with readings property
|
|
127
|
+
const readings = Array.isArray(data) ? data : (data.readings || []);
|
|
128
|
+
setCurrentData(readings);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
setCurrentFailed(true);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
setCurrentFailed(true);
|
|
136
|
+
}
|
|
137
|
+
setLoading(false);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
if (cancelled)
|
|
141
|
+
return;
|
|
142
|
+
setError(err instanceof Error ? err.message : 'Network error');
|
|
143
|
+
setLoading(false);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
fetchData();
|
|
147
|
+
return () => {
|
|
148
|
+
cancelled = true;
|
|
149
|
+
};
|
|
150
|
+
}, [baseUrl, enabled]);
|
|
151
|
+
// Merge summary data with today's live data
|
|
152
|
+
const mergedData = (0, react_1.useMemo)(() => {
|
|
153
|
+
if (loading || !enabled)
|
|
154
|
+
return null;
|
|
155
|
+
const entries = [];
|
|
156
|
+
const today = new Date().toISOString().split('T')[0];
|
|
157
|
+
// Get historical data from summary
|
|
158
|
+
const historicalEntries = summaryData?.services?.[serviceName.toLowerCase()] || [];
|
|
159
|
+
// Get today's readings from current.json
|
|
160
|
+
const todayReadings = currentData
|
|
161
|
+
? groupReadingsByDate(currentData, serviceName).get(today) || []
|
|
162
|
+
: [];
|
|
163
|
+
// Add today's aggregated data if we have readings
|
|
164
|
+
if (todayReadings.length > 0) {
|
|
165
|
+
// Sort by timestamp for accurate incident counting
|
|
166
|
+
todayReadings.sort((a, b) => a.t - b.t);
|
|
167
|
+
entries.push(aggregateDayReadings(today, todayReadings));
|
|
168
|
+
}
|
|
169
|
+
// Add historical entries (filter out today if it exists in summary)
|
|
170
|
+
for (const entry of historicalEntries) {
|
|
171
|
+
if (entry.date !== today) {
|
|
172
|
+
entries.push(entry);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Sort by date descending (most recent first)
|
|
176
|
+
entries.sort((a, b) => b.date.localeCompare(a.date));
|
|
177
|
+
// Limit to requested number of days
|
|
178
|
+
return entries.slice(0, days);
|
|
179
|
+
}, [summaryData, currentData, serviceName, days, loading]);
|
|
180
|
+
// Determine error state
|
|
181
|
+
const finalError = (0, react_1.useMemo)(() => {
|
|
182
|
+
if (error)
|
|
183
|
+
return error;
|
|
184
|
+
if (summaryFailed && currentFailed)
|
|
185
|
+
return 'No data available';
|
|
186
|
+
return null;
|
|
187
|
+
}, [error, summaryFailed, currentFailed]);
|
|
188
|
+
return {
|
|
189
|
+
data: mergedData,
|
|
190
|
+
loading,
|
|
191
|
+
error: finalError,
|
|
192
|
+
lastUpdated: summaryData?.lastUpdated || null,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -14,7 +14,7 @@ export interface MiniHeatmapProps {
|
|
|
14
14
|
maintenance?: ScheduledMaintenance[];
|
|
15
15
|
/** System name to filter incidents and maintenance */
|
|
16
16
|
systemName?: string;
|
|
17
|
-
/** Number of days to show (default 90) */
|
|
17
|
+
/** Number of days to show (default 14, expandable to 90 with daily-summary.json) */
|
|
18
18
|
days?: number;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MiniHeatmap.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusItem/MiniHeatmap.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAK5F,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,2BAA2B;IAC3B,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,qCAAqC;IACrC,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACrC,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,
|
|
1
|
+
{"version":3,"file":"MiniHeatmap.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusItem/MiniHeatmap.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAK5F,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,2BAA2B;IAC3B,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,qCAAqC;IACrC,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACrC,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,SAAc,EACd,WAAgB,EAChB,UAAU,EACV,IAAS,GACV,EAAE,gBAAgB,GAAG,GAAG,CAAC,OAAO,CA+MhC"}
|
|
@@ -19,7 +19,7 @@ const MiniHeatmap_module_css_1 = __importDefault(require("./MiniHeatmap.module.c
|
|
|
19
19
|
* Compact heatmap visualization showing daily uptime status
|
|
20
20
|
* Similar to status.claude.com or GitHub contribution graph
|
|
21
21
|
*/
|
|
22
|
-
function MiniHeatmap({ history, incidents = [], maintenance = [], systemName, days =
|
|
22
|
+
function MiniHeatmap({ history, incidents = [], maintenance = [], systemName, days = 14, }) {
|
|
23
23
|
// Calculate daily uptime percentages
|
|
24
24
|
const calculateDailyUptime = () => {
|
|
25
25
|
const dailyStats = new Map();
|
|
@@ -13,6 +13,10 @@ export interface Props {
|
|
|
13
13
|
showUptime?: boolean;
|
|
14
14
|
showMiniChart?: boolean;
|
|
15
15
|
onClick?: () => void;
|
|
16
|
+
/** Base URL for fetching daily-summary.json (enables 90-day heatmap) */
|
|
17
|
+
dataBaseUrl?: string;
|
|
18
|
+
/** Number of days to show in heatmap (default: 14, or 90 if dataBaseUrl provided) */
|
|
19
|
+
heatmapDays?: number;
|
|
16
20
|
}
|
|
17
|
-
export default function StatusItem({ item, incidents, maintenance, showResponseTime, showUptime, showMiniChart, onClick, }: Props): JSX.Element;
|
|
21
|
+
export default function StatusItem({ item, incidents, maintenance, showResponseTime, showUptime, showMiniChart, onClick, dataBaseUrl, heatmapDays, }: Props): JSX.Element;
|
|
18
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusItem/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAC,UAAU,IAAI,cAAc,EAAE,cAAc,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusItem/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAC,UAAU,IAAI,cAAc,EAAE,cAAc,EAAE,oBAAoB,EAAqB,MAAM,aAAa,CAAC;AAKxH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACrC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAyBD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,IAAI,EACJ,SAAc,EACd,WAAgB,EAChB,gBAAuB,EACvB,UAAiB,EACjB,aAAoB,EACpB,OAAO,EACP,WAAW,EACX,WAAW,GACZ,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoIrB"}
|
|
@@ -5,6 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.default = StatusItem;
|
|
7
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
/**
|
|
9
|
+
* Copyright (c) Your Organization
|
|
10
|
+
*
|
|
11
|
+
* This source code is licensed under the MIT license found in the
|
|
12
|
+
* LICENSE file in the root directory of this source tree.
|
|
13
|
+
*/
|
|
14
|
+
const react_1 = require("react");
|
|
15
|
+
const useDailySummary_1 = require("../../hooks/useDailySummary");
|
|
8
16
|
const MiniHeatmap_1 = __importDefault(require("./MiniHeatmap"));
|
|
9
17
|
const styles_module_css_1 = __importDefault(require("./styles.module.css"));
|
|
10
18
|
const statusConfig = {
|
|
@@ -29,12 +37,60 @@ const statusConfig = {
|
|
|
29
37
|
icon: '⚙',
|
|
30
38
|
},
|
|
31
39
|
};
|
|
32
|
-
function StatusItem({ item, incidents = [], maintenance = [], showResponseTime = true, showUptime = true, showMiniChart = true, onClick, }) {
|
|
40
|
+
function StatusItem({ item, incidents = [], maintenance = [], showResponseTime = true, showUptime = true, showMiniChart = true, onClick, dataBaseUrl, heatmapDays, }) {
|
|
33
41
|
const config = statusConfig[item.status];
|
|
42
|
+
// Determine days to show: use prop if provided, otherwise 90 if dataBaseUrl, else 14
|
|
43
|
+
const daysToShow = heatmapDays ?? (dataBaseUrl ? 90 : 14);
|
|
44
|
+
// Fetch daily summary data if baseUrl provided (ADR-002)
|
|
45
|
+
const { data: summaryData } = (0, useDailySummary_1.useDailySummary)({
|
|
46
|
+
baseUrl: dataBaseUrl || '',
|
|
47
|
+
serviceName: item.name,
|
|
48
|
+
days: daysToShow,
|
|
49
|
+
enabled: !!dataBaseUrl && showMiniChart,
|
|
50
|
+
});
|
|
51
|
+
// Convert summary data to history format for MiniHeatmap
|
|
52
|
+
const enhancedHistory = (0, react_1.useMemo)(() => {
|
|
53
|
+
// Start with existing history
|
|
54
|
+
const existingHistory = item.history || [];
|
|
55
|
+
// If no summary data, return existing
|
|
56
|
+
if (!summaryData || summaryData.length === 0) {
|
|
57
|
+
return existingHistory;
|
|
58
|
+
}
|
|
59
|
+
// Create synthetic history entries from summary data
|
|
60
|
+
// Each day becomes a single "check" with status based on uptimePct
|
|
61
|
+
const summaryAsHistory = summaryData.map(entry => {
|
|
62
|
+
// Determine status from uptime percentage
|
|
63
|
+
let status = 'up';
|
|
64
|
+
if (entry.uptimePct < 0.5) {
|
|
65
|
+
status = 'down';
|
|
66
|
+
}
|
|
67
|
+
else if (entry.uptimePct < 0.99) {
|
|
68
|
+
status = 'degraded';
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
timestamp: `${entry.date}T12:00:00Z`, // Noon UTC as representative time
|
|
72
|
+
status,
|
|
73
|
+
code: entry.checksPassed > 0 ? 200 : 500,
|
|
74
|
+
responseTime: entry.avgLatencyMs || 0,
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
// Merge: prefer existing history for recent days, use summary for older days
|
|
78
|
+
const existingDates = new Set(existingHistory.map(h => h.timestamp.split('T')[0]));
|
|
79
|
+
// Add summary entries for dates not in existing history
|
|
80
|
+
const combined = [...existingHistory];
|
|
81
|
+
for (const entry of summaryAsHistory) {
|
|
82
|
+
const dateKey = entry.timestamp.split('T')[0];
|
|
83
|
+
if (!existingDates.has(dateKey)) {
|
|
84
|
+
combined.push(entry);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Sort by timestamp descending (most recent first)
|
|
88
|
+
return combined.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
89
|
+
}, [item.history, summaryData]);
|
|
34
90
|
return ((0, jsx_runtime_1.jsxs)("div", { className: `${styles_module_css_1.default.statusItem} ${onClick ? styles_module_css_1.default.clickable : ''}`, onClick: onClick, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, onKeyDown: onClick ? (e) => {
|
|
35
91
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
36
92
|
e.preventDefault();
|
|
37
93
|
onClick();
|
|
38
94
|
}
|
|
39
|
-
} : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusHeader, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusName, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.statusIcon, style: { backgroundColor: config.color }, children: config.icon }), (0, jsx_runtime_1.jsx)("h3", { children: item.name })] }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_css_1.default.statusLabel, style: { color: config.color }, children: config.label })] }), item.description && ((0, jsx_runtime_1.jsx)("p", { className: styles_module_css_1.default.statusDescription, children: item.description })), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusMetrics, children: [showUptime && item.uptime && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Uptime:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: item.uptime })] })), showResponseTime && item.responseTime !== undefined && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Response Time:" }), (0, jsx_runtime_1.jsxs)("span", { className: styles_module_css_1.default.metricValue, children: [item.responseTime, "ms"] })] })), item.incidentCount !== undefined && item.incidentCount > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Active Incidents:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: item.incidentCount })] })), item.lastChecked && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Last Checked:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: new Date(item.lastChecked).toLocaleString() })] }))] }), showMiniChart &&
|
|
95
|
+
} : undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusHeader, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusName, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.statusIcon, style: { backgroundColor: config.color }, children: config.icon }), (0, jsx_runtime_1.jsx)("h3", { children: item.name })] }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_css_1.default.statusLabel, style: { color: config.color }, children: config.label })] }), item.description && ((0, jsx_runtime_1.jsx)("p", { className: styles_module_css_1.default.statusDescription, children: item.description })), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.statusMetrics, children: [showUptime && item.uptime && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Uptime:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: item.uptime })] })), showResponseTime && item.responseTime !== undefined && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Response Time:" }), (0, jsx_runtime_1.jsxs)("span", { className: styles_module_css_1.default.metricValue, children: [item.responseTime, "ms"] })] })), item.incidentCount !== undefined && item.incidentCount > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Active Incidents:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: item.incidentCount })] })), item.lastChecked && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_css_1.default.metric, children: [(0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricLabel, children: "Last Checked:" }), (0, jsx_runtime_1.jsx)("span", { className: styles_module_css_1.default.metricValue, children: new Date(item.lastChecked).toLocaleString() })] }))] }), showMiniChart && enhancedHistory.length > 0 && ((0, jsx_runtime_1.jsx)(MiniHeatmap_1.default, { history: enhancedHistory, incidents: incidents, maintenance: maintenance, systemName: item.name, days: daysToShow }))] }));
|
|
40
96
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusPage/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAC,UAAU,EAA+B,MAAM,aAAa,CAAC;AAK1E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAC,UAAU,EAAC,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/theme/StatusPage/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAC,UAAU,EAA+B,MAAM,aAAa,CAAC;AAK1E,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAC,UAAU,EAAC,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAwQnE"}
|
|
@@ -106,8 +106,12 @@ function StatusPage({ statusData }) {
|
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
// Only use current.json data if we found matching items
|
|
110
|
+
if (files.length > 0) {
|
|
111
|
+
setSystemFiles(files);
|
|
112
|
+
return; // Success, don't try legacy format
|
|
113
|
+
}
|
|
114
|
+
// Otherwise, fall through to try legacy format or build-time data
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
catch (error) {
|
package/lib/types.d.ts
CHANGED
|
@@ -256,6 +256,46 @@ export interface ChartAnnotation {
|
|
|
256
256
|
[key: string]: any;
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* ADR-002: Daily summary entry for historical data aggregation
|
|
261
|
+
*
|
|
262
|
+
* Represents aggregated statistics for a single day.
|
|
263
|
+
* Used in daily-summary.json for 90-day heatmap visualization.
|
|
264
|
+
*/
|
|
265
|
+
export interface DailySummaryEntry {
|
|
266
|
+
/** ISO date string (YYYY-MM-DD) */
|
|
267
|
+
date: string;
|
|
268
|
+
/** Uptime percentage as decimal (0.0 to 1.0) */
|
|
269
|
+
uptimePct: number;
|
|
270
|
+
/** Average latency in milliseconds (null if no successful checks) */
|
|
271
|
+
avgLatencyMs: number | null;
|
|
272
|
+
/** 95th percentile latency in milliseconds (null if no successful checks) */
|
|
273
|
+
p95LatencyMs: number | null;
|
|
274
|
+
/** Total number of checks performed */
|
|
275
|
+
checksTotal: number;
|
|
276
|
+
/** Number of successful checks (up or maintenance) */
|
|
277
|
+
checksPassed: number;
|
|
278
|
+
/** Number of incident transitions (up → down) */
|
|
279
|
+
incidentCount: number;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* ADR-002: Daily summary file for historical data aggregation
|
|
283
|
+
*
|
|
284
|
+
* Schema v1 for daily-summary.json, containing aggregated daily statistics
|
|
285
|
+
* for all monitored services over a configurable time window.
|
|
286
|
+
*
|
|
287
|
+
* @see docs/adrs/ADR-002-historical-data-aggregation.md
|
|
288
|
+
*/
|
|
289
|
+
export interface DailySummaryFile {
|
|
290
|
+
/** Schema version (currently 1) */
|
|
291
|
+
version: number;
|
|
292
|
+
/** ISO timestamp of last update */
|
|
293
|
+
lastUpdated: string;
|
|
294
|
+
/** Number of days covered */
|
|
295
|
+
windowDays: number;
|
|
296
|
+
/** Aggregated data per service (key = service name) */
|
|
297
|
+
services: Record<string, DailySummaryEntry[]>;
|
|
298
|
+
}
|
|
259
299
|
export interface PluginOptions {
|
|
260
300
|
/**
|
|
261
301
|
* GitHub repository owner (defaults to the site's organizationName)
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/lib/version.d.ts
CHANGED
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amiable-dev/docusaurus-plugin-stentorosaur",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "A Docusaurus plugin for displaying status monitoring dashboard powered by GitHub Issues and Actions, similar to Upptime",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/plugin-status.d.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"stentorosaur-notify": "scripts/notify.js",
|
|
11
11
|
"stentorosaur-setup-status-branch": "scripts/setup-status-branch.js",
|
|
12
12
|
"stentorosaur-migrate-to-status-branch": "scripts/migrate-to-status-branch.js",
|
|
13
|
-
"stentorosaur-cleanup-status-branch": "scripts/cleanup-status-branch.js"
|
|
13
|
+
"stentorosaur-cleanup-status-branch": "scripts/cleanup-status-branch.js",
|
|
14
|
+
"stentorosaur-bootstrap-summary": "scripts/bootstrap-summary.js"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"docusaurus",
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bootstrap script to generate initial daily-summary.json from existing archives
|
|
5
|
+
*
|
|
6
|
+
* This script is typically run once when upgrading to a version that supports
|
|
7
|
+
* historical data aggregation (ADR-002). It reads all existing archive files
|
|
8
|
+
* and generates the initial daily-summary.json.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/bootstrap-summary.js --output-dir status-data
|
|
12
|
+
* node scripts/bootstrap-summary.js --output-dir status-data --window 90
|
|
13
|
+
*
|
|
14
|
+
* Options:
|
|
15
|
+
* --output-dir <path> Output directory containing archives/ (default: status-data)
|
|
16
|
+
* --window <days> Number of days to aggregate (default: 90)
|
|
17
|
+
* --verbose Enable verbose logging
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const zlib = require('zlib');
|
|
23
|
+
|
|
24
|
+
// Parse command line arguments
|
|
25
|
+
const args = process.argv.slice(2);
|
|
26
|
+
const options = {
|
|
27
|
+
outputDir: 'status-data',
|
|
28
|
+
windowDays: 90,
|
|
29
|
+
verbose: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < args.length; i++) {
|
|
33
|
+
switch (args[i]) {
|
|
34
|
+
case '--output-dir':
|
|
35
|
+
options.outputDir = args[++i];
|
|
36
|
+
break;
|
|
37
|
+
case '--window':
|
|
38
|
+
options.windowDays = parseInt(args[++i]);
|
|
39
|
+
break;
|
|
40
|
+
case '--verbose':
|
|
41
|
+
options.verbose = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function log(...msg) {
|
|
47
|
+
console.log('[bootstrap-summary]', ...msg);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function verbose(...msg) {
|
|
51
|
+
if (options.verbose) {
|
|
52
|
+
console.log('[bootstrap-summary:verbose]', ...msg);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Calculate p95 latency from an array of latency values
|
|
58
|
+
*/
|
|
59
|
+
function calculateP95(latencies) {
|
|
60
|
+
if (latencies.length === 0) return null;
|
|
61
|
+
const sorted = [...latencies].sort((a, b) => a - b);
|
|
62
|
+
const index = Math.ceil(sorted.length * 0.95) - 1;
|
|
63
|
+
return sorted[Math.max(0, index)];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Aggregate readings for a specific day into a DailySummaryEntry
|
|
68
|
+
*/
|
|
69
|
+
function aggregateDayReadings(date, readings) {
|
|
70
|
+
const checksTotal = readings.length;
|
|
71
|
+
const checksPassed = readings.filter(r => r.state === 'up' || r.state === 'maintenance').length;
|
|
72
|
+
const uptimePct = checksTotal > 0 ? checksPassed / checksTotal : 0;
|
|
73
|
+
|
|
74
|
+
const latencies = readings
|
|
75
|
+
.filter(r => r.state === 'up')
|
|
76
|
+
.map(r => r.lat);
|
|
77
|
+
|
|
78
|
+
const avgLatencyMs = latencies.length > 0
|
|
79
|
+
? Math.round(latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length)
|
|
80
|
+
: null;
|
|
81
|
+
|
|
82
|
+
const p95LatencyMs = calculateP95(latencies);
|
|
83
|
+
|
|
84
|
+
// Count incidents (transitions from up to down)
|
|
85
|
+
let incidentCount = 0;
|
|
86
|
+
for (let i = 1; i < readings.length; i++) {
|
|
87
|
+
if (readings[i - 1].state === 'up' && readings[i].state === 'down') {
|
|
88
|
+
incidentCount++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
date,
|
|
94
|
+
uptimePct,
|
|
95
|
+
avgLatencyMs,
|
|
96
|
+
p95LatencyMs,
|
|
97
|
+
checksTotal,
|
|
98
|
+
checksPassed,
|
|
99
|
+
incidentCount,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Generate daily-summary.json from existing archives
|
|
105
|
+
*/
|
|
106
|
+
function generateDailySummary(archivesDir, outputDir, windowDays) {
|
|
107
|
+
const now = new Date();
|
|
108
|
+
|
|
109
|
+
// Group all readings by service and date
|
|
110
|
+
const serviceReadings = new Map();
|
|
111
|
+
|
|
112
|
+
// Collect from last N days
|
|
113
|
+
for (let d = 0; d < windowDays; d++) {
|
|
114
|
+
const date = new Date(now.getTime() - d * 24 * 60 * 60 * 1000);
|
|
115
|
+
const year = date.getFullYear();
|
|
116
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
117
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
118
|
+
const dateKey = `${year}-${month}-${day}`;
|
|
119
|
+
|
|
120
|
+
const dir = path.join(archivesDir, String(year), month);
|
|
121
|
+
const plainFile = path.join(dir, `history-${year}-${month}-${day}.jsonl`);
|
|
122
|
+
const gzFile = path.join(dir, `history-${year}-${month}-${day}.jsonl.gz`);
|
|
123
|
+
|
|
124
|
+
let content = null;
|
|
125
|
+
|
|
126
|
+
// Try plain file first
|
|
127
|
+
if (fs.existsSync(plainFile)) {
|
|
128
|
+
try {
|
|
129
|
+
content = fs.readFileSync(plainFile, 'utf8');
|
|
130
|
+
verbose(`Read ${plainFile}`);
|
|
131
|
+
} catch (err) {
|
|
132
|
+
verbose(`Failed to read ${plainFile}:`, err.message);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Try gzipped file
|
|
136
|
+
else if (fs.existsSync(gzFile)) {
|
|
137
|
+
try {
|
|
138
|
+
const compressed = fs.readFileSync(gzFile);
|
|
139
|
+
content = zlib.gunzipSync(compressed).toString('utf8');
|
|
140
|
+
verbose(`Read ${gzFile}`);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
verbose(`Failed to decompress ${gzFile}:`, err.message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Parse and group by service
|
|
147
|
+
if (content) {
|
|
148
|
+
const lines = content.trim().split('\n').filter(line => line.trim());
|
|
149
|
+
|
|
150
|
+
for (const line of lines) {
|
|
151
|
+
try {
|
|
152
|
+
const obj = JSON.parse(line);
|
|
153
|
+
const svc = obj.svc;
|
|
154
|
+
|
|
155
|
+
if (!serviceReadings.has(svc)) {
|
|
156
|
+
serviceReadings.set(svc, new Map());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const svcMap = serviceReadings.get(svc);
|
|
160
|
+
if (!svcMap.has(dateKey)) {
|
|
161
|
+
svcMap.set(dateKey, []);
|
|
162
|
+
}
|
|
163
|
+
svcMap.get(dateKey).push(obj);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
verbose('Failed to parse line:', line);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Aggregate each service's daily data
|
|
172
|
+
const services = {};
|
|
173
|
+
let totalDays = 0;
|
|
174
|
+
|
|
175
|
+
for (const [svc, dateMap] of serviceReadings.entries()) {
|
|
176
|
+
const entries = [];
|
|
177
|
+
|
|
178
|
+
// Sort dates in reverse chronological order (most recent first)
|
|
179
|
+
const sortedDates = [...dateMap.keys()].sort().reverse();
|
|
180
|
+
totalDays = Math.max(totalDays, sortedDates.length);
|
|
181
|
+
|
|
182
|
+
for (const dateKey of sortedDates) {
|
|
183
|
+
const readings = dateMap.get(dateKey);
|
|
184
|
+
// Sort readings by timestamp for accurate incident counting
|
|
185
|
+
readings.sort((a, b) => a.t - b.t);
|
|
186
|
+
|
|
187
|
+
const entry = aggregateDayReadings(dateKey, readings);
|
|
188
|
+
entries.push(entry);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
services[svc] = entries;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Build the daily summary file (ADR-002 schema v1)
|
|
195
|
+
const summary = {
|
|
196
|
+
version: 1,
|
|
197
|
+
lastUpdated: now.toISOString(),
|
|
198
|
+
windowDays,
|
|
199
|
+
services,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Atomic write: temp file → rename
|
|
203
|
+
const summaryPath = path.join(outputDir, 'daily-summary.json');
|
|
204
|
+
const tempPath = path.join(outputDir, 'daily-summary.tmp');
|
|
205
|
+
|
|
206
|
+
fs.writeFileSync(tempPath, JSON.stringify(summary, null, 2));
|
|
207
|
+
fs.renameSync(tempPath, summaryPath);
|
|
208
|
+
|
|
209
|
+
return { summary, totalDays };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Main execution
|
|
213
|
+
function main() {
|
|
214
|
+
try {
|
|
215
|
+
const archivesDir = path.join(options.outputDir, 'archives');
|
|
216
|
+
|
|
217
|
+
if (!fs.existsSync(archivesDir)) {
|
|
218
|
+
console.error(`Error: Archives directory not found: ${archivesDir}`);
|
|
219
|
+
console.error('Make sure --output-dir points to the correct status data directory.');
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
log(`Generating daily-summary.json from ${archivesDir}...`);
|
|
224
|
+
log(`Window: ${options.windowDays} days`);
|
|
225
|
+
|
|
226
|
+
const { summary, totalDays } = generateDailySummary(
|
|
227
|
+
archivesDir,
|
|
228
|
+
options.outputDir,
|
|
229
|
+
options.windowDays
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const serviceCount = Object.keys(summary.services).length;
|
|
233
|
+
log(`\nGenerated daily-summary.json:`);
|
|
234
|
+
log(` Services: ${serviceCount}`);
|
|
235
|
+
log(` Days with data: ${totalDays}`);
|
|
236
|
+
log(` Window: ${options.windowDays} days`);
|
|
237
|
+
log(` Output: ${path.join(options.outputDir, 'daily-summary.json')}`);
|
|
238
|
+
|
|
239
|
+
if (serviceCount === 0) {
|
|
240
|
+
log('\nWarning: No data found. Make sure archives contain JSONL files.');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.error('Error:', error.message);
|
|
245
|
+
if (options.verbose) {
|
|
246
|
+
console.error(error);
|
|
247
|
+
}
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
main();
|
package/scripts/monitor.js
CHANGED
|
@@ -241,6 +241,171 @@ function buildCurrentJson(archivesDir, days = 14) {
|
|
|
241
241
|
return readings;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Calculate p95 latency from an array of latency values
|
|
246
|
+
* @param {number[]} latencies - Array of latency values in ms
|
|
247
|
+
* @returns {number|null} The p95 latency or null if empty
|
|
248
|
+
*/
|
|
249
|
+
function calculateP95(latencies) {
|
|
250
|
+
if (latencies.length === 0) return null;
|
|
251
|
+
const sorted = [...latencies].sort((a, b) => a - b);
|
|
252
|
+
const index = Math.ceil(sorted.length * 0.95) - 1;
|
|
253
|
+
return sorted[Math.max(0, index)];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Aggregate readings for a specific day into a DailySummaryEntry (ADR-002 schema)
|
|
258
|
+
* @param {string} date - ISO date string (YYYY-MM-DD)
|
|
259
|
+
* @param {Array<{t: number, svc: string, state: string, code: number, lat: number}>} readings
|
|
260
|
+
* @returns {Object} DailySummaryEntry
|
|
261
|
+
*/
|
|
262
|
+
function aggregateDayReadings(date, readings) {
|
|
263
|
+
const checksTotal = readings.length;
|
|
264
|
+
const checksPassed = readings.filter(r => r.state === 'up' || r.state === 'maintenance').length;
|
|
265
|
+
const uptimePct = checksTotal > 0 ? checksPassed / checksTotal : 0;
|
|
266
|
+
|
|
267
|
+
const latencies = readings
|
|
268
|
+
.filter(r => r.state === 'up')
|
|
269
|
+
.map(r => r.lat);
|
|
270
|
+
|
|
271
|
+
const avgLatencyMs = latencies.length > 0
|
|
272
|
+
? Math.round(latencies.reduce((sum, lat) => sum + lat, 0) / latencies.length)
|
|
273
|
+
: null;
|
|
274
|
+
|
|
275
|
+
const p95LatencyMs = calculateP95(latencies);
|
|
276
|
+
|
|
277
|
+
// Count incidents (transitions from up to down)
|
|
278
|
+
let incidentCount = 0;
|
|
279
|
+
for (let i = 1; i < readings.length; i++) {
|
|
280
|
+
if (readings[i - 1].state === 'up' && readings[i].state === 'down') {
|
|
281
|
+
incidentCount++;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
date,
|
|
287
|
+
uptimePct,
|
|
288
|
+
avgLatencyMs,
|
|
289
|
+
p95LatencyMs,
|
|
290
|
+
checksTotal,
|
|
291
|
+
checksPassed,
|
|
292
|
+
incidentCount,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Generate daily-summary.json with aggregated historical data (ADR-002)
|
|
298
|
+
* Uses hybrid approach: reads current.json and archives up to 90 days
|
|
299
|
+
* @param {string} archivesDir - Path to archives directory
|
|
300
|
+
* @param {string} outputDir - Path to output directory
|
|
301
|
+
* @param {number} windowDays - Number of days to aggregate (default: 90)
|
|
302
|
+
*/
|
|
303
|
+
function generateDailySummary(archivesDir, outputDir, windowDays = 90) {
|
|
304
|
+
const now = new Date();
|
|
305
|
+
|
|
306
|
+
// Group all readings by service and date
|
|
307
|
+
const serviceReadings = new Map(); // Map<service, Map<date, Reading[]>>
|
|
308
|
+
|
|
309
|
+
// Collect from last N days
|
|
310
|
+
for (let d = 0; d < windowDays; d++) {
|
|
311
|
+
const date = new Date(now.getTime() - d * 24 * 60 * 60 * 1000);
|
|
312
|
+
const year = date.getFullYear();
|
|
313
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
314
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
315
|
+
const dateKey = `${year}-${month}-${day}`;
|
|
316
|
+
|
|
317
|
+
const dir = path.join(archivesDir, String(year), month);
|
|
318
|
+
const plainFile = path.join(dir, `history-${year}-${month}-${day}.jsonl`);
|
|
319
|
+
const gzFile = path.join(dir, `history-${year}-${month}-${day}.jsonl.gz`);
|
|
320
|
+
|
|
321
|
+
let content = null;
|
|
322
|
+
|
|
323
|
+
// Try plain file first (today's file)
|
|
324
|
+
if (fs.existsSync(plainFile)) {
|
|
325
|
+
try {
|
|
326
|
+
content = fs.readFileSync(plainFile, 'utf8');
|
|
327
|
+
verbose(`[summary] Read ${plainFile}`);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
verbose(`[summary] Failed to read ${plainFile}:`, err.message);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// Try gzipped file (older days)
|
|
333
|
+
else if (fs.existsSync(gzFile)) {
|
|
334
|
+
try {
|
|
335
|
+
const compressed = fs.readFileSync(gzFile);
|
|
336
|
+
content = zlib.gunzipSync(compressed).toString('utf8');
|
|
337
|
+
verbose(`[summary] Read ${gzFile}`);
|
|
338
|
+
} catch (err) {
|
|
339
|
+
verbose(`[summary] Failed to decompress ${gzFile}:`, err.message);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Parse and group by service
|
|
344
|
+
if (content) {
|
|
345
|
+
const lines = content.trim().split('\n').filter(line => line.trim());
|
|
346
|
+
|
|
347
|
+
for (const line of lines) {
|
|
348
|
+
try {
|
|
349
|
+
const obj = JSON.parse(line);
|
|
350
|
+
const svc = obj.svc;
|
|
351
|
+
|
|
352
|
+
if (!serviceReadings.has(svc)) {
|
|
353
|
+
serviceReadings.set(svc, new Map());
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const svcMap = serviceReadings.get(svc);
|
|
357
|
+
if (!svcMap.has(dateKey)) {
|
|
358
|
+
svcMap.set(dateKey, []);
|
|
359
|
+
}
|
|
360
|
+
svcMap.get(dateKey).push(obj);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
verbose('[summary] Failed to parse line:', line);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Aggregate each service's daily data
|
|
369
|
+
const services = {};
|
|
370
|
+
|
|
371
|
+
for (const [svc, dateMap] of serviceReadings.entries()) {
|
|
372
|
+
const entries = [];
|
|
373
|
+
|
|
374
|
+
// Sort dates in reverse chronological order (most recent first)
|
|
375
|
+
const sortedDates = [...dateMap.keys()].sort().reverse();
|
|
376
|
+
|
|
377
|
+
for (const dateKey of sortedDates) {
|
|
378
|
+
const readings = dateMap.get(dateKey);
|
|
379
|
+
// Sort readings by timestamp for accurate incident counting
|
|
380
|
+
readings.sort((a, b) => a.t - b.t);
|
|
381
|
+
|
|
382
|
+
const entry = aggregateDayReadings(dateKey, readings);
|
|
383
|
+
entries.push(entry);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
services[svc] = entries;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Build the daily summary file (ADR-002 schema v1)
|
|
390
|
+
const summary = {
|
|
391
|
+
version: 1,
|
|
392
|
+
lastUpdated: now.toISOString(),
|
|
393
|
+
windowDays,
|
|
394
|
+
services,
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
// Atomic write: temp file → rename
|
|
398
|
+
const summaryPath = path.join(outputDir, 'daily-summary.json');
|
|
399
|
+
const tempPath = path.join(outputDir, 'daily-summary.tmp');
|
|
400
|
+
|
|
401
|
+
fs.writeFileSync(tempPath, JSON.stringify(summary, null, 2));
|
|
402
|
+
fs.renameSync(tempPath, summaryPath);
|
|
403
|
+
|
|
404
|
+
verbose(`[summary] Generated ${summaryPath} with ${Object.keys(services).length} services`);
|
|
405
|
+
|
|
406
|
+
return summary;
|
|
407
|
+
}
|
|
408
|
+
|
|
244
409
|
/**
|
|
245
410
|
* Generate status.json from current.json for plugin consumption
|
|
246
411
|
* Aggregates time-series data into status items
|
|
@@ -486,7 +651,14 @@ async function main() {
|
|
|
486
651
|
generateStatusJson(currentPath, options.outputDir);
|
|
487
652
|
log('Generated status.json for plugin');
|
|
488
653
|
}
|
|
489
|
-
|
|
654
|
+
|
|
655
|
+
// Generate daily-summary.json for 90-day heatmap (ADR-002)
|
|
656
|
+
const archivesDir = path.join(options.outputDir, 'archives');
|
|
657
|
+
if (fs.existsSync(archivesDir)) {
|
|
658
|
+
generateDailySummary(archivesDir, options.outputDir, 90);
|
|
659
|
+
log('Generated daily-summary.json for 90-day heatmap');
|
|
660
|
+
}
|
|
661
|
+
|
|
490
662
|
// Summary
|
|
491
663
|
log(`\nMonitored ${results.length} system(s):`);
|
|
492
664
|
for (const result of results) {
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/annotation-utils.ts","./src/data-source-resolver.client.ts","./src/data-source-resolver.ts","./src/data-source-validator.ts","./src/demo-data.ts","./src/github-service.ts","./src/historical-data.ts","./src/index.ts","./src/label-utils.ts","./src/maintenance-utils.ts","./src/options.ts","./src/plugin-status.d.ts","./src/time-utils.ts","./src/types.ts","./src/version.ts","./src/hooks/index.ts","./src/hooks/useStatusData.ts","./src/notifications/simple-index.ts","./src/notifications/simple-notification-service.ts","./src/notifications/types.ts","./src/notifications/providers/discord-provider.ts","./src/notifications/providers/email-provider.ts","./src/notifications/providers/slack-provider.ts","./src/notifications/providers/telegram-provider.ts","./src/theme/css-modules.d.ts","./src/theme/theme-layout.d.ts","./src/theme/ChartPanel/index.tsx","./src/theme/IncidentHistory/index.tsx","./src/theme/Maintenance/MaintenanceItem/index.tsx","./src/theme/Maintenance/MaintenanceList/index.tsx","./src/theme/PerformanceMetrics/index.tsx","./src/theme/ResponseTimeChart/index.tsx","./src/theme/SLIChart/index.tsx","./src/theme/StatusBoard/index.tsx","./src/theme/StatusHistory/index.tsx","./src/theme/StatusItem/MiniHeatmap.tsx","./src/theme/StatusItem/index.tsx","./src/theme/StatusPage/index.tsx","./src/theme/UptimeChart/index.tsx","./src/theme/UptimeStatusPage/index.tsx","./src/theme/components/ExportButton.tsx","./src/theme/hooks/useChartExport.ts","./src/theme/hooks/useDataExport.ts","./src/utils/csv.ts","./src/utils/markdown.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/annotation-utils.ts","./src/data-source-resolver.client.ts","./src/data-source-resolver.ts","./src/data-source-validator.ts","./src/demo-data.ts","./src/github-service.ts","./src/historical-data.ts","./src/index.ts","./src/label-utils.ts","./src/maintenance-utils.ts","./src/options.ts","./src/plugin-status.d.ts","./src/time-utils.ts","./src/types.ts","./src/version.ts","./src/hooks/index.ts","./src/hooks/useDailySummary.ts","./src/hooks/useStatusData.ts","./src/notifications/simple-index.ts","./src/notifications/simple-notification-service.ts","./src/notifications/types.ts","./src/notifications/providers/discord-provider.ts","./src/notifications/providers/email-provider.ts","./src/notifications/providers/slack-provider.ts","./src/notifications/providers/telegram-provider.ts","./src/theme/css-modules.d.ts","./src/theme/theme-layout.d.ts","./src/theme/ChartPanel/index.tsx","./src/theme/IncidentHistory/index.tsx","./src/theme/Maintenance/MaintenanceItem/index.tsx","./src/theme/Maintenance/MaintenanceList/index.tsx","./src/theme/PerformanceMetrics/index.tsx","./src/theme/ResponseTimeChart/index.tsx","./src/theme/SLIChart/index.tsx","./src/theme/StatusBoard/index.tsx","./src/theme/StatusHistory/index.tsx","./src/theme/StatusItem/MiniHeatmap.tsx","./src/theme/StatusItem/index.tsx","./src/theme/StatusPage/index.tsx","./src/theme/UptimeChart/index.tsx","./src/theme/UptimeStatusPage/index.tsx","./src/theme/components/ExportButton.tsx","./src/theme/hooks/useChartExport.ts","./src/theme/hooks/useDataExport.ts","./src/utils/csv.ts","./src/utils/markdown.ts"],"version":"5.9.3"}
|