mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-24 06:28:42 +01:00
@@ -32,9 +32,8 @@
|
||||
|
||||
<router-link
|
||||
:to="{
|
||||
name: '/merged/[name]',
|
||||
query: { id: containers.map(({ id }) => id) },
|
||||
params: { name: label.replace('label.', '') },
|
||||
name: '/merged/[ids]',
|
||||
params: { ids: containers.map(({ id }) => id).join(',') },
|
||||
}"
|
||||
class="btn btn-square btn-outline btn-primary btn-xs"
|
||||
active-class="btn-active"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<MultiContainerStat class="ml-auto" :containers="containers" />
|
||||
<MultiContainerActionToolbar class="mobile-hidden" @clear="viewer?.clear()" />
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
@@ -24,6 +25,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ViewerWithSource from "@/components/LogViewer/ViewerWithSource.vue";
|
||||
import { ComponentExposed } from "vue-component-type-helpers";
|
||||
|
||||
const { ids = [], scrollable = false } = defineProps<{
|
||||
ids?: string[];
|
||||
@@ -31,9 +33,9 @@ const { ids = [], scrollable = false } = defineProps<{
|
||||
}>();
|
||||
|
||||
const containerStore = useContainerStore();
|
||||
|
||||
const viewer = ref<ComponentExposed<typeof ViewerWithSource>>();
|
||||
const { allContainersById, ready } = storeToRefs(containerStore);
|
||||
|
||||
const containers = computed(() => ids.map((id) => allContainersById.value[id]));
|
||||
|
||||
provideLoggingContext(containers);
|
||||
</script>
|
||||
|
||||
@@ -20,47 +20,30 @@ function parseMessage(data: string): LogEntry<string | JSONObject> {
|
||||
}
|
||||
|
||||
export function useContainerStream(container: Ref<Container>): LogStreamSource {
|
||||
const url = computed(() =>
|
||||
withBase(`/api/hosts/${container.value.host}/containers/${container.value.id}/logs/stream`),
|
||||
);
|
||||
|
||||
const loadMoreUrl = computed(() =>
|
||||
withBase(`/api/hosts/${container.value.host}/containers/${container.value.id}/logs`),
|
||||
);
|
||||
|
||||
const url = computed(() => `/api/hosts/${container.value.host}/containers/${container.value.id}/logs/stream`);
|
||||
const loadMoreUrl = computed(() => `/api/hosts/${container.value.host}/containers/${container.value.id}/logs`);
|
||||
return useLogStream(url, loadMoreUrl);
|
||||
}
|
||||
|
||||
export function useStackStream(stack: Ref<Stack>): LogStreamSource {
|
||||
const url = computed(() => withBase(`/api/stacks/${stack.value.name}/logs/stream`));
|
||||
return useLogStream(url);
|
||||
return useLogStream(computed(() => `/api/stacks/${stack.value.name}/logs/stream`));
|
||||
}
|
||||
|
||||
export function useGroupedStream(group: Ref<GroupedContainers>): LogStreamSource {
|
||||
const url = computed(() => withBase(`/api/groups/${group.value.name}/logs/stream`));
|
||||
return useLogStream(url);
|
||||
return useLogStream(computed(() => `/api/groups/${group.value.name}/logs/stream`));
|
||||
}
|
||||
|
||||
export function useMergedStream(containers: Ref<Container[]>): LogStreamSource {
|
||||
const url = computed(() => {
|
||||
const ids = containers.value.map((c) => ["id", c.id]).join(",");
|
||||
return withBase(`/api/hosts/${containers.value[0].host}/logs/mergedStream/${ids}`);
|
||||
const ids = containers.value.map((c) => c.id).join(",");
|
||||
return `/api/hosts/${containers.value[0].host}/logs/mergedStream/${ids}`;
|
||||
});
|
||||
|
||||
return useLogStream(url);
|
||||
}
|
||||
|
||||
export function useServiceStream(service: Ref<Service>): LogStreamSource {
|
||||
const { streamConfig } = useLoggingContext();
|
||||
|
||||
const url = computed(() => {
|
||||
const params = Object.entries(toValue(streamConfig))
|
||||
.filter(([, value]) => value)
|
||||
.reduce((acc, [key]) => ({ ...acc, [key]: "1" }), {});
|
||||
return withBase(`/api/services/${service.value.name}/logs/stream?${new URLSearchParams(params).toString()}`);
|
||||
});
|
||||
|
||||
return useLogStream(url);
|
||||
return useLogStream(computed(() => `/api/services/${service.value.name}/logs/stream`));
|
||||
}
|
||||
|
||||
export type LogStreamSource = ReturnType<typeof useLogStream>;
|
||||
@@ -187,7 +170,7 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
|
||||
const stopWatcher = watchOnce(url, () => abortController.abort("stream changed"));
|
||||
const moreParams = { ...params.value, from: from.toISOString(), to: to.toISOString(), fill: "1" };
|
||||
const logs = await (
|
||||
await fetch(`${loadMoreUrl.value}?${new URLSearchParams(moreParams).toString()}`, { signal })
|
||||
await fetch(withBase(`${loadMoreUrl.value}?${new URLSearchParams(moreParams).toString()}`), { signal })
|
||||
).text();
|
||||
stopWatcher();
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
const containerStore = useContainerStore();
|
||||
const { ready } = storeToRefs(containerStore);
|
||||
|
||||
const route = useRoute("/merged/[name]");
|
||||
const route = useRoute("/merged/[ids]");
|
||||
|
||||
const pinnedLogsStore = usePinnedLogsStore();
|
||||
const { pinnedLogs } = storeToRefs(pinnedLogsStore);
|
||||
|
||||
const ids = toRef(() => route.query.id as string[]);
|
||||
const ids = toRef(() => route.params.ids.split(","));
|
||||
|
||||
watchEffect(() => {
|
||||
if (ready.value) {
|
||||
2
assets/typed-router.d.ts
vendored
2
assets/typed-router.d.ts
vendored
@@ -23,7 +23,7 @@ declare module 'vue-router/auto-routes' {
|
||||
'/container/[id]': RouteRecordInfo<'/container/[id]', '/container/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
|
||||
'/group/[name]': RouteRecordInfo<'/group/[name]', '/group/:name', { name: ParamValue<true> }, { name: ParamValue<false> }>,
|
||||
'/login': RouteRecordInfo<'/login', '/login', Record<never, never>, Record<never, never>>,
|
||||
'/merged/[name]': RouteRecordInfo<'/merged/[name]', '/merged/:name', { name: ParamValue<true> }, { name: ParamValue<false> }>,
|
||||
'/merged/[ids]': RouteRecordInfo<'/merged/[ids]', '/merged/:ids', { ids: ParamValue<true> }, { ids: ParamValue<false> }>,
|
||||
'/service/[name]': RouteRecordInfo<'/service/[name]', '/service/:name', { name: ParamValue<true> }, { name: ParamValue<false> }>,
|
||||
'/settings': RouteRecordInfo<'/settings', '/settings', Record<never, never>, Record<never, never>>,
|
||||
'/show': RouteRecordInfo<'/show', '/show', Record<never, never>, Record<never, never>>,
|
||||
|
||||
@@ -168,13 +168,10 @@ func (h *handler) streamContainerLogs(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (h *handler) streamLogsMerged(w http.ResponseWriter, r *http.Request) {
|
||||
if !r.URL.Query().Has("id") {
|
||||
http.Error(w, "ids query parameter is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
idsSplit := strings.Split(chi.URLParam(r, "ids"), ",")
|
||||
|
||||
ids := make(map[string]bool)
|
||||
for _, id := range r.URL.Query()["id"] {
|
||||
for _, id := range idsSplit {
|
||||
ids[id] = true
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ func createRouter(h *handler) *chi.Mux {
|
||||
r.Get("/api/hosts/{host}/containers/{id}/logs/stream", h.streamContainerLogs)
|
||||
r.Get("/api/hosts/{host}/containers/{id}/logs/download", h.downloadLogs)
|
||||
r.Get("/api/hosts/{host}/containers/{id}/logs", h.fetchLogsBetweenDates)
|
||||
r.Get("/api/hosts/{host}/logs/mergedStream", h.streamLogsMerged)
|
||||
r.Get("/api/hosts/{host}/logs/mergedStream/{ids}", h.streamLogsMerged)
|
||||
r.Get("/api/stacks/{stack}/logs/stream", h.streamStackLogs)
|
||||
r.Get("/api/services/{service}/logs/stream", h.streamServiceLogs)
|
||||
r.Get("/api/groups/{group}/logs/stream", h.streamGroupedLogs)
|
||||
|
||||
Reference in New Issue
Block a user