This commit is contained in:
tree 2023-07-07 19:05:33 +00:00
rodič 904dd83fe0
revize f4281adf29
4 změnil soubory, kde provedl 170 přidání a 93 odebrání

Zobrazit soubor

@ -90,6 +90,14 @@ function findDIDFed(item) {
return ff ? ff.id : null;
}
function pdsUrlFromHost(host) {
let https = true;
if (host.startsWith("localhost:")) {
https = false;
}
return `http${https ? "s" : ""}://${host}`;
}
function getPDSStatus(item) {
if (!item.inspect) {
return "unknown";
@ -155,28 +163,39 @@ router
perf(ctx);
})
.get("/pds/:host", async (ctx) => {
let host = ctx.params.host;
let https = true;
if (host.startsWith("localhost:")) {
https = false;
}
const q = { url: `http${https ? "s" : ""}://${host}` };
const item = await ats.db.pds.findOne(q);
const url = pdsUrlFromHost(ctx.params.host);
const item = await ats.db.pds.findOne({ url });
if (!item) {
return ctx.response.code = 404;
}
Object.assign(item, prepareObject("pds", item));
ctx.response.body = item;
perf(ctx);
})
.get("/pds/:host/latency", async (ctx) => {
const url = pdsUrlFromHost(ctx.params.host);
const item = await ats.db.pds.findOne({ url });
if (!item) {
return ctx.response.code = 404;
}
const host = item.url.replace(/^https?:\/\//, "");
const allowedRanges = ["24h", "7d", "30d"];
const rangesAggregation = ["3m", "15m", "1h"];
const userRange = ctx.request.url.searchParams.get("range");
const range = userRange && allowedRanges.includes(userRange)
? userRange
: "24h";
const aggregation = rangesAggregation[allowedRanges.indexOf(range)];
const query = `
from(bucket: "ats-stats")
|> range(start: -1d)
|> range(start: -${range})
|> filter(fn: (r) => r["_measurement"] == "pds_response_time")
|> filter(fn: (r) => r["pds"] == "${item.host}")
|> aggregateWindow(every: 3m, fn: mean, createEmpty: true)`;
|> filter(fn: (r) => r["pds"] == "${host}")
|> aggregateWindow(every: ${aggregation}, fn: mean, createEmpty: true)`;
item.responseTimesDay = await ats.influxQuery.collectRows(query);
ctx.response.body = item;
const data = await ats.influxQuery.collectRows(query);
ctx.response.body = { range, aggregation, data };
perf(ctx);
})
.get("/dids", async (ctx) => {
@ -309,34 +328,52 @@ router
perf(ctx);
})
.get("/_metrics", async (ctx) => {
const metrics = {
pds_count: [await ats.db.pds.count()],
did_count: [await ats.db.did.count()],
};
for (const queueName of Object.keys(ats.queues)) {
const queue = ats.queues[queueName];
const getMetric = async (name) =>
(await queue.getMetrics(name)).meta.count;
const metrics = {};
metrics[`queue_metric_completed{name="${queueName}"}`] = [
await getMetric("completed"),
];
metrics[`queue_metric_failed{name="${queueName}"}`] = [
await getMetric("failed"),
];
metrics[`queue_active{name="${queueName}"}`] = [
await queue.getActiveCount(),
];
metrics[`queue_waiting{name="${queueName}"}`] = [
await queue.getWaitingCount(),
];
metrics[`queue_waiting_children{name="${queueName}"}`] = [
await queue.getWaitingChildrenCount(),
];
metrics[`queue_prioritized{name="${queueName}"}`] = [
await queue.getPrioritizedCount(),
];
}
await Promise.all([
(async () => {
metrics.did_count = [await ats.db.did.count()];
})(),
(async () => {
metrics.pds_count = [await ats.db.pds.count()];
})(),
(async () => {
const statuses = { online: 0, offline: 0, degraded: 0, unknown: 0 };
for (const pds of await ats.db.pds.find().toArray()) {
const stn = getPDSStatus(pds);
statuses[stn]++;
}
for (const st of Object.keys(statuses)) {
metrics[`pds_count{status="${st}"}`] = [statuses[st]];
}
})(),
(async () => {
for (const queueName of Object.keys(ats.queues)) {
const queue = ats.queues[queueName];
const getMetric = async (name) =>
(await queue.getMetrics(name)).meta.count;
metrics[`queue_metric_completed{name="${queueName}"}`] = [
await getMetric("completed"),
];
metrics[`queue_metric_failed{name="${queueName}"}`] = [
await getMetric("failed"),
];
metrics[`queue_active{name="${queueName}"}`] = [
await queue.getActiveCount(),
];
metrics[`queue_waiting{name="${queueName}"}`] = [
await queue.getWaitingCount(),
];
metrics[`queue_waiting_children{name="${queueName}"}`] = [
await queue.getWaitingChildrenCount(),
];
metrics[`queue_prioritized{name="${queueName}"}`] = [
await queue.getPrioritizedCount(),
];
}
})(),
]);
ctx.response.body = Object.keys(metrics).map((m) => {
const [data, help, type] = metrics[m];
return `${m} ${data}`;

Zobrazit soubor

@ -38,11 +38,13 @@ export class ATScan {
};
console.log(`Connected to MongoDB: ${this.env.MONGODB_URL}`);
if (this.enableNats) {
this.nats = await NATSConnect({
servers: this.env.NATS_SERVERS,
});
this.JSONCodec = JSONCodec();
console.log(`Connected to NATS: ${this.env.NATS_SERVERS}`);
await (async () => {
this.nats = await NATSConnect({
servers: this.env.NATS_SERVERS,
});
this.JSONCodec = JSONCodec();
console.log(`Connected to NATS: ${this.env.NATS_SERVERS}`);
})();
}
if (this.enableQueues) {
this.queues = await makeQueues(this);

Zobrazit soubor

@ -1,6 +1,6 @@
{
"name": "atscan-fe",
"version": "0.7.2-alpha",
"version": "0.7.3-alpha",
"private": true,
"scripts": {
"dev": "vite dev",

Zobrazit soubor

@ -5,9 +5,16 @@
import SourceSection from '$lib/components/SourceSection.svelte';
import BasicPage from '$lib/components/BasicPage.svelte';
import Chart from '$lib/components/Chart.svelte';
import { onMount } from 'svelte';
import { request } from '$lib/api';
import { TabGroup, Tab, TabAnchor } from '@skeletonlabs/skeleton';
import { writable } from 'svelte/store';
export let data;
const chartResponseTimesTab = writable(0);
let chartResponseTimes = null;
const item = data.item;
const status = getPDSStatus(item);
@ -114,47 +121,69 @@
}
};
$: chartResponseTimes = {
animationDuration: 250,
tooltip: {
trigger: 'axis'
//formatter: '{b}: {c} ms'
},
legend: {
data: Object.keys(crawlers).map((c) => `${crawlers[c].region} (${crawlers[c].location})`)
},
grid: {
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: item.responseTimesDay?.filter((r) => r.table === 0).map((r) => r._time) || []
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} ms'
}
},
series: Object.keys(crawlers).map((crawler) => {
const crawlerOptions = crawlers[crawler];
return {
name: `${crawlerOptions.region} (${crawlerOptions.location})`,
type: 'line',
//stack: 'ms',
data: item.responseTimesDay?.filter((r) => r.crawler === crawler).map((r) => r._value) || []
};
})
};
function renderLatencyChart(chartData) {
return {
animationDuration: 250,
tooltip: {
trigger: 'axis'
//formatter: '{b}: {c} ms'
},
legend: {
data: Object.keys(crawlers).map((c) => `${crawlers[c].region} (${crawlers[c].location})`)
},
grid: {
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: chartData.filter((r) => r.table === 0).map((r) => r._time) || []
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} ms'
}
},
series: Object.keys(crawlers).map((crawler) => {
const crawlerOptions = crawlers[crawler];
return {
name: `${crawlerOptions.region} (${crawlerOptions.location})`,
type: 'line',
//stack: 'ms',
data: chartData.filter((r) => r.crawler === crawler).map((r) => r._value) || []
};
})
};
}
const latencyConfig = ['24h', '7d', '30d'];
chartResponseTimesTab.subscribe(async (num) => {
chartResponseTimes = null;
const latencyData = await request(
fetch,
`/pds/${item.host}/latency?range=${latencyConfig[num]}`
);
if (latencyData) {
chartResponseTimes = renderLatencyChart(latencyData.data);
}
});
onMount(async () => {
const latencyData = await request(fetch, `/pds/${item.host}/latency`);
if (latencyData) {
chartResponseTimes = renderLatencyChart(latencyData.data);
}
});
</script>
<BasicPage {data} title={item.host} {breadcrumb} noHeader="true">
@ -187,11 +216,20 @@
</div>
<h2 class="h2">Response times</h2>
{#if chartResponseTimes}
<div class="w-full h-64">
<Chart options={chartResponseTimes} />
</div>
{/if}
<TabGroup>
<Tab bind:group={$chartResponseTimesTab} name="tab1" value={0}>Last 24h</Tab>
<Tab bind:group={$chartResponseTimesTab} name="tab2" value={1}>Last 7d</Tab>
<Tab bind:group={$chartResponseTimesTab} name="tab3" value={2}>Last 30d</Tab>
<!-- Tab Panels --->
<svelte:fragment slot="panel">
<div class="w-full h-64">
{#if chartResponseTimes}
<Chart options={chartResponseTimes} />
{/if}
</div>
</svelte:fragment>
</TabGroup>
<div class="table-container">
<!-- Native Table Element -->
@ -201,7 +239,7 @@
<th class="text-sm">Region</th>
<th class="text-sm">Location</th>
<th class="text-sm">Status</th>
<th class="text-sm">Response time</th>
<th class="text-sm">Latency</th>
<th class="text-sm">Last check</th>
</tr>
</thead>