Skip to content

Commit 56973f1

Browse files
committed
ready for a look
1 parent e529ee5 commit 56973f1

File tree

1 file changed

+46
-63
lines changed

1 file changed

+46
-63
lines changed

src/shadowbox/server/manager_metrics.ts

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
QueryResultData,
2020
} from '../infrastructure/prometheus_scraper';
2121
import {DataUsageByUser, DataUsageTimeframe} from '../model/metrics';
22+
import * as logging from '../infrastructure/logging';
2223

2324
const PROMETHEUS_RANGE_QUERY_STEP_SECONDS = 5 * 60;
2425

@@ -99,61 +100,6 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
99100
return {bytesTransferredByUserId: usage};
100101
}
101102

102-
private queryCache = new Map<string, {timestamp: number; result: QueryResultData}>();
103-
104-
private async promethusClientTimedQuery(query: string) {
105-
const cacheId = query;
106-
107-
if (this.queryCache.has(cacheId)) {
108-
const cached = this.queryCache.get(cacheId);
109-
110-
if (cached && cached.timestamp + PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000 > Date.now()) {
111-
console.log(cacheId, 'cache hit');
112-
113-
return cached.result;
114-
}
115-
}
116-
117-
console.time(query);
118-
119-
const result = await this.prometheusClient.query(query);
120-
121-
this.queryCache.set(cacheId, {timestamp: Date.now(), result});
122-
123-
console.timeEnd(query);
124-
125-
return result;
126-
}
127-
128-
private async promethusClientTimedRangeQuery(
129-
query: string,
130-
start: number,
131-
end: number,
132-
step: string
133-
) {
134-
const cacheId = `${query}-${start}-${end}-${step}`;
135-
136-
if (this.queryCache.has(cacheId)) {
137-
const cached = this.queryCache.get(cacheId);
138-
139-
if (cached && cached.timestamp + PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000 > Date.now()) {
140-
console.log(cacheId, 'cache hit');
141-
142-
return cached.result;
143-
}
144-
}
145-
146-
console.time(cacheId);
147-
148-
const result = await this.prometheusClient.queryRange(query, start, end, step);
149-
150-
this.queryCache.set(cacheId, {timestamp: Date.now(), result});
151-
152-
console.timeEnd(cacheId);
153-
154-
return result;
155-
}
156-
157103
async getServerMetrics(timeframe: Duration): Promise<ServerMetrics> {
158104
const now = new Date().getTime() / 1000;
159105
// We need to calculate consistent start and end times for Prometheus range
@@ -167,6 +113,8 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
167113
Math.ceil(now / PROMETHEUS_RANGE_QUERY_STEP_SECONDS) * PROMETHEUS_RANGE_QUERY_STEP_SECONDS;
168114
const start = end - timeframe.seconds;
169115

116+
this.prunePrometheusCache();
117+
170118
const [
171119
bandwidth,
172120
bandwidthRange,
@@ -177,34 +125,34 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
177125
dataTransferredByAccessKeyRange,
178126
tunnelTimeByAccessKeyRange,
179127
] = await Promise.all([
180-
this.promethusClientTimedQuery(
128+
this.cachedPrometheusClient.query(
181129
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`
182130
),
183-
this.promethusClientTimedRangeQuery(
131+
this.cachedPrometheusClient.queryRange(
184132
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`,
185133
start,
186134
end,
187135
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
188136
),
189-
this.promethusClientTimedQuery(
137+
this.cachedPrometheusClient.query(
190138
`sum(increase(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (location, asn, asorg)`
191139
),
192-
this.promethusClientTimedQuery(
140+
this.cachedPrometheusClient.query(
193141
`sum(increase(shadowsocks_tunnel_time_seconds_per_location[${timeframe.seconds}s])) by (location, asn, asorg)`
194142
),
195-
this.promethusClientTimedQuery(
143+
this.cachedPrometheusClient.query(
196144
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (access_key)`
197145
),
198-
this.promethusClientTimedQuery(
146+
this.cachedPrometheusClient.query(
199147
`sum(increase(shadowsocks_tunnel_time_seconds[${timeframe.seconds}s])) by (access_key)`
200148
),
201-
this.promethusClientTimedRangeQuery(
149+
this.cachedPrometheusClient.queryRange(
202150
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
203151
start,
204152
end,
205153
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
206154
),
207-
this.promethusClientTimedRangeQuery(
155+
this.cachedPrometheusClient.queryRange(
208156
`sum(increase(shadowsocks_tunnel_time_seconds[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
209157
start,
210158
end,
@@ -287,6 +235,41 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
287235
accessKeys: Array.from(accessKeyMap.values()),
288236
};
289237
}
238+
239+
private prometheusCache = new Map<string, {timestamp: number; result: QueryResultData}>();
240+
241+
private get cachedPrometheusClient() {
242+
return new Proxy(this.prometheusClient, {
243+
get: (target, prop) => {
244+
if (typeof target[prop] !== 'function') {
245+
return target[prop];
246+
}
247+
248+
return async (query, ...args) => {
249+
const cacheId = `${String(prop)}: ${query} (args: ${args.join(', ')}))`;
250+
251+
if (this.prometheusCache.has(cacheId)) {
252+
return this.prometheusCache.get(cacheId).result;
253+
}
254+
255+
const result = await (target[prop] as Function)(query, ...args);
256+
257+
this.prometheusCache.set(cacheId, {timestamp: Date.now(), result});
258+
259+
return result;
260+
};
261+
},
262+
});
263+
}
264+
265+
private prunePrometheusCache() {
266+
const now = Date.now();
267+
for (const [key, value] of this.prometheusCache) {
268+
if (now - value.timestamp > PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000) {
269+
this.prometheusCache.delete(key);
270+
}
271+
}
272+
}
290273
}
291274

292275
function getServerMetricsLocationEntry(

0 commit comments

Comments
 (0)