You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.0 KiB
175 lines
5.0 KiB
<script lang="ts">
|
|
import { navigate } from "svelte-routing";
|
|
import { getUnixTime, sub } from "date-fns";
|
|
|
|
import { buildQueryParams, fromUnixTimeSafe } from "../api/util";
|
|
import { getLogs, getStats, LogPayload, StatSearchKey } from "../api";
|
|
import type { Stat, Log } from "../api";
|
|
|
|
import PageContainer from "./PageContainer.svelte";
|
|
import SearchOptions from "../components/SearchOptions.svelte";
|
|
import TimeChart from "../components/TimeChart.svelte";
|
|
import LogViewer from "../components/LogViewer.svelte";
|
|
|
|
export let location: Location;
|
|
|
|
const { search } = location;
|
|
let params = new URLSearchParams(search.substring(1));
|
|
|
|
const aggKey = params.get("key");
|
|
const fixed = aggKey
|
|
? aggKey[0].toUpperCase() + aggKey.substr(1)
|
|
: "Domain";
|
|
|
|
let start: Date =
|
|
fromUnixTimeSafe(params.get("start")) || sub(new Date(), { hours: 24 });
|
|
let end: Date = fromUnixTimeSafe(params.get("end")) || null;
|
|
|
|
let filter: string = params.get("filter") || "";
|
|
|
|
let chartKey: StatSearchKey = StatSearchKey[fixed] || StatSearchKey.Domain;
|
|
let chartInterval: number = 30;
|
|
let page: number = Number(params.get("page") || 0);
|
|
|
|
let chartData: Stat = null;
|
|
let chartErrorMsg: string = null;
|
|
let chartDataLoading: Boolean = false;
|
|
|
|
let logs: Log[] = [];
|
|
let logErrorMsg: string = null;
|
|
let logDataLoading: Boolean = false;
|
|
let pageSize: number = Number(params.get("pageSize") || 25);
|
|
let pageCount: number = 0;
|
|
let logCount: number = 0;
|
|
|
|
const fetchLogs = async () => {
|
|
if (logDataLoading) {
|
|
console.warn("tried loading logs while already loading");
|
|
return;
|
|
}
|
|
|
|
logErrorMsg = null;
|
|
logDataLoading = true;
|
|
const { error, payload } = await getLogs({
|
|
start,
|
|
end,
|
|
page,
|
|
pageSize,
|
|
filter,
|
|
});
|
|
logDataLoading = false;
|
|
|
|
if (error) {
|
|
logErrorMsg = error;
|
|
return new LogPayload();
|
|
}
|
|
|
|
return payload;
|
|
};
|
|
|
|
const fetchStats = async (): Promise<Stat> => {
|
|
if (chartDataLoading) {
|
|
console.warn("tried loading stats while already loading");
|
|
return;
|
|
}
|
|
|
|
chartErrorMsg = null;
|
|
chartDataLoading = true;
|
|
const { error, payload } = await getStats({
|
|
start,
|
|
end,
|
|
key: chartKey,
|
|
interval: chartInterval,
|
|
});
|
|
chartDataLoading = false;
|
|
|
|
if (error) {
|
|
chartErrorMsg = error;
|
|
return null;
|
|
}
|
|
|
|
return payload;
|
|
};
|
|
|
|
let done = true;
|
|
const updateData = async (evt) => {
|
|
if (chartDataLoading || logDataLoading || !done) {
|
|
console.debug("SKIPPED DATA FETCH");
|
|
return;
|
|
}
|
|
|
|
console.groupCollapsed("Stats Data Update");
|
|
const {
|
|
filter: eFilter,
|
|
start: eStart,
|
|
end: eEnd,
|
|
key: eKey,
|
|
page: ePage,
|
|
pageSize: eps,
|
|
} = evt;
|
|
console.debug("handled search, fetching new data:", evt);
|
|
console.groupEnd();
|
|
|
|
let truePage =
|
|
logCount <= pageSize * page ? 0 : ePage === 0 ? null : ePage;
|
|
if (logCount <= pageSize * page) {
|
|
console.warn(
|
|
"adjusting log page because logCount is too small for current settings"
|
|
);
|
|
|
|
page = 0;
|
|
}
|
|
|
|
navigate(
|
|
`${location?.pathname}${buildQueryParams({
|
|
start: eStart ? getUnixTime(eStart) : null,
|
|
end: eEnd ? getUnixTime(eEnd) : null,
|
|
filter: eFilter === "" ? eFilter : null,
|
|
key: eKey !== "domain" ? eKey : null,
|
|
page: truePage,
|
|
pageSize: eps && eps !== 25 ? eps : null,
|
|
})}`,
|
|
{ replace: true }
|
|
);
|
|
|
|
[{ page, total: logCount, pageCount, pageSize, logs }, chartData] =
|
|
await Promise.all([fetchLogs(), fetchStats()]);
|
|
|
|
done = true;
|
|
};
|
|
|
|
$: updateData({ start, end, key: chartKey, filter, pageSize, page });
|
|
</script>
|
|
|
|
<PageContainer
|
|
{location}
|
|
header="Stats"
|
|
description="Server performance stats and activity log"
|
|
>
|
|
<SearchOptions bind:start bind:end bind:filter bind:key={chartKey} />
|
|
<section style="height: 384px;" class="my-5">
|
|
{#if chartDataLoading}
|
|
<p>Loading chart</p>
|
|
{:else if chartErrorMsg}
|
|
<p>{chartErrorMsg}</p>
|
|
{:else}
|
|
<TimeChart stats={chartData} column={chartKey} />
|
|
{/if}
|
|
</section>
|
|
<section class="my-5">
|
|
{#if logDataLoading}
|
|
<p>Loading logs</p>
|
|
{:else if logErrorMsg}
|
|
<p>{logErrorMsg}</p>
|
|
{:else}
|
|
<LogViewer
|
|
pages={pageCount}
|
|
total={logCount}
|
|
{logs}
|
|
bind:page
|
|
bind:pageSize
|
|
/>
|
|
{/if}
|
|
</section>
|
|
</PageContainer>
|