1
0
mirror of https://github.com/amir20/dozzle.git synced 2025-12-24 06:28:42 +01:00

feat: more improvements to analytic and gzips logs for better performance (#3814)

This commit is contained in:
Amir Raminfar
2025-04-17 14:09:06 -07:00
committed by GitHub
parent 061cd0c445
commit 1cf178e37d
16 changed files with 53 additions and 22 deletions

View File

@@ -13,11 +13,12 @@
class="textarea textarea-primary w-full font-mono text-lg"
:class="{ 'textarea-error': error }"
></textarea>
<div class="label mt-2 overflow-y-auto">
<span v-if="!isReady">{{ $t("analytics.creating_table") }}</span>
<div class="mt-2">
<span class="text-error" v-if="state === 'error'">{{ error }}</span>
<span v-else-if="state === 'initializing'">{{ $t("analytics.creating_table") }}</span>
<span v-else-if="state === 'downloading'">{{ $t("analytics.downloading") }}</span>
<span v-else-if="evaluating">{{ $t("analytics.evaluating_query") }}</span>
<span class="label-text-alt text-error" v-else-if="error">{{ error }}</span>
<span class="label-text-alt" v-else>
<span v-else>
{{ $t("analytics.total_records", { count: results.numRows.toLocaleString() }) }}
<template v-if="results.numRows > pageLimit">{{
$t("analytics.showing_first", { count: page.numRows.toLocaleString() })
@@ -26,7 +27,7 @@
</div>
</label>
</section>
<SQLTable :table="page" :loading="evaluating || !isReady" />
<SQLTable :table="page" :loading="evaluating || state !== 'ready'" />
</div>
</aside>
</template>
@@ -34,12 +35,14 @@
<script setup lang="ts">
import { Container } from "@/models/Container";
import { type Table } from "@apache-arrow/esnext-esm";
const { container } = defineProps<{ container: Container }>();
const query = ref("SELECT * FROM logs LIMIT 100");
const error = ref<string | null>(null);
const debouncedQuery = debouncedRef(query, 500);
const evaluating = ref(false);
const pageLimit = 1000;
const state = ref<"downloading" | "error" | "ready" | "initializing">("downloading");
const url = withBase(
`/api/hosts/${container.host}/containers/${container.id}/logs?stdout=1&stderr=1&everything&jsonOnly`,
@@ -55,27 +58,29 @@ if (!response.ok) {
const { db, conn } = await useDuckDB();
const empty = await conn.query<Record<string, any>>(`SELECT 1 LIMIT 0`);
const { isReady } = useAsyncState(
async () => {
onMounted(async () => {
try {
state.value = "downloading";
await db.registerFileBuffer("logs.json", new Uint8Array(await response.arrayBuffer()));
state.value = "initializing";
await conn.query(
`CREATE TABLE logs AS SELECT unnest(m) FROM read_json('logs.json', ignore_errors = true, format = 'newline_delimited')`,
);
},
undefined,
{
onError: (e) => {
console.error(e);
if (e instanceof Error) {
error.value = e.message;
}
},
},
);
state.value = "ready";
} catch (e) {
console.error(e);
state.value = "error";
if (e instanceof Error) {
error.value = e.message;
}
}
});
const results = computedAsync(
async () => {
if (isReady.value) {
if (state.value === "ready") {
return await conn.query<Record<string, any>>(debouncedQuery.value);
} else {
return empty;
@@ -85,6 +90,7 @@ const results = computedAsync(
{
onError: (e) => {
console.error(e);
state.value = "error";
if (e instanceof Error) {
error.value = e.message;
}
@@ -93,7 +99,10 @@ const results = computedAsync(
},
);
whenever(evaluating, () => (error.value = null));
whenever(evaluating, () => {
error.value = null;
state.value = "ready";
});
const page = computed(() =>
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
) as unknown as ComputedRef<Table<Record<string, any>>>;