@hyperwatch/hyperwatch 4.3.1 → 5.0.1
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 +9 -4
- package/config/apache_syslog_example.js +1 -1
- package/config/default.js +1 -1
- package/config/example.js +4 -4
- package/config/express_websocket_example.js +1 -1
- package/config/websocket_client_example.js +52 -0
- package/docs/configuration.md +67 -6
- package/docs/express-embedding.md +137 -0
- package/docs/input.md +50 -24
- package/docs/tutorials/apache_input.md +16 -14
- package/docs/tutorials/express_input.md +10 -8
- package/package.json +16 -14
- package/scripts/fetch-anthropic-ips.js +60 -0
- package/src/app/api.js +129 -3
- package/src/app/index.js +8 -4
- package/src/app/mount.js +115 -0
- package/src/app/websocket.js +12 -9
- package/src/app/ws-server.js +123 -0
- package/src/constants.js +8 -5
- package/src/data/amazon-searchbot-ips.json +304 -0
- package/src/data/amazonbot-ips.json +775 -1
- package/src/data/chatgpt-user-ips.json +115 -112
- package/src/data/claude-bot-ips.json +28 -0
- package/src/data/cloudfront-ips.json +14 -0
- package/src/data/gptbot-ips.json +0 -3
- package/src/data/openai-searchbot-ips.json +4 -0
- package/src/index.js +6 -1
- package/src/input/http.js +4 -0
- package/src/input/syslog.js +5 -1
- package/src/input/websocket.js +57 -21
- package/src/lib/aggregator.js +112 -19
- package/src/lib/formatter.js +10 -1
- package/src/lib/log-buffer.js +45 -0
- package/src/lib/persistence.js +11 -1
- package/src/lib/pipeline.js +140 -14
- package/src/lib/recent-map.js +23 -0
- package/src/modules/address.js +59 -2
- package/src/modules/dnsbl.js +11 -1
- package/src/modules/history.js +4 -28
- package/src/modules/hostname.js +12 -4
- package/src/modules/identity.js +92 -9
- package/src/modules/index.js +14 -5
- package/src/modules/signature.js +49 -14
- package/src/modules/sparkline.js +7 -3
- package/src/modules/status.js +6 -1
package/src/modules/signature.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
const { is
|
|
1
|
+
const { is } = require('immutable');
|
|
2
2
|
|
|
3
3
|
const api = require('../app/api');
|
|
4
|
-
const { Aggregator } = require('../lib/aggregator');
|
|
4
|
+
const { Aggregator, lastSeen, statusCount } = require('../lib/aggregator');
|
|
5
5
|
const { Formatter } = require('../lib/formatter');
|
|
6
6
|
const pipeline = require('../lib/pipeline');
|
|
7
|
+
const { touch, prune, countRecent } = require('../lib/recent-map');
|
|
7
8
|
const {
|
|
8
9
|
aggregateCount,
|
|
9
10
|
aggregateSum,
|
|
@@ -40,6 +41,9 @@ function normalisedIdentityHeader(headers) {
|
|
|
40
41
|
return obj;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
const addressCount15m = (entry) => countRecent(entry.get('addresses'), 15 * 60);
|
|
45
|
+
const addressCount24h = (entry) => countRecent(entry.get('addresses'));
|
|
46
|
+
|
|
43
47
|
function computeSignature(headers) {
|
|
44
48
|
const string = Object.keys(headers)
|
|
45
49
|
.map((key) => [key, headers[key]].join(':'))
|
|
@@ -65,8 +69,10 @@ function init() {
|
|
|
65
69
|
pipeline.getNode('main').map(augment).registerNode('main');
|
|
66
70
|
}
|
|
67
71
|
|
|
72
|
+
let _aggregator;
|
|
73
|
+
|
|
68
74
|
function start() {
|
|
69
|
-
const aggregator = new Aggregator();
|
|
75
|
+
const aggregator = (_aggregator = new Aggregator());
|
|
70
76
|
|
|
71
77
|
aggregator.setIdentifier((log) => log.getIn(['signature', 'id']));
|
|
72
78
|
|
|
@@ -75,15 +81,24 @@ function start() {
|
|
|
75
81
|
signatureFormatter.setFormats([
|
|
76
82
|
['signature', (entry) => entry.getIn(['signature', 'id'])],
|
|
77
83
|
['identity', (entry) => entry.get('identity')],
|
|
78
|
-
['
|
|
84
|
+
['addressCount15m', addressCount15m],
|
|
85
|
+
['addressCount24h', addressCount24h],
|
|
79
86
|
[
|
|
80
87
|
'addresses',
|
|
81
88
|
(entry) =>
|
|
82
|
-
entry
|
|
83
|
-
.get('addresses')
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
entry.has('addresses')
|
|
90
|
+
? entry.get('addresses').keySeq().slice(0, 10).join('<br>')
|
|
91
|
+
: '',
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
'lastAddress',
|
|
95
|
+
(entry) => {
|
|
96
|
+
const addr = entry.get('lastAddress');
|
|
97
|
+
if (!addr) {
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
return addr.get('hostname') || addr.get('value') || '';
|
|
101
|
+
},
|
|
87
102
|
],
|
|
88
103
|
|
|
89
104
|
[
|
|
@@ -96,9 +111,15 @@ function start() {
|
|
|
96
111
|
},
|
|
97
112
|
],
|
|
98
113
|
|
|
114
|
+
['lastSeen', lastSeen],
|
|
99
115
|
['count15m', (entry) => aggregateCount(entry, 'per_minute')],
|
|
100
116
|
['count24h', (entry) => aggregateCount(entry, 'per_hour')],
|
|
101
117
|
|
|
118
|
+
['2xx15m', statusCount('2xx_per_minute')],
|
|
119
|
+
['2xx24h', statusCount('2xx_per_hour')],
|
|
120
|
+
['4xx15m', statusCount('4xx_per_minute')],
|
|
121
|
+
['4xx24h', statusCount('4xx_per_hour')],
|
|
122
|
+
|
|
102
123
|
[
|
|
103
124
|
'execTime15m',
|
|
104
125
|
(entry) => formatDuration(aggregateSum(entry, 'per_minute')),
|
|
@@ -121,10 +142,12 @@ function start() {
|
|
|
121
142
|
}
|
|
122
143
|
|
|
123
144
|
const address = log.get('address');
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
145
|
+
entry = entry.set('lastAddress', address);
|
|
146
|
+
// Distinct IPs with last-seen time, pruned to 24h; backs both the 15m
|
|
147
|
+
// and 24h counts
|
|
148
|
+
const value = address && address.get('value');
|
|
149
|
+
if (value) {
|
|
150
|
+
entry = entry.update('addresses', (map) => touch(map, value));
|
|
128
151
|
}
|
|
129
152
|
|
|
130
153
|
return entry;
|
|
@@ -132,7 +155,16 @@ function start() {
|
|
|
132
155
|
|
|
133
156
|
aggregator.setEnricher(enricher);
|
|
134
157
|
|
|
135
|
-
|
|
158
|
+
aggregator.setEntryGc((entry) =>
|
|
159
|
+
entry.has('addresses') ? entry.update('addresses', prune) : entry
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
aggregator.sorters.addressCount15m = addressCount15m;
|
|
163
|
+
aggregator.sorters.addressCount24h = addressCount24h;
|
|
164
|
+
|
|
165
|
+
pipeline
|
|
166
|
+
.getNode('main')
|
|
167
|
+
.map((log) => aggregator.processLog(log), 'aggregator');
|
|
136
168
|
|
|
137
169
|
api.registerAggregator('signatures', aggregator);
|
|
138
170
|
}
|
|
@@ -140,4 +172,7 @@ function start() {
|
|
|
140
172
|
module.exports = {
|
|
141
173
|
init,
|
|
142
174
|
start,
|
|
175
|
+
get aggregator() {
|
|
176
|
+
return _aggregator;
|
|
177
|
+
},
|
|
143
178
|
};
|
package/src/modules/sparkline.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const aggregator = require('../lib/aggregator');
|
|
2
2
|
|
|
3
|
-
const sparkline = (entry, key) => {
|
|
3
|
+
const sparkline = (entry, key, output) => {
|
|
4
|
+
if (output === 'text') {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
const id = entry.get('id');
|
|
5
9
|
|
|
6
10
|
const points = entry
|
|
@@ -22,8 +26,8 @@ sparkline ('${id}', ${JSON.stringify(points)}, '#797979', 14, 5);
|
|
|
22
26
|
};
|
|
23
27
|
|
|
24
28
|
function init() {
|
|
25
|
-
aggregator.defaultFormatter.insertFormat('activity', (entry) =>
|
|
26
|
-
sparkline(entry, 'per_minute')
|
|
29
|
+
aggregator.defaultFormatter.insertFormat('activity', (entry, output) =>
|
|
30
|
+
sparkline(entry, 'per_minute', output)
|
|
27
31
|
);
|
|
28
32
|
}
|
|
29
33
|
|
package/src/modules/status.js
CHANGED
|
@@ -23,10 +23,15 @@ function mapper(entry, format) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function start() {
|
|
26
|
-
api.get('/status
|
|
26
|
+
api.get('/status{.:format}', (req, res) => {
|
|
27
27
|
const raw = req.query.raw ? true : false;
|
|
28
28
|
const format = req.params.format || (raw ? 'json' : null);
|
|
29
29
|
|
|
30
|
+
if (format && !['json', 'txt'].includes(format)) {
|
|
31
|
+
res.sendStatus(404);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
let rawData = monitoring.getAllComputed();
|
|
31
36
|
|
|
32
37
|
if (req.query.type) {
|