Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e22d54cf74 | |||
| 7bf331cf6e | |||
| d529ed7855 | |||
| 46d124b11a | |||
| d09aa5d481 | |||
| cc77c16f92 | |||
| 63be3bf2d8 | |||
| ec29c78052 | |||
| df3f04dd50 | |||
| 7af7956b7f | |||
| d21473fe0b | |||
| 4093512497 | |||
| 0ef6252158 | |||
| 5947338966 | |||
| db5e760ae3 | |||
| 1ab4464f9a | |||
| 45ea4ac095 | |||
| c6339effd1 | |||
| 4e217f4e3a | |||
| c58f3b4254 | |||
| a7680940ab | |||
| cce2e8a8b5 | |||
| 8513824fb4 | |||
| 00da15c2fc | |||
| c1d31313b2 | |||
| 6f7c1d8ba6 | |||
| f1982c094d | |||
| cd63b5ded8 | |||
| 96fbee9ece | |||
| 36a5d7e6b9 | |||
| 520d82246f | |||
| ddfd00aaed | |||
| f3ab541ad1 | |||
| 4026e927f5 | |||
| b1643d490c | |||
| eab380b70d | |||
| 070f1c7bdb | |||
| 8b1adb51c8 | |||
| 46465356ab | |||
| ce096983ca | |||
| ddd3a80ddb | |||
| aeb1fd96e2 | |||
| dc9f402a1d | |||
| 2c2e3d5790 | |||
| 5e33094517 | |||
| 853a5d4f0d | |||
| 8ea5876615 | |||
| c4aacb211f | |||
| 8cf0912af0 | |||
| cedd112f6b | |||
| 01cf239569 | |||
| f4f14b900c | |||
| 6722a0129e | |||
| 277beb940b | |||
| 2d62257a33 | |||
| 5a890cbb94 | |||
| 39b3b1b59d | |||
| 567337649e | |||
| 423e4e11a3 | |||
| 049214d529 | |||
| d11f997999 | |||
| 1e5264a00b | |||
| 157b2cb304 | |||
| dc18e0f4a4 | |||
| 9bbe35e7fd | |||
| add108dc04 | |||
| 45ec05419d | |||
| 00f0cb606a | |||
| 896c402adc | |||
| f9f0f8f1e0 | |||
| 3b014dc0c7 | |||
| 3dcd5b3b78 |
@@ -28,7 +28,7 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: 📦 Dozzle version
|
||||
description: Can be found in logs or settings page.
|
||||
description: Run `docker run amir20/dozzle --version` or `curl http://<host>/api/version`.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base", "schedule:weekly", "group:allNonMajor", ":automergeMinor"],
|
||||
"rangeStrategy": "bump",
|
||||
"ignoreDeps": ["@duckdb/duckdb-wasm"]
|
||||
"extends": ["config:recommended", "schedule:weekly", "group:allNonMajor", ":automergeMinor"],
|
||||
"rangeStrategy": "bump"
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
|
||||
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
if: ${{ !github.event.repository.fork && !github.event.pull_request.head.repo.fork && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == 'amir20/dozzle') }}
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
|
||||
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.1
|
||||
go-version: "1.23"
|
||||
check-latest: true
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
@@ -68,10 +68,18 @@ jobs:
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
- name: Run Go Tests with Coverage
|
||||
run: make test
|
||||
staticcheck:
|
||||
runs-on: ubuntu-latest
|
||||
name: Go Staticcheck
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Generate dependencies
|
||||
run: make fake_assets shared_key.pem shared_cert.pem
|
||||
- name: Stactic checker
|
||||
uses: dominikh/staticcheck-action@v1.3.1
|
||||
with:
|
||||
install-go: false
|
||||
version: "latest"
|
||||
int-test:
|
||||
name: Integration Tests
|
||||
timeout-minutes: 60
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Build assets
|
||||
FROM --platform=$BUILDPLATFORM node:22.9.0-alpine AS node
|
||||
FROM --platform=$BUILDPLATFORM node:23.1.0-alpine AS node
|
||||
|
||||
RUN corepack enable
|
||||
|
||||
@@ -22,7 +22,7 @@ COPY public ./public
|
||||
# Build assets
|
||||
RUN pnpm build
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:1.23.1-alpine AS builder
|
||||
FROM --platform=$BUILDPLATFORM golang:1.23.2-alpine AS builder
|
||||
|
||||
# install gRPC dependencies
|
||||
RUN apk add --no-cache ca-certificates protoc protobuf-dev\
|
||||
|
||||
@@ -6,16 +6,10 @@
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const $: typeof import('vue/macros')['$']
|
||||
const $$: typeof import('vue/macros')['$$']
|
||||
const $computed: typeof import('vue/macros')['$computed']
|
||||
const $customRef: typeof import('vue/macros')['$customRef']
|
||||
const $ref: typeof import('vue/macros')['$ref']
|
||||
const $shallowRef: typeof import('vue/macros')['$shallowRef']
|
||||
const $toRef: typeof import('vue/macros')['$toRef']
|
||||
const DEFAULT_SETTINGS: typeof import('./stores/settings')['DEFAULT_SETTINGS']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||
const allLevels: typeof import('./composable/logContext')['allLevels']
|
||||
const arrayEquals: typeof import('./utils/index')['arrayEquals']
|
||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||
@@ -49,7 +43,6 @@ declare global {
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const defineStore: typeof import('pinia')['defineStore']
|
||||
const drawerContext: typeof import('./composable/drawer')['drawerContext']
|
||||
const drwaer: typeof import('./composable/showLogDetails')['drwaer']
|
||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||
@@ -65,7 +58,6 @@ declare global {
|
||||
const hashCode: typeof import('./utils/index')['hashCode']
|
||||
const hourStyle: typeof import('./stores/settings')['hourStyle']
|
||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||
const initDuckDB: typeof import('./composable/duckdb')['initDuckDB']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const injectLocal: typeof import('@vueuse/core')['injectLocal']
|
||||
const isDefined: typeof import('@vueuse/core')['isDefined']
|
||||
@@ -111,9 +103,7 @@ declare global {
|
||||
const persistentVisibleKeysForContainer: typeof import('./composable/storage')['persistentVisibleKeysForContainer']
|
||||
const pinnedContainers: typeof import('./composable/storage')['pinnedContainers']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const provideDetails: typeof import('./composable/showDetails')['provideDetails']
|
||||
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
||||
const provideLogDetails: typeof import('./composable/showLogDetails')['provideLogDetails']
|
||||
const provideLoggingContext: typeof import('./composable/logContext')['provideLoggingContext']
|
||||
const provideScrollContext: typeof import('./composable/scrollContext')['provideScrollContext']
|
||||
const reactify: typeof import('@vueuse/core')['reactify']
|
||||
@@ -143,7 +133,6 @@ declare global {
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const showAllContainers: typeof import('./stores/settings')['showAllContainers']
|
||||
const showLogDetails: typeof import('./composable/showLogDetails')['showLogDetails']
|
||||
const showStd: typeof import('./stores/settings')['showStd']
|
||||
const showTimestamp: typeof import('./stores/settings')['showTimestamp']
|
||||
const size: typeof import('./stores/settings')['size']
|
||||
@@ -213,7 +202,6 @@ declare global {
|
||||
const useDebounce: typeof import('@vueuse/core')['useDebounce']
|
||||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
|
||||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
|
||||
const useDetails: typeof import('./composable/showDetails')['useDetails']
|
||||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
|
||||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
|
||||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
|
||||
@@ -258,8 +246,6 @@ declare global {
|
||||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
|
||||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
|
||||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
|
||||
const useLogDetails: typeof import('./composable/showLogDetails')['useLogDetails']
|
||||
const useLogSearchContext: typeof import('./composable/logSearchContext')['useLogSearchContext']
|
||||
const useLoggingContext: typeof import('./composable/logContext')['useLoggingContext']
|
||||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
|
||||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
|
||||
@@ -392,6 +378,7 @@ declare module 'vue' {
|
||||
readonly DEFAULT_SETTINGS: UnwrapRef<typeof import('./stores/settings')['DEFAULT_SETTINGS']>
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
||||
readonly allLevels: UnwrapRef<typeof import('./composable/logContext')['allLevels']>
|
||||
readonly arrayEquals: UnwrapRef<typeof import('./utils/index')['arrayEquals']>
|
||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||
|
||||
@@ -65,6 +65,7 @@ declare module 'vue' {
|
||||
'Mdi:cog': typeof import('~icons/mdi/cog')['default']
|
||||
'Mdi:contentCopy': typeof import('~icons/mdi/content-copy')['default']
|
||||
'Mdi:docker': typeof import('~icons/mdi/docker')['default']
|
||||
'Mdi:gauge': typeof import('~icons/mdi/gauge')['default']
|
||||
'Mdi:hamburgerMenu': typeof import('~icons/mdi/hamburger-menu')['default']
|
||||
'Mdi:hexagonMultiple': typeof import('~icons/mdi/hexagon-multiple')['default']
|
||||
'Mdi:key': typeof import('~icons/mdi/key')['default']
|
||||
@@ -105,6 +106,7 @@ declare module 'vue' {
|
||||
SimpleLogItem: typeof import('./components/LogViewer/SimpleLogItem.vue')['default']
|
||||
SkippedEntriesLogItem: typeof import('./components/LogViewer/SkippedEntriesLogItem.vue')['default']
|
||||
SlideTransition: typeof import('./components/common/SlideTransition.vue')['default']
|
||||
SQLTable: typeof import('./components/LogViewer/SQLTable.vue')['default']
|
||||
StackLog: typeof import('./components/StackViewer/StackLog.vue')['default']
|
||||
StatMonitor: typeof import('./components/LogViewer/StatMonitor.vue')['default']
|
||||
StatSparkline: typeof import('./components/LogViewer/StatSparkline.vue')['default']
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
v-model="selectedHost"
|
||||
/>
|
||||
</div>
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
|
||||
<DropdownMenu
|
||||
class="btn-sm"
|
||||
v-model="selectedHost"
|
||||
:options="[
|
||||
@@ -37,8 +37,8 @@
|
||||
</div>
|
||||
<div class="flex-1 text-right" v-show="containers.length > pageSizes[0]">
|
||||
{{ $t("label.per-page") }}
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
|
||||
<DropdownMenu
|
||||
class="dropdown-left btn-xs md:btn-sm"
|
||||
v-model="perPage"
|
||||
:options="pageSizes.map((i) => ({ label: i.toLocaleString(), value: i }))"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="dropdown dropdown-end dropdown-hover">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm gap-0.5 px-2">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm w-10 gap-0.5 px-2">
|
||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
</label>
|
||||
@@ -28,46 +28,78 @@
|
||||
</li>
|
||||
<li class="line"></li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="flex size-4 gap-0.5">
|
||||
<template v-if="streamConfig.stderr && streamConfig.stdout">
|
||||
<carbon:circle-solid class="w-2 text-red" />
|
||||
<carbon:circle-solid class="w-2 text-blue" />
|
||||
</template>
|
||||
</div>
|
||||
{{ $t("toolbar.show-all") }}
|
||||
</a>
|
||||
<details>
|
||||
<summary>
|
||||
<div class="flex w-4">
|
||||
<carbon:circle-solid class="w-2.5 text-red" v-if="streamConfig.stderr" />
|
||||
<carbon:circle-solid class="w-2.5 text-blue" v-if="streamConfig.stdout" />
|
||||
</div>
|
||||
Streams
|
||||
</summary>
|
||||
<ul class="menu">
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<mdi:check class="w-4" v-if="streamConfig.stdout == true && streamConfig.stderr == true" />
|
||||
<div v-else class="w-4"></div>
|
||||
{{ $t("toolbar.show-all") }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = false;
|
||||
"
|
||||
>
|
||||
<mdi:check class="w-4" v-if="streamConfig.stdout == true && streamConfig.stderr == false" />
|
||||
<div v-else class="w-4"></div>
|
||||
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = false;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<mdi:check class="w-4" v-if="streamConfig.stdout == false && streamConfig.stderr == true" />
|
||||
<div v-else class="w-4"></div>
|
||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = true;
|
||||
streamConfig.stderr = false;
|
||||
"
|
||||
>
|
||||
<div class="flex size-4 flex-col gap-1">
|
||||
<carbon:circle-solid class="w-2 text-blue" v-if="!streamConfig.stderr && streamConfig.stdout" />
|
||||
</div>
|
||||
{{ $t("toolbar.show", { std: "STDOUT" }) }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@click="
|
||||
streamConfig.stdout = false;
|
||||
streamConfig.stderr = true;
|
||||
"
|
||||
>
|
||||
<div class="flex size-4 flex-col gap-1">
|
||||
<carbon:circle-solid class="w-2 text-red" v-if="streamConfig.stderr && !streamConfig.stdout" />
|
||||
</div>
|
||||
{{ $t("toolbar.show", { std: "STDERR" }) }}
|
||||
</a>
|
||||
<details class="group/details">
|
||||
<summary>
|
||||
<mdi:gauge />
|
||||
Levels
|
||||
<Toggle
|
||||
class="toggle-xs invisible group-open/details:visible"
|
||||
v-model="toggleAllLevels"
|
||||
title="Toggle all levels"
|
||||
/>
|
||||
</summary>
|
||||
<ul class="menu">
|
||||
<li v-for="level in allLevels">
|
||||
<a class="capitalize" @click="levels.has(level) ? levels.delete(level) : levels.add(level)">
|
||||
<mdi:check class="w-4" v-if="levels.has(level)" />
|
||||
<div v-else class="w-4"></div>
|
||||
|
||||
<div class="flex">
|
||||
<div class="badge" :data-level="level">{{ level }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<!-- Container Actions (Enabled via config) -->
|
||||
@@ -108,11 +140,12 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Container } from "@/models/Container";
|
||||
import { allLevels } from "@/composable/logContext";
|
||||
import LogAnalytics from "../LogViewer/LogAnalytics.vue";
|
||||
|
||||
const { showSearch } = useSearchFilter();
|
||||
const { enableActions } = config;
|
||||
const { streamConfig, hasComplexLogs } = useLoggingContext();
|
||||
const { streamConfig, hasComplexLogs, levels } = useLoggingContext();
|
||||
const showDrawer = useDrawer();
|
||||
|
||||
const { container } = defineProps<{ container: Container }>();
|
||||
@@ -141,6 +174,17 @@ const downloadUrl = computed(() =>
|
||||
);
|
||||
|
||||
const disableRestart = computed(() => actionStates.stop || actionStates.start || actionStates.restart);
|
||||
|
||||
const toggleAllLevels = computed({
|
||||
get: () => levels.value.size === allLevels.length,
|
||||
set: (value) => {
|
||||
if (value) {
|
||||
allLevels.forEach((level) => levels.value.add(level));
|
||||
} else {
|
||||
levels.value.clear();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
@@ -151,4 +195,11 @@ li.line {
|
||||
a {
|
||||
@apply whitespace-nowrap;
|
||||
}
|
||||
|
||||
.menu li ul {
|
||||
margin-inline-start: 0;
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
</span>
|
||||
</router-link>
|
||||
<template #content>
|
||||
<ContainerPopup :container="item" />
|
||||
<ContainerPopup :container="item as Container" />
|
||||
</template>
|
||||
</Popup>
|
||||
</li>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { createRouter, createWebHistory } from "vue-router";
|
||||
import { default as Component } from "./EventSource.vue";
|
||||
import LogViewer from "@/components/LogViewer/LogViewer.vue";
|
||||
import { Container } from "@/models/Container";
|
||||
import { Level } from "@/models/LogEntry";
|
||||
|
||||
vi.mock("@/stores/config", () => ({
|
||||
__esModule: true,
|
||||
@@ -67,7 +68,7 @@ describe("<ContainerEventSource />", () => {
|
||||
],
|
||||
});
|
||||
|
||||
return mount(Component<Container>, {
|
||||
return mount(Component, {
|
||||
global: {
|
||||
plugins: [router, createTestingPinia({ createSpy: vi.fn }), createI18n({})],
|
||||
components: {
|
||||
@@ -82,6 +83,7 @@ describe("<ContainerEventSource />", () => {
|
||||
containers: computed(() => [{ id: "abc", image: "test:v123", host: "localhost" }]),
|
||||
streamConfig: reactive({ stdout: true, stderr: true }),
|
||||
hasComplexLogs: ref(false),
|
||||
levels: new Set<Level>(["info"]),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -97,7 +99,7 @@ describe("<ContainerEventSource />", () => {
|
||||
});
|
||||
}
|
||||
|
||||
const sourceUrl = "/api/hosts/localhost/containers/abc/logs/stream?stdout=1&stderr=1";
|
||||
const sourceUrl = "/api/hosts/localhost/containers/abc/logs/stream?stdout=1&stderr=1&levels=info";
|
||||
|
||||
test("renders loading correctly", async () => {
|
||||
const wrapper = createLogEventSource();
|
||||
|
||||
@@ -22,42 +22,16 @@
|
||||
</div>
|
||||
</label>
|
||||
</section>
|
||||
<table class="table table-zebra table-pin-rows table-md" v-if="!evaluating && isReady">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in page" :key="row">
|
||||
<td v-for="column in columns" :key="column">{{ row[column] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-md animate-pulse" v-else>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="_ in 3">
|
||||
<div class="h-4 w-20 animate-pulse bg-base-content/50 opacity-50"></div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="_ in 9">
|
||||
<td v-for="_ in 3">
|
||||
<div class="h-4 w-20 bg-base-content/50 opacity-20"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<SQLTable :table="page" :loading="evaluating || !isReady" />
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<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");
|
||||
const query = ref("SELECT * FROM logs LIMIT 100");
|
||||
const error = ref<string | null>(null);
|
||||
const debouncedQuery = debouncedRef(query, 500);
|
||||
const evaluating = ref(false);
|
||||
@@ -115,13 +89,9 @@ const results = computedAsync(
|
||||
},
|
||||
);
|
||||
|
||||
whenever(evaluating, () => {
|
||||
error.value = null;
|
||||
});
|
||||
|
||||
const columns = computed(() =>
|
||||
results.value.numRows > 0 ? Object.keys(results.value.get(0) as Record<string, any>) : [],
|
||||
);
|
||||
const page = computed(() => (results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value));
|
||||
whenever(evaluating, () => (error.value = null));
|
||||
const page = computed(() =>
|
||||
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
|
||||
) as unknown as ComputedRef<Table<Record<string, any>>>;
|
||||
</script>
|
||||
<style lang="postcss" scoped></style>
|
||||
|
||||
@@ -48,7 +48,9 @@
|
||||
<tr>
|
||||
<th class="w-60">Field</th>
|
||||
<th class="mobile-hidden">Value</th>
|
||||
<th class="w-20"><input type="checkbox" class="toggle toggle-primary" @change="toggleAll($event)" /></th>
|
||||
<th class="w-20">
|
||||
<input type="checkbox" class="toggle toggle-primary" v-model="toggleAllFields" title="Toggle all" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ref="list">
|
||||
@@ -85,21 +87,11 @@ function toggleField(key: string[]) {
|
||||
visibleKeys.value = new Map<string[], boolean>(fields.value.map(({ key }) => [key, true]));
|
||||
}
|
||||
|
||||
const enabled = visibleKeys.value.get(key);
|
||||
const enabled = visibleKeys.value.get(key) ?? true;
|
||||
|
||||
visibleKeys.value.set(key, !enabled);
|
||||
}
|
||||
|
||||
function toggleAll(e: Event) {
|
||||
if (visibleKeys.value.size === 0) {
|
||||
visibleKeys.value = new Map<string[], boolean>(fields.value.map(({ key }) => [key, true]));
|
||||
}
|
||||
|
||||
const enabled = e.target instanceof HTMLInputElement && e.target.checked;
|
||||
for (const key of visibleKeys.value.keys()) {
|
||||
visibleKeys.value.set(key, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
const fields = computed({
|
||||
get() {
|
||||
const fieldsWithValue: { key: string[]; value: any; enabled: boolean }[] = [];
|
||||
@@ -116,7 +108,7 @@ const fields = computed({
|
||||
|
||||
for (const [key, value] of allFields) {
|
||||
if ([...visibleKeys.value.keys()].findIndex((k) => arrayEquals(k, key)) === -1) {
|
||||
fieldsWithValue.push({ key, value, enabled: false });
|
||||
fieldsWithValue.push({ key, value, enabled: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,6 +124,22 @@ const fields = computed({
|
||||
},
|
||||
});
|
||||
|
||||
const toggleAllFields = computed({
|
||||
get: () => fields.value.every(({ enabled }) => enabled),
|
||||
set(value) {
|
||||
if (visibleKeys.value.size === 0) {
|
||||
visibleKeys.value = new Map<string[], boolean>(fields.value.map(({ key }) => [key, true]));
|
||||
}
|
||||
for (const key of visibleKeys.value.keys()) {
|
||||
visibleKeys.value.set(key, value);
|
||||
}
|
||||
|
||||
for (const field of fields.value) {
|
||||
visibleKeys.value.set(field.key, value);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function syntaxHighlight(json: any) {
|
||||
json = JSON.stringify(json, null, 2);
|
||||
return json.replace(
|
||||
@@ -149,7 +157,7 @@ function syntaxHighlight(json: any) {
|
||||
} else if (/null/.test(match)) {
|
||||
cls = "json-null";
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + "</span>";
|
||||
return `<span class="${cls}">${match}</span>`;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,10 @@ useIntersectionObserver(
|
||||
> li {
|
||||
@apply py-0;
|
||||
}
|
||||
|
||||
:deep(.tag) {
|
||||
@apply rounded-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<table class="table table-zebra table-pin-rows table-md" v-if="!loading">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="column in columns" :key="column">{{ column }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in table" :key="row">
|
||||
<td v-for="column in columns" :key="column">{{ row[column] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-md animate-pulse" v-else>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="_ in 3">
|
||||
<div class="h-4 w-20 animate-pulse bg-base-content/50 opacity-50"></div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="_ in 9">
|
||||
<td v-for="_ in 3">
|
||||
<div class="h-4 w-20 bg-base-content/50 opacity-20"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { type Table } from "@apache-arrow/esnext-esm";
|
||||
|
||||
const { loading, table } = defineProps<{
|
||||
loading: boolean;
|
||||
table: Table<Record<string, any>>;
|
||||
}>();
|
||||
|
||||
const columns = computed(() => (table.numRows > 0 ? Object.keys(table.get(0) as Record<string, any>) : []));
|
||||
</script>
|
||||
@@ -23,8 +23,8 @@ import stripAnsi from "strip-ansi";
|
||||
|
||||
const ansiConvertor = new AnsiConvertor({
|
||||
escapeXML: false,
|
||||
fg: "var(--base-content-color)",
|
||||
bg: "var(--base-color)",
|
||||
fg: "oklch(var(--base-content-color))",
|
||||
bg: "oklch(var(--base-color))",
|
||||
});
|
||||
|
||||
const { showContainerName = false } = defineProps<{
|
||||
@@ -38,7 +38,7 @@ const linkify = (text: string) =>
|
||||
text.replace(urlPattern, (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`);
|
||||
</script>
|
||||
<style scoped lang="postcss">
|
||||
.log-wrapper > :deep(a) {
|
||||
.log-wrapper :deep(a) {
|
||||
@apply text-primary underline-offset-4 hover:underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<div data-v-a49e52d4="" data-v-cf9ff940="" class="relative flex w-full items-start gap-x-2">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" data-v-a49e52d4="" class="mt-1.5 size-2.5 flex-none rounded-lg flex"></div>
|
||||
@@ -25,7 +25,7 @@ exports[`<ContainerEventSource /> > render html correctly > should render dates
|
||||
<div data-v-a49e52d4="" data-v-cf9ff940="" class="relative flex w-full items-start gap-x-2">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" data-v-a49e52d4="" class="mt-1.5 size-2.5 flex-none rounded-lg flex"></div>
|
||||
@@ -44,7 +44,7 @@ exports[`<ContainerEventSource /> > render html correctly > should render messag
|
||||
<div data-v-a49e52d4="" data-v-cf9ff940="" class="relative flex w-full items-start gap-x-2">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div data-v-961504e7="" data-v-a49e52d4="" class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em] select-none" size="small">
|
||||
<div class="inline-flex gap-2 whitespace-nowrap text-blue"><time datetime="2019-06-12T10:55:42.459Z" class="mobile-hidden">06/12/2019</time><time datetime="2019-06-12T10:55:42.459Z">10:55:42 AM</time></div>
|
||||
</div>
|
||||
<div data-v-e625cddd="" data-v-a49e52d4="" class="mt-1.5 size-2.5 flex-none rounded-lg flex"></div>
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
<aside class="fixed h-screen w-[inherit] overflow-auto p-3" data-testid="navigation">
|
||||
<h1>
|
||||
<router-link :to="{ name: '/' }">
|
||||
<svg class="h-14 w-28 fill-secondary">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
<LogoWithText class="logo h-16 w-40" />
|
||||
</router-link>
|
||||
|
||||
<small class="mb-4 block text-xs font-light" v-if="hostname">
|
||||
@@ -28,5 +26,18 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LogoWithText from "@/logo-text.svg";
|
||||
const { hostname } = config;
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.logo {
|
||||
:deep(.content-fill) {
|
||||
@apply fill-base-content;
|
||||
}
|
||||
|
||||
:deep(.secondary-fill) {
|
||||
@apply fill-secondary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ul class="menu dropdown-content z-50 mt-1 w-52 rounded-box border border-base-content/20 bg-base p-2 shadow">
|
||||
<slot>
|
||||
<li v-for="item in options">
|
||||
<a @click="modelValue = item.value">
|
||||
<a @click="update(item.value as T)">
|
||||
<mdi:check class="w-4" v-if="modelValue == item.value" />
|
||||
<div v-else class="w-4"></div>
|
||||
{{ item.label }}
|
||||
@@ -24,17 +24,19 @@ type DropdownItem = {
|
||||
value: T;
|
||||
};
|
||||
|
||||
const { modelValue } = defineModels<{
|
||||
modelValue: T;
|
||||
}>();
|
||||
const model = defineModel<T>();
|
||||
|
||||
const { options = [], defaultLabel = "" } = defineProps<{
|
||||
options?: DropdownItem[];
|
||||
const { options, defaultLabel = "" } = defineProps<{
|
||||
options: DropdownItem[];
|
||||
defaultLabel?: string;
|
||||
}>();
|
||||
|
||||
const label = computed(() => options.find((item) => item.value === modelValue.value)?.label ?? defaultLabel);
|
||||
const label = computed(() => options.find((item) => item.value === model.value)?.label ?? defaultLabel);
|
||||
const details = ref<HTMLElement | null>(null);
|
||||
const close = () => details.value?.removeAttribute("open");
|
||||
watch(modelValue, () => close());
|
||||
|
||||
const update = (value: T) => {
|
||||
model.value = value;
|
||||
close();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
<nav class="fixed top-0 z-10 w-full border-b border-base-content/20 bg-base p-2" data-testid="navigation">
|
||||
<div class="flex items-center">
|
||||
<router-link :to="{ name: '/' }">
|
||||
<svg class="h-14 w-28 fill-secondary">
|
||||
<use href="#logo"></use>
|
||||
</svg>
|
||||
<Logo class="logo h-8" />
|
||||
</router-link>
|
||||
|
||||
<div class="ml-auto flex items-center gap-2">
|
||||
@@ -28,6 +26,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Logo from "@/logo.svg";
|
||||
const route = useRoute();
|
||||
|
||||
const show = ref(false);
|
||||
@@ -59,4 +58,10 @@ li.exited {
|
||||
.fade-leave-to .menu {
|
||||
@apply -translate-y-2;
|
||||
}
|
||||
|
||||
.logo {
|
||||
:deep(.secondary-fill) {
|
||||
@apply fill-secondary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em]" :size="size">
|
||||
<div class="tag inline-flex items-center justify-center rounded bg-base-lighter px-2 py-[0.2em]" :size="size">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<slot />
|
||||
</template>
|
||||
<template #input>
|
||||
<input type="checkbox" class="toggle toggle-primary" v-model="modelValue" />
|
||||
<input type="checkbox" class="toggle toggle-primary" v-model="modelValue" v-bind="$attrs" />
|
||||
</template>
|
||||
</LabeledInput>
|
||||
</template>
|
||||
|
||||
@@ -104,21 +104,20 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
|
||||
buffer.value = [];
|
||||
}
|
||||
|
||||
const { streamConfig, hasComplexLogs } = useLoggingContext();
|
||||
const { streamConfig, hasComplexLogs, levels } = useLoggingContext();
|
||||
|
||||
const params = computed(() => {
|
||||
const params = Object.entries(toValue(streamConfig))
|
||||
.filter(([, value]) => value)
|
||||
.reduce((acc, [key]) => ({ ...acc, [key]: "1" }), {} as Record<string, string>);
|
||||
|
||||
if (isSearching.value) {
|
||||
params["filter"] = debouncedSearchFilter.value;
|
||||
const params = new URLSearchParams();
|
||||
if (streamConfig.value.stdout) params.append("stdout", "1");
|
||||
if (streamConfig.value.stderr) params.append("stderr", "1");
|
||||
if (isSearching.value) params.append("filter", debouncedSearchFilter.value);
|
||||
for (const level of levels.value) {
|
||||
params.append("levels", level);
|
||||
}
|
||||
|
||||
return params;
|
||||
});
|
||||
|
||||
const urlWithParams = computed(() => withBase(`${url.value}?${new URLSearchParams(params.value).toString()}`));
|
||||
const urlWithParams = computed(() => withBase(`${url.value}?${params.value.toString()}`));
|
||||
|
||||
function connect({ clear } = { clear: true }) {
|
||||
close();
|
||||
@@ -170,10 +169,14 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
|
||||
const signal = abortController.signal;
|
||||
isLoadingMore.value = true;
|
||||
try {
|
||||
const moreParams = { ...params.value, from: from.toISOString(), to: to.toISOString(), minimum: "100" };
|
||||
const urlWithMoreParams = computed(() =>
|
||||
withBase(`${loadMoreUrl.value}?${new URLSearchParams(moreParams).toString()}`),
|
||||
);
|
||||
const urlWithMoreParams = computed(() => {
|
||||
const loadMoreParams = new URLSearchParams(params.value);
|
||||
loadMoreParams.append("from", from.toISOString());
|
||||
loadMoreParams.append("to", to.toISOString());
|
||||
loadMoreParams.append("minimum", "100");
|
||||
|
||||
return withBase(`${loadMoreUrl.value}?${loadMoreParams.toString()}`);
|
||||
});
|
||||
const stopWatcher = watchOnce(urlWithMoreParams, () => abortController.abort("stream changed"));
|
||||
const logs = await (await fetch(urlWithMoreParams.value, { signal })).text();
|
||||
stopWatcher();
|
||||
@@ -194,7 +197,11 @@ function useLogStream(url: Ref<string>, loadMoreUrl?: Ref<string>) {
|
||||
|
||||
onScopeDispose(() => close());
|
||||
|
||||
watch(messages, () => (hasComplexLogs.value = messages.value.some((m) => m instanceof ComplexLogEntry)));
|
||||
watch(messages, () => {
|
||||
if (messages.value.length > 1) {
|
||||
hasComplexLogs.value = messages.value.some((m) => m instanceof ComplexLogEntry);
|
||||
}
|
||||
});
|
||||
|
||||
return { messages, loadOlderLogs, isLoadingMore, hasComplexLogs };
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
import { Container } from "@/models/Container";
|
||||
import { Level } from "@/models/LogEntry";
|
||||
|
||||
type LogContext = {
|
||||
streamConfig: { stdout: boolean; stderr: boolean };
|
||||
containers: Container[];
|
||||
loadingMore: boolean;
|
||||
hasComplexLogs: boolean;
|
||||
levels: Set<Level>;
|
||||
};
|
||||
|
||||
export const allLevels: Level[] = [
|
||||
"info",
|
||||
"debug",
|
||||
"warn",
|
||||
"error",
|
||||
"fatal",
|
||||
"trace",
|
||||
"warning",
|
||||
"critical",
|
||||
"unknown",
|
||||
];
|
||||
|
||||
// export for testing
|
||||
export const loggingContextKey = Symbol("loggingContext") as InjectionKey<LogContext>;
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
@@ -21,6 +35,7 @@ export const provideLoggingContext = (containers: Ref<Container[]>) => {
|
||||
containers,
|
||||
loadingMore: false,
|
||||
hasComplexLogs: false,
|
||||
levels: new Set<Level>(allLevels),
|
||||
}),
|
||||
);
|
||||
};
|
||||
@@ -33,6 +48,7 @@ export const useLoggingContext = () => {
|
||||
containers: [],
|
||||
loadingMore: false,
|
||||
hasComplexLogs: false,
|
||||
levels: new Set<Level>(allLevels),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="128" height="128" rx="6" fill="#222222"/>
|
||||
<path d="M82.3248 94.3863H123V104.093H67.8025V95.3506L106.164 44.3736H68.3808V34.5382H121.072V42.9594L82.3248 94.3863Z" fill="#FFDD57"/>
|
||||
<path d="M8 107.107L17.5656 14L43.8372 16.7013C51.9339 17.5338 58.9091 20.0604 64.7629 24.2812C70.6166 28.5019 74.8873 34.0893 77.5749 41.0432C80.3052 48.0016 81.2514 55.7674 80.4137 64.3407L79.8027 70.2877C78.9005 79.0698 76.4053 86.5894 72.3173 92.8468C68.2719 99.1084 62.914 103.684 56.2436 106.574C49.6158 109.468 42.1213 110.529 33.7602 109.755L8 107.107ZM28.8005 25.3655L21.3043 98.3288L34.2164 99.6565C43.6767 100.629 51.3299 98.4435 57.1758 93.0993C63.0644 87.7595 66.5671 79.6542 67.684 68.7832L68.2424 63.3477C69.3286 52.7752 67.6788 44.3123 63.293 37.9592C58.9542 31.5678 52.2295 27.8607 43.1188 26.8377L28.8005 25.3655Z" fill="#FFDD57"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 949 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 396 114"><path class="secondary-fill" d="M89.408 46.477a6.49 6.49 0 0 0-6.488 6.49 6.488 6.488 0 1 0 12.978 0 6.49 6.49 0 0 0-6.49-6.49m-42.836 0a6.49 6.49 0 1 0 0 12.98 6.49 6.49 0 0 0 0-12.98M28.5 38.295a6.5 6.5 0 0 1-1.897-4.593 6.474 6.474 0 0 1 6.49-6.49c1.663 0 3.327.631 4.592 1.896l-1.517 1.12a51.67 51.67 0 0 1 31.822-10.91c11.999 0 23.028 4.078 31.823 10.91L98.3 29.113a6.47 6.47 0 0 1 4.592-1.897c1.659 0 3.324.63 4.588 1.897a6.52 6.52 0 0 1 1.892 4.593 6.47 6.47 0 0 1-1.892 4.594l1.514 1.113c21.944 21.942-15.406 31.822-15.406 31.822H42.392c-1.077 0-38.88-8.35-15.406-31.822zM102.214 94.411a7.894 7.894 0 0 1-7.894-7.895 7.893 7.893 0 1 1 15.787 0 7.89 7.89 0 0 1-7.893 7.895M37.355 95.13a7.894 7.894 0 0 1-7.895-7.896 7.894 7.894 0 0 1 7.895-7.893 7.894 7.894 0 0 1 7.896 7.893 7.894 7.894 0 0 1-7.896 7.895M44.372 72.866h47.402s-22.981 7.899-47.402 0"/><path class="content-fill" d="M142 79.928V33.446h13.836c3.571 0 6.886.574 9.947 1.786 3.06 1.147 5.675 2.805 7.779 4.846 4.272 4.144 6.822 10.01 6.822 16.514 0 3.379-.637 6.567-1.913 9.5-1.275 2.933-3.06 5.356-5.228 7.396-4.4 4.017-10.648 6.44-17.407 6.44zm4.91-41.89v37.3h8.735c3.889 0 7.332-.83 10.265-2.423 2.997-1.595 5.356-3.762 6.95-6.568 1.658-2.805 2.487-6.057 2.487-9.628 0-5.292-1.977-10.01-5.356-13.39-3.315-3.315-8.48-5.292-14.346-5.292zm86.587 18.554c0 4.4-1.02 8.416-2.997 12.05q-3.06 5.452-8.416 8.608c-3.634 2.104-7.588 3.188-12.051 3.188-3.252 0-6.312-.637-9.245-1.849-2.869-1.211-5.356-2.869-7.397-5.037-2.04-2.04-3.634-4.527-4.845-7.46-1.148-2.933-1.786-5.993-1.786-9.245q0-6.6 3.061-12.051c1.976-3.635 4.782-6.568 8.416-8.672C201.808 34.02 205.825 33 210.224 33c3.252 0 6.313.574 9.246 1.785 2.869 1.276 5.356 2.933 7.396 4.974 2.04 2.168 3.698 4.654 4.846 7.523 1.211 2.934 1.785 5.994 1.785 9.31m-5.037.255c0-5.229-1.913-10.075-5.101-13.581s-7.97-5.739-13.326-5.739c-3.443 0-6.567.893-9.373 2.55-2.805 1.786-4.973 4.081-6.503 6.95q-2.296 4.4-2.296 9.565c0 5.164 1.913 10.074 5.101 13.517 3.188 3.507 7.97 5.739 13.262 5.739 3.444 0 6.568-.893 9.373-2.615 2.87-1.657 5.037-4.017 6.568-6.886 1.53-2.87 2.295-6.057 2.295-9.5m43.932 18.618v4.463h-33.539v-4.463l27.672-37.555H239.81v-4.464h32.454v4.464l-27.8 37.555zm38.192 0v4.463h-33.538v-4.463l27.672-37.555h-26.715v-4.464h32.454v4.464l-27.8 37.555zm8.927 4.463V33.446h4.91v41.891h22.061v4.591zm34.622 0V33.446h29.075v4.527h-24.165v16.068h22.125v4.527h-22.125v16.833h24.42v4.527z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 97 76" fill="none"><path class="secondary-fill" d="M70.091 27.16a6.49 6.49 0 0 0-6.488 6.49 6.488 6.488 0 1 0 12.978 0 6.49 6.49 0 0 0-6.49-6.49m-42.836 0a6.49 6.49 0 1 0 0 12.98 6.49 6.49 0 0 0 0-12.98M9.182 18.977a6.5 6.5 0 0 1-1.898-4.592 6.474 6.474 0 0 1 6.49-6.49c1.664 0 3.327.631 4.593 1.896l-1.517 1.12A51.67 51.67 0 0 1 48.672 0C60.671 0 71.7 4.08 80.495 10.911l-1.512-1.115A6.46 6.46 0 0 1 83.575 7.9c1.659 0 3.324.63 4.587 1.897a6.51 6.51 0 0 1 1.893 4.593 6.47 6.47 0 0 1-1.893 4.594l1.515 1.113c21.944 21.942-15.406 31.822-15.406 31.822H23.075c-1.077 0-38.88-8.35-15.406-31.822zM82.897 75.094a7.894 7.894 0 0 1-7.894-7.895 7.893 7.893 0 1 1 15.787 0 7.893 7.893 0 0 1-7.893 7.895M18.038 75.812a7.894 7.894 0 0 1-7.895-7.895 7.894 7.894 0 0 1 7.895-7.894 7.894 7.894 0 0 1 7.896 7.894 7.894 7.894 0 0 1-7.896 7.895M25.055 53.549h47.402s-22.981 7.899-47.402 0"/></svg>
|
||||
|
After Width: | Height: | Size: 934 B |
@@ -29,7 +29,7 @@
|
||||
--base-darker-color: 11% 0 0;
|
||||
--base-content-color: 89.23% 0 0;
|
||||
--primary-color: 70.96% 0.143 176.65;
|
||||
--secondary-color: 91.36% 0.11098 90.1243;
|
||||
--secondary-color: 81.38% 0.1448 90.1243;
|
||||
}
|
||||
|
||||
html[data-theme="light"] {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, ComputedRef, Ref } from "vue";
|
||||
import { flattenJSON, getDeep } from "@/utils";
|
||||
import { flattenJSON } from "@/utils";
|
||||
import ComplexLogItem from "@/components/LogViewer/ComplexLogItem.vue";
|
||||
import SimpleLogItem from "@/components/LogViewer/SimpleLogItem.vue";
|
||||
import ContainerEventLogItem from "@/components/LogViewer/ContainerEventLogItem.vue";
|
||||
@@ -9,7 +9,17 @@ export type JSONValue = string | number | boolean | JSONObject | Array<JSONValue
|
||||
export type JSONObject = { [x: string]: JSONValue };
|
||||
export type Position = "start" | "end" | "middle" | undefined;
|
||||
export type Std = "stdout" | "stderr";
|
||||
export type Level = "debug" | "info" | "warn" | "error" | "fatal" | "trace" | "unknown";
|
||||
export type Level =
|
||||
| "error"
|
||||
| "warn"
|
||||
| "warning"
|
||||
| "info"
|
||||
| "debug"
|
||||
| "trace"
|
||||
| "severe"
|
||||
| "critical"
|
||||
| "fatal"
|
||||
| "unknown";
|
||||
export interface LogEvent {
|
||||
readonly m: string | JSONObject;
|
||||
readonly ts: number;
|
||||
@@ -75,10 +85,18 @@ export class ComplexLogEntry extends LogEntry<JSONObject> {
|
||||
if (visibleKeys.value.size === 0) {
|
||||
return flattenJSON(message);
|
||||
} else {
|
||||
const keys = Array.from(visibleKeys.value.entries())
|
||||
.filter(([, value]) => value)
|
||||
.map(([key]) => key);
|
||||
return keys.reduce((acc, attr) => ({ ...acc, [attr.join(".")]: getDeep(message, attr) }), {});
|
||||
const flatJSON = flattenJSON(message);
|
||||
const filteredJSON: Record<string, any> = {};
|
||||
for (const [keys, enabled] of visibleKeys.value.entries()) {
|
||||
const key = keys.join(".");
|
||||
if (!enabled) {
|
||||
delete flatJSON[key];
|
||||
continue;
|
||||
}
|
||||
filteredJSON[key] = flatJSON[key];
|
||||
delete flatJSON[key];
|
||||
}
|
||||
return { ...filteredJSON, ...flatJSON };
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -36,8 +36,7 @@
|
||||
{{ $t("settings.locale") }}
|
||||
</template>
|
||||
<template #input>
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
<DropdownMenu
|
||||
v-model="locale"
|
||||
:options="[
|
||||
{ label: 'Auto', value: '' },
|
||||
@@ -53,8 +52,7 @@
|
||||
</template>
|
||||
<template #input>
|
||||
<div class="flex gap-2">
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
<DropdownMenu
|
||||
v-model="dateLocale"
|
||||
:options="[
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
@@ -64,8 +62,7 @@
|
||||
{ label: 'YYYY-MM-DD', value: 'en-CA' },
|
||||
]"
|
||||
/>
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
<DropdownMenu
|
||||
v-model="hourStyle"
|
||||
:options="[
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
@@ -82,8 +79,7 @@
|
||||
{{ $t("settings.font-size") }}
|
||||
</template>
|
||||
<template #input>
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
<DropdownMenu
|
||||
v-model="size"
|
||||
:options="[
|
||||
{ label: 'Small', value: 'small' },
|
||||
@@ -99,8 +95,7 @@
|
||||
{{ $t("settings.color-scheme") }}
|
||||
</template>
|
||||
<template #input>
|
||||
<!-- @vue-ignore -->
|
||||
<dropdown-menu
|
||||
<DropdownMenu
|
||||
v-model="lightTheme"
|
||||
:options="[
|
||||
{ label: 'Auto', value: 'auto' },
|
||||
|
||||
@@ -94,7 +94,7 @@ services:
|
||||
|
||||
playwright:
|
||||
container_name: playwright
|
||||
image: mcr.microsoft.com/playwright:v1.47.2-jammy
|
||||
image: mcr.microsoft.com/playwright:v1.48.2-jammy
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- .:/app
|
||||
|
||||
@@ -27,6 +27,7 @@ export default defineConfig({
|
||||
],
|
||||
],
|
||||
themeConfig: {
|
||||
logo: "/logo.svg",
|
||||
search: {
|
||||
provider: "local",
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { useMutationObserver } from "@vueuse/core";
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
const isDark = ref(false);
|
||||
onMounted(() => {
|
||||
@@ -16,14 +16,6 @@ onMounted(() => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.classList.add("home");
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
document.documentElement.classList.remove("home");
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -149,19 +149,17 @@
|
||||
|
||||
.VPHomeHero .name {
|
||||
@apply text-7xl font-light;
|
||||
font-family: "Playfair Display Variable", serif;
|
||||
}
|
||||
|
||||
.VPNavBarTitle .title {
|
||||
@apply text-3xl font-light;
|
||||
color: var(--bar-title-color);
|
||||
font-family: "Playfair Display Variable", serif;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.VPHero .container .image {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.home .VPNav .container {
|
||||
.VPNavBar.home .container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,34 @@ users:
|
||||
|
||||
Dozzle uses [JWT](https://en.wikipedia.org/wiki/JSON_Web_Token) to generate tokens for authentication. This token is saved in a cookie.
|
||||
|
||||
### Extending Authentication Cookie Lifetime
|
||||
|
||||
By default, Dozzle uses session cookies which expire when the browser is closed. You can extend the lifetime of the cookie by setting `--auth-ttl` to a duration. Here is an example:
|
||||
|
||||
::: code-group
|
||||
|
||||
```sh [cli]
|
||||
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/dozzle/data:/data -p 8080:8080 amir20/dozzle --auth-provider simple --auth-ttl 48h
|
||||
```
|
||||
|
||||
```yaml [docker-compose.yml]
|
||||
services:
|
||||
dozzle:
|
||||
image: amir20/dozzle:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /path/to/dozzle/data:/data
|
||||
ports:
|
||||
- 8080:8080
|
||||
environment:
|
||||
DOZZLE_AUTH_PROVIDER: simple
|
||||
DOZZLE_AUTH_TTL: 48h
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Note that only the duration is supported. You can only use `s`, `m`, `h` for seconds, minutes and hours respectively.
|
||||
|
||||
## Generating users.yml
|
||||
|
||||
Dozzle has a builtin `generate` command to generate `users.yml`. Here is an example:
|
||||
|
||||
@@ -90,3 +90,11 @@ time="2024-07-10T13:35:53Z" level=warning msg="duplicate host ID: *********, End
|
||||
Dozzle uses the Docker API to gather information about the hosts. Each host must have a unique ID. This ID is used to identify the host in the UI. In swarm mode, Dozzle uses the node ID from `docker systen info` to identify the host. If you are not using swarm mode, then Dozzle will use the system ID from `docker system info` as the host ID.
|
||||
|
||||
Somettimes, VMs maybe restored from back ups, with the same host ID. This can cause Dozzle to think that the host is already present and skip adding it to the list of hosts. To fix this, you need to remove `/var/lib/docker/engine-id` file. This file contains the host ID and is created when the Docker daemon starts.
|
||||
|
||||
## Why am I only seeing running containers? How do I see stopped containers?
|
||||
|
||||
By default, Dozzle only shows running containers. To see stopped containers, you need to enable the `Show Stopped Containers` option in the settings. This option is disabled by default to reduce the number of containers shown in the UI.
|
||||
|
||||
## Is there a way to sync my settings across multiple instances of Dozzle?
|
||||
|
||||
In single-user mode, Dozzle stores the settings in the browser's local storage. This means that the settings are only available on the browser where they were set. For Dozzle to enable syncing settings across multiple instances, it needs to know who the user is. In multi-user mode, Dozzle uses the user's username to store the settings on disk and sync them across multiple instances. This information is stored in `/data` directory. If you want to sync settings across multiple instances, you need to [enable](/guide/authentication) multi-user mode and provide a username.
|
||||
|
||||
@@ -49,7 +49,7 @@ docker container run --privileged -e CONTAINERS=1 -e INFO=1 -v /var/run/docker.s
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> Using `CONTAINERS=1` is required to list running containers. `EVENTS` is also needed but it is enabled by default. `INFO=1` is optional but it will provide more information on host meta data.
|
||||
> Using `CONTAINERS=1` is required to list running containers. `EVENTS` is also needed but it is enabled by default. `INFO=1` is needed to list system information.
|
||||
|
||||
Running Dozzle without any certs should work. Here is an example:
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 97 76" width="97" height="76" fill="none"><path fill="oklch(81.38% .1448 90.1243)" d="M70.091 27.16a6.49 6.49 0 0 0-6.488 6.49 6.488 6.488 0 1 0 12.978 0 6.49 6.49 0 0 0-6.49-6.49m-42.836 0a6.49 6.49 0 1 0 0 12.98 6.49 6.49 0 0 0 0-12.98M9.182 18.977a6.5 6.5 0 0 1-1.898-4.592 6.474 6.474 0 0 1 6.49-6.49c1.664 0 3.327.631 4.593 1.896l-1.517 1.12A51.67 51.67 0 0 1 48.672 0C60.671 0 71.7 4.08 80.495 10.911l-1.512-1.115A6.46 6.46 0 0 1 83.575 7.9c1.659 0 3.324.63 4.587 1.897a6.51 6.51 0 0 1 1.893 4.593 6.47 6.47 0 0 1-1.893 4.594l1.515 1.113c21.944 21.942-15.406 31.822-15.406 31.822H23.075c-1.077 0-38.88-8.35-15.406-31.822zM82.897 75.094a7.894 7.894 0 0 1-7.894-7.895 7.893 7.893 0 1 1 15.787 0 7.893 7.893 0 0 1-7.893 7.895M18.038 75.812a7.894 7.894 0 0 1-7.895-7.895 7.894 7.894 0 0 1 7.895-7.894 7.894 7.894 0 0 1 7.896 7.894 7.894 7.894 0 0 1-7.896 7.895M25.055 53.549h47.402s-22.981 7.899-47.402 0"/></svg>
|
||||
|
After Width: | Height: | Size: 969 B |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@@ -19,7 +19,7 @@ require (
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -31,11 +31,11 @@ require (
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/samber/lo v1.47.0
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8
|
||||
github.com/yuin/goldmark v1.7.4
|
||||
golang.org/x/crypto v0.27.0
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/sync v0.8.0
|
||||
google.golang.org/grpc v1.67.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
google.golang.org/grpc v1.67.1
|
||||
google.golang.org/protobuf v1.35.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -72,9 +72,9 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.22.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
gotest.tools/v3 v3.0.3 // indirect
|
||||
)
|
||||
|
||||
go 1.23.1
|
||||
go 1.23.2
|
||||
|
||||
@@ -137,6 +137,10 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
|
||||
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.6 h1:cZgJxVh5mL5cu8KOnwxvFJy5TFB0BHUskZZyq7TYbDg=
|
||||
github.com/yuin/goldmark v1.7.6/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
@@ -159,6 +163,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -196,6 +202,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -207,6 +215,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -227,8 +237,12 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
|
||||
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
@@ -61,13 +62,17 @@ func NewClient(endpoint string, certificates tls.Certificate, opts ...grpc.DialO
|
||||
}
|
||||
|
||||
func rpcErrToErr(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
status, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
if status.Code() == codes.Unknown && status.Message() == "EOF" {
|
||||
return fmt.Errorf("found EOF while streaming logs: %w", io.EOF)
|
||||
return fmt.Errorf("EOF error while converting gRPC to error: %w", io.EOF)
|
||||
}
|
||||
|
||||
switch status.Code() {
|
||||
@@ -77,8 +82,10 @@ func rpcErrToErr(err error) error {
|
||||
return fmt.Errorf("deadline exceeded: %v with %w", status.Message(), context.DeadlineExceeded)
|
||||
case codes.Unknown:
|
||||
return fmt.Errorf("unknown error: %v with %w", status.Message(), err)
|
||||
case codes.OK:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown error: %v with %w", status.Message(), err)
|
||||
return fmt.Errorf("unknown code: %v with %w", status.Code(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,9 +181,10 @@ func (c *Client) StreamRawBytes(ctx context.Context, containerID string, since t
|
||||
defer w.Close()
|
||||
for {
|
||||
resp, err := out.Recv()
|
||||
err = rpcErrToErr(err)
|
||||
if err != nil {
|
||||
if err == io.EOF || err == context.Canceled {
|
||||
err = rpcErrToErr(err)
|
||||
e := errors.Unwrap(err)
|
||||
if e == io.EOF || e == context.Canceled {
|
||||
return
|
||||
} else {
|
||||
log.Error().Err(err).Msg("agent client: failed to receive raw bytes")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.2
|
||||
// protoc v5.27.3
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc v5.28.3
|
||||
// source: rpc.proto
|
||||
|
||||
package pb
|
||||
@@ -29,11 +29,9 @@ type ListContainersRequest struct {
|
||||
|
||||
func (x *ListContainersRequest) Reset() {
|
||||
*x = ListContainersRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListContainersRequest) String() string {
|
||||
@@ -44,7 +42,7 @@ func (*ListContainersRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListContainersRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -69,11 +67,9 @@ type ListContainersResponse struct {
|
||||
|
||||
func (x *ListContainersResponse) Reset() {
|
||||
*x = ListContainersResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListContainersResponse) String() string {
|
||||
@@ -84,7 +80,7 @@ func (*ListContainersResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListContainersResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -116,11 +112,9 @@ type FindContainerRequest struct {
|
||||
|
||||
func (x *FindContainerRequest) Reset() {
|
||||
*x = FindContainerRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *FindContainerRequest) String() string {
|
||||
@@ -131,7 +125,7 @@ func (*FindContainerRequest) ProtoMessage() {}
|
||||
|
||||
func (x *FindContainerRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -163,11 +157,9 @@ type FindContainerResponse struct {
|
||||
|
||||
func (x *FindContainerResponse) Reset() {
|
||||
*x = FindContainerResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *FindContainerResponse) String() string {
|
||||
@@ -178,7 +170,7 @@ func (*FindContainerResponse) ProtoMessage() {}
|
||||
|
||||
func (x *FindContainerResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -212,11 +204,9 @@ type StreamLogsRequest struct {
|
||||
|
||||
func (x *StreamLogsRequest) Reset() {
|
||||
*x = StreamLogsRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamLogsRequest) String() string {
|
||||
@@ -227,7 +217,7 @@ func (*StreamLogsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StreamLogsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -273,11 +263,9 @@ type StreamLogsResponse struct {
|
||||
|
||||
func (x *StreamLogsResponse) Reset() {
|
||||
*x = StreamLogsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamLogsResponse) String() string {
|
||||
@@ -288,7 +276,7 @@ func (*StreamLogsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StreamLogsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -323,11 +311,9 @@ type LogsBetweenDatesRequest struct {
|
||||
|
||||
func (x *LogsBetweenDatesRequest) Reset() {
|
||||
*x = LogsBetweenDatesRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *LogsBetweenDatesRequest) String() string {
|
||||
@@ -338,7 +324,7 @@ func (*LogsBetweenDatesRequest) ProtoMessage() {}
|
||||
|
||||
func (x *LogsBetweenDatesRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -394,11 +380,9 @@ type StreamRawBytesRequest struct {
|
||||
|
||||
func (x *StreamRawBytesRequest) Reset() {
|
||||
*x = StreamRawBytesRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamRawBytesRequest) String() string {
|
||||
@@ -409,7 +393,7 @@ func (*StreamRawBytesRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StreamRawBytesRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -462,11 +446,9 @@ type StreamRawBytesResponse struct {
|
||||
|
||||
func (x *StreamRawBytesResponse) Reset() {
|
||||
*x = StreamRawBytesResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamRawBytesResponse) String() string {
|
||||
@@ -477,7 +459,7 @@ func (*StreamRawBytesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StreamRawBytesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -507,11 +489,9 @@ type StreamEventsRequest struct {
|
||||
|
||||
func (x *StreamEventsRequest) Reset() {
|
||||
*x = StreamEventsRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamEventsRequest) String() string {
|
||||
@@ -522,7 +502,7 @@ func (*StreamEventsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StreamEventsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -547,11 +527,9 @@ type StreamEventsResponse struct {
|
||||
|
||||
func (x *StreamEventsResponse) Reset() {
|
||||
*x = StreamEventsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamEventsResponse) String() string {
|
||||
@@ -562,7 +540,7 @@ func (*StreamEventsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StreamEventsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[10]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -592,11 +570,9 @@ type StreamStatsRequest struct {
|
||||
|
||||
func (x *StreamStatsRequest) Reset() {
|
||||
*x = StreamStatsRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamStatsRequest) String() string {
|
||||
@@ -607,7 +583,7 @@ func (*StreamStatsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StreamStatsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[11]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -632,11 +608,9 @@ type StreamStatsResponse struct {
|
||||
|
||||
func (x *StreamStatsResponse) Reset() {
|
||||
*x = StreamStatsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamStatsResponse) String() string {
|
||||
@@ -647,7 +621,7 @@ func (*StreamStatsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StreamStatsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[12]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -677,11 +651,9 @@ type HostInfoRequest struct {
|
||||
|
||||
func (x *HostInfoRequest) Reset() {
|
||||
*x = HostInfoRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HostInfoRequest) String() string {
|
||||
@@ -692,7 +664,7 @@ func (*HostInfoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HostInfoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[13]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -717,11 +689,9 @@ type HostInfoResponse struct {
|
||||
|
||||
func (x *HostInfoResponse) Reset() {
|
||||
*x = HostInfoResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HostInfoResponse) String() string {
|
||||
@@ -732,7 +702,7 @@ func (*HostInfoResponse) ProtoMessage() {}
|
||||
|
||||
func (x *HostInfoResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[14]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -762,11 +732,9 @@ type StreamContainerStartedRequest struct {
|
||||
|
||||
func (x *StreamContainerStartedRequest) Reset() {
|
||||
*x = StreamContainerStartedRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamContainerStartedRequest) String() string {
|
||||
@@ -777,7 +745,7 @@ func (*StreamContainerStartedRequest) ProtoMessage() {}
|
||||
|
||||
func (x *StreamContainerStartedRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[15]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -802,11 +770,9 @@ type StreamContainerStartedResponse struct {
|
||||
|
||||
func (x *StreamContainerStartedResponse) Reset() {
|
||||
*x = StreamContainerStartedResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StreamContainerStartedResponse) String() string {
|
||||
@@ -817,7 +783,7 @@ func (*StreamContainerStartedResponse) ProtoMessage() {}
|
||||
|
||||
func (x *StreamContainerStartedResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[16]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -850,11 +816,9 @@ type ContainerActionRequest struct {
|
||||
|
||||
func (x *ContainerActionRequest) Reset() {
|
||||
*x = ContainerActionRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerActionRequest) String() string {
|
||||
@@ -865,7 +829,7 @@ func (*ContainerActionRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerActionRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[17]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -902,11 +866,9 @@ type ContainerActionResponse struct {
|
||||
|
||||
func (x *ContainerActionResponse) Reset() {
|
||||
*x = ContainerActionResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_rpc_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_rpc_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerActionResponse) String() string {
|
||||
@@ -917,7 +879,7 @@ func (*ContainerActionResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerActionResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_rpc_proto_msgTypes[18]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -1173,236 +1135,6 @@ func file_rpc_proto_init() {
|
||||
return
|
||||
}
|
||||
file_types_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_rpc_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ListContainersRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ListContainersResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*FindContainerRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*FindContainerResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamLogsRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamLogsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*LogsBetweenDatesRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamRawBytesRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamRawBytesResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamEventsRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[10].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamEventsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[11].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamStatsRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[12].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamStatsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[13].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*HostInfoRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[14].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*HostInfoResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[15].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamContainerStartedRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[16].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*StreamContainerStartedResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[17].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ContainerActionRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_rpc_proto_msgTypes[18].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ContainerActionResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.4.0
|
||||
// - protoc v5.27.3
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.28.3
|
||||
// source: rpc.proto
|
||||
|
||||
package pb
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.62.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion8
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
AgentService_ListContainers_FullMethodName = "/protobuf.AgentService/ListContainers"
|
||||
@@ -37,12 +37,12 @@ const (
|
||||
type AgentServiceClient interface {
|
||||
ListContainers(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (*ListContainersResponse, error)
|
||||
FindContainer(ctx context.Context, in *FindContainerRequest, opts ...grpc.CallOption) (*FindContainerResponse, error)
|
||||
StreamLogs(ctx context.Context, in *StreamLogsRequest, opts ...grpc.CallOption) (AgentService_StreamLogsClient, error)
|
||||
LogsBetweenDates(ctx context.Context, in *LogsBetweenDatesRequest, opts ...grpc.CallOption) (AgentService_LogsBetweenDatesClient, error)
|
||||
StreamRawBytes(ctx context.Context, in *StreamRawBytesRequest, opts ...grpc.CallOption) (AgentService_StreamRawBytesClient, error)
|
||||
StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (AgentService_StreamEventsClient, error)
|
||||
StreamStats(ctx context.Context, in *StreamStatsRequest, opts ...grpc.CallOption) (AgentService_StreamStatsClient, error)
|
||||
StreamContainerStarted(ctx context.Context, in *StreamContainerStartedRequest, opts ...grpc.CallOption) (AgentService_StreamContainerStartedClient, error)
|
||||
StreamLogs(ctx context.Context, in *StreamLogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamLogsResponse], error)
|
||||
LogsBetweenDates(ctx context.Context, in *LogsBetweenDatesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamLogsResponse], error)
|
||||
StreamRawBytes(ctx context.Context, in *StreamRawBytesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamRawBytesResponse], error)
|
||||
StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamEventsResponse], error)
|
||||
StreamStats(ctx context.Context, in *StreamStatsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamStatsResponse], error)
|
||||
StreamContainerStarted(ctx context.Context, in *StreamContainerStartedRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamContainerStartedResponse], error)
|
||||
HostInfo(ctx context.Context, in *HostInfoRequest, opts ...grpc.CallOption) (*HostInfoResponse, error)
|
||||
ContainerAction(ctx context.Context, in *ContainerActionRequest, opts ...grpc.CallOption) (*ContainerActionResponse, error)
|
||||
}
|
||||
@@ -75,13 +75,13 @@ func (c *agentServiceClient) FindContainer(ctx context.Context, in *FindContaine
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) StreamLogs(ctx context.Context, in *StreamLogsRequest, opts ...grpc.CallOption) (AgentService_StreamLogsClient, error) {
|
||||
func (c *agentServiceClient) StreamLogs(ctx context.Context, in *StreamLogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamLogsResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[0], AgentService_StreamLogs_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceStreamLogsClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[StreamLogsRequest, StreamLogsResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -91,30 +91,16 @@ func (c *agentServiceClient) StreamLogs(ctx context.Context, in *StreamLogsReque
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_StreamLogsClient interface {
|
||||
Recv() (*StreamLogsResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamLogsClient = grpc.ServerStreamingClient[StreamLogsResponse]
|
||||
|
||||
type agentServiceStreamLogsClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamLogsClient) Recv() (*StreamLogsResponse, error) {
|
||||
m := new(StreamLogsResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) LogsBetweenDates(ctx context.Context, in *LogsBetweenDatesRequest, opts ...grpc.CallOption) (AgentService_LogsBetweenDatesClient, error) {
|
||||
func (c *agentServiceClient) LogsBetweenDates(ctx context.Context, in *LogsBetweenDatesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamLogsResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[1], AgentService_LogsBetweenDates_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceLogsBetweenDatesClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[LogsBetweenDatesRequest, StreamLogsResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -124,30 +110,16 @@ func (c *agentServiceClient) LogsBetweenDates(ctx context.Context, in *LogsBetwe
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_LogsBetweenDatesClient interface {
|
||||
Recv() (*StreamLogsResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_LogsBetweenDatesClient = grpc.ServerStreamingClient[StreamLogsResponse]
|
||||
|
||||
type agentServiceLogsBetweenDatesClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceLogsBetweenDatesClient) Recv() (*StreamLogsResponse, error) {
|
||||
m := new(StreamLogsResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) StreamRawBytes(ctx context.Context, in *StreamRawBytesRequest, opts ...grpc.CallOption) (AgentService_StreamRawBytesClient, error) {
|
||||
func (c *agentServiceClient) StreamRawBytes(ctx context.Context, in *StreamRawBytesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamRawBytesResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[2], AgentService_StreamRawBytes_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceStreamRawBytesClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[StreamRawBytesRequest, StreamRawBytesResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -157,30 +129,16 @@ func (c *agentServiceClient) StreamRawBytes(ctx context.Context, in *StreamRawBy
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_StreamRawBytesClient interface {
|
||||
Recv() (*StreamRawBytesResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamRawBytesClient = grpc.ServerStreamingClient[StreamRawBytesResponse]
|
||||
|
||||
type agentServiceStreamRawBytesClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamRawBytesClient) Recv() (*StreamRawBytesResponse, error) {
|
||||
m := new(StreamRawBytesResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (AgentService_StreamEventsClient, error) {
|
||||
func (c *agentServiceClient) StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamEventsResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[3], AgentService_StreamEvents_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceStreamEventsClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[StreamEventsRequest, StreamEventsResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -190,30 +148,16 @@ func (c *agentServiceClient) StreamEvents(ctx context.Context, in *StreamEventsR
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_StreamEventsClient interface {
|
||||
Recv() (*StreamEventsResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamEventsClient = grpc.ServerStreamingClient[StreamEventsResponse]
|
||||
|
||||
type agentServiceStreamEventsClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamEventsClient) Recv() (*StreamEventsResponse, error) {
|
||||
m := new(StreamEventsResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) StreamStats(ctx context.Context, in *StreamStatsRequest, opts ...grpc.CallOption) (AgentService_StreamStatsClient, error) {
|
||||
func (c *agentServiceClient) StreamStats(ctx context.Context, in *StreamStatsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamStatsResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[4], AgentService_StreamStats_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceStreamStatsClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[StreamStatsRequest, StreamStatsResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -223,30 +167,16 @@ func (c *agentServiceClient) StreamStats(ctx context.Context, in *StreamStatsReq
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_StreamStatsClient interface {
|
||||
Recv() (*StreamStatsResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamStatsClient = grpc.ServerStreamingClient[StreamStatsResponse]
|
||||
|
||||
type agentServiceStreamStatsClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamStatsClient) Recv() (*StreamStatsResponse, error) {
|
||||
m := new(StreamStatsResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *agentServiceClient) StreamContainerStarted(ctx context.Context, in *StreamContainerStartedRequest, opts ...grpc.CallOption) (AgentService_StreamContainerStartedClient, error) {
|
||||
func (c *agentServiceClient) StreamContainerStarted(ctx context.Context, in *StreamContainerStartedRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StreamContainerStartedResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &AgentService_ServiceDesc.Streams[5], AgentService_StreamContainerStarted_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &agentServiceStreamContainerStartedClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[StreamContainerStartedRequest, StreamContainerStartedResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -256,22 +186,8 @@ func (c *agentServiceClient) StreamContainerStarted(ctx context.Context, in *Str
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type AgentService_StreamContainerStartedClient interface {
|
||||
Recv() (*StreamContainerStartedResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type agentServiceStreamContainerStartedClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamContainerStartedClient) Recv() (*StreamContainerStartedResponse, error) {
|
||||
m := new(StreamContainerStartedResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamContainerStartedClient = grpc.ServerStreamingClient[StreamContainerStartedResponse]
|
||||
|
||||
func (c *agentServiceClient) HostInfo(ctx context.Context, in *HostInfoRequest, opts ...grpc.CallOption) (*HostInfoResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
@@ -295,24 +211,27 @@ func (c *agentServiceClient) ContainerAction(ctx context.Context, in *ContainerA
|
||||
|
||||
// AgentServiceServer is the server API for AgentService service.
|
||||
// All implementations must embed UnimplementedAgentServiceServer
|
||||
// for forward compatibility
|
||||
// for forward compatibility.
|
||||
type AgentServiceServer interface {
|
||||
ListContainers(context.Context, *ListContainersRequest) (*ListContainersResponse, error)
|
||||
FindContainer(context.Context, *FindContainerRequest) (*FindContainerResponse, error)
|
||||
StreamLogs(*StreamLogsRequest, AgentService_StreamLogsServer) error
|
||||
LogsBetweenDates(*LogsBetweenDatesRequest, AgentService_LogsBetweenDatesServer) error
|
||||
StreamRawBytes(*StreamRawBytesRequest, AgentService_StreamRawBytesServer) error
|
||||
StreamEvents(*StreamEventsRequest, AgentService_StreamEventsServer) error
|
||||
StreamStats(*StreamStatsRequest, AgentService_StreamStatsServer) error
|
||||
StreamContainerStarted(*StreamContainerStartedRequest, AgentService_StreamContainerStartedServer) error
|
||||
StreamLogs(*StreamLogsRequest, grpc.ServerStreamingServer[StreamLogsResponse]) error
|
||||
LogsBetweenDates(*LogsBetweenDatesRequest, grpc.ServerStreamingServer[StreamLogsResponse]) error
|
||||
StreamRawBytes(*StreamRawBytesRequest, grpc.ServerStreamingServer[StreamRawBytesResponse]) error
|
||||
StreamEvents(*StreamEventsRequest, grpc.ServerStreamingServer[StreamEventsResponse]) error
|
||||
StreamStats(*StreamStatsRequest, grpc.ServerStreamingServer[StreamStatsResponse]) error
|
||||
StreamContainerStarted(*StreamContainerStartedRequest, grpc.ServerStreamingServer[StreamContainerStartedResponse]) error
|
||||
HostInfo(context.Context, *HostInfoRequest) (*HostInfoResponse, error)
|
||||
ContainerAction(context.Context, *ContainerActionRequest) (*ContainerActionResponse, error)
|
||||
mustEmbedUnimplementedAgentServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedAgentServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedAgentServiceServer struct {
|
||||
}
|
||||
// UnimplementedAgentServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedAgentServiceServer struct{}
|
||||
|
||||
func (UnimplementedAgentServiceServer) ListContainers(context.Context, *ListContainersRequest) (*ListContainersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListContainers not implemented")
|
||||
@@ -320,22 +239,22 @@ func (UnimplementedAgentServiceServer) ListContainers(context.Context, *ListCont
|
||||
func (UnimplementedAgentServiceServer) FindContainer(context.Context, *FindContainerRequest) (*FindContainerResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FindContainer not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) StreamLogs(*StreamLogsRequest, AgentService_StreamLogsServer) error {
|
||||
func (UnimplementedAgentServiceServer) StreamLogs(*StreamLogsRequest, grpc.ServerStreamingServer[StreamLogsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamLogs not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) LogsBetweenDates(*LogsBetweenDatesRequest, AgentService_LogsBetweenDatesServer) error {
|
||||
func (UnimplementedAgentServiceServer) LogsBetweenDates(*LogsBetweenDatesRequest, grpc.ServerStreamingServer[StreamLogsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method LogsBetweenDates not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) StreamRawBytes(*StreamRawBytesRequest, AgentService_StreamRawBytesServer) error {
|
||||
func (UnimplementedAgentServiceServer) StreamRawBytes(*StreamRawBytesRequest, grpc.ServerStreamingServer[StreamRawBytesResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamRawBytes not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) StreamEvents(*StreamEventsRequest, AgentService_StreamEventsServer) error {
|
||||
func (UnimplementedAgentServiceServer) StreamEvents(*StreamEventsRequest, grpc.ServerStreamingServer[StreamEventsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamEvents not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) StreamStats(*StreamStatsRequest, AgentService_StreamStatsServer) error {
|
||||
func (UnimplementedAgentServiceServer) StreamStats(*StreamStatsRequest, grpc.ServerStreamingServer[StreamStatsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamStats not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) StreamContainerStarted(*StreamContainerStartedRequest, AgentService_StreamContainerStartedServer) error {
|
||||
func (UnimplementedAgentServiceServer) StreamContainerStarted(*StreamContainerStartedRequest, grpc.ServerStreamingServer[StreamContainerStartedResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method StreamContainerStarted not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) HostInfo(context.Context, *HostInfoRequest) (*HostInfoResponse, error) {
|
||||
@@ -345,6 +264,7 @@ func (UnimplementedAgentServiceServer) ContainerAction(context.Context, *Contain
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ContainerAction not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServiceServer) mustEmbedUnimplementedAgentServiceServer() {}
|
||||
func (UnimplementedAgentServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeAgentServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AgentServiceServer will
|
||||
@@ -354,6 +274,13 @@ type UnsafeAgentServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterAgentServiceServer(s grpc.ServiceRegistrar, srv AgentServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAgentServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&AgentService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
@@ -398,126 +325,66 @@ func _AgentService_StreamLogs_Handler(srv interface{}, stream grpc.ServerStream)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).StreamLogs(m, &agentServiceStreamLogsServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).StreamLogs(m, &grpc.GenericServerStream[StreamLogsRequest, StreamLogsResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_StreamLogsServer interface {
|
||||
Send(*StreamLogsResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceStreamLogsServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamLogsServer) Send(m *StreamLogsResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamLogsServer = grpc.ServerStreamingServer[StreamLogsResponse]
|
||||
|
||||
func _AgentService_LogsBetweenDates_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(LogsBetweenDatesRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).LogsBetweenDates(m, &agentServiceLogsBetweenDatesServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).LogsBetweenDates(m, &grpc.GenericServerStream[LogsBetweenDatesRequest, StreamLogsResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_LogsBetweenDatesServer interface {
|
||||
Send(*StreamLogsResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceLogsBetweenDatesServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceLogsBetweenDatesServer) Send(m *StreamLogsResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_LogsBetweenDatesServer = grpc.ServerStreamingServer[StreamLogsResponse]
|
||||
|
||||
func _AgentService_StreamRawBytes_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(StreamRawBytesRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).StreamRawBytes(m, &agentServiceStreamRawBytesServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).StreamRawBytes(m, &grpc.GenericServerStream[StreamRawBytesRequest, StreamRawBytesResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_StreamRawBytesServer interface {
|
||||
Send(*StreamRawBytesResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceStreamRawBytesServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamRawBytesServer) Send(m *StreamRawBytesResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamRawBytesServer = grpc.ServerStreamingServer[StreamRawBytesResponse]
|
||||
|
||||
func _AgentService_StreamEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(StreamEventsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).StreamEvents(m, &agentServiceStreamEventsServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).StreamEvents(m, &grpc.GenericServerStream[StreamEventsRequest, StreamEventsResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_StreamEventsServer interface {
|
||||
Send(*StreamEventsResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceStreamEventsServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamEventsServer) Send(m *StreamEventsResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamEventsServer = grpc.ServerStreamingServer[StreamEventsResponse]
|
||||
|
||||
func _AgentService_StreamStats_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(StreamStatsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).StreamStats(m, &agentServiceStreamStatsServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).StreamStats(m, &grpc.GenericServerStream[StreamStatsRequest, StreamStatsResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_StreamStatsServer interface {
|
||||
Send(*StreamStatsResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceStreamStatsServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamStatsServer) Send(m *StreamStatsResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamStatsServer = grpc.ServerStreamingServer[StreamStatsResponse]
|
||||
|
||||
func _AgentService_StreamContainerStarted_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(StreamContainerStartedRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(AgentServiceServer).StreamContainerStarted(m, &agentServiceStreamContainerStartedServer{ServerStream: stream})
|
||||
return srv.(AgentServiceServer).StreamContainerStarted(m, &grpc.GenericServerStream[StreamContainerStartedRequest, StreamContainerStartedResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type AgentService_StreamContainerStartedServer interface {
|
||||
Send(*StreamContainerStartedResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type agentServiceStreamContainerStartedServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *agentServiceStreamContainerStartedServer) Send(m *StreamContainerStartedResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type AgentService_StreamContainerStartedServer = grpc.ServerStreamingServer[StreamContainerStartedResponse]
|
||||
|
||||
func _AgentService_HostInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HostInfoRequest)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.2
|
||||
// protoc v5.27.3
|
||||
// protoc-gen-go v1.35.1
|
||||
// protoc v5.28.3
|
||||
// source: types.proto
|
||||
|
||||
package pb
|
||||
@@ -95,11 +95,9 @@ type Container struct {
|
||||
|
||||
func (x *Container) Reset() {
|
||||
*x = Container{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Container) String() string {
|
||||
@@ -110,7 +108,7 @@ func (*Container) ProtoMessage() {}
|
||||
|
||||
func (x *Container) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -243,11 +241,9 @@ type ContainerStat struct {
|
||||
|
||||
func (x *ContainerStat) Reset() {
|
||||
*x = ContainerStat{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerStat) String() string {
|
||||
@@ -258,7 +254,7 @@ func (*ContainerStat) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerStat) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -317,11 +313,9 @@ type LogEvent struct {
|
||||
|
||||
func (x *LogEvent) Reset() {
|
||||
*x = LogEvent{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *LogEvent) String() string {
|
||||
@@ -332,7 +326,7 @@ func (*LogEvent) ProtoMessage() {}
|
||||
|
||||
func (x *LogEvent) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -406,11 +400,9 @@ type SimpleMessage struct {
|
||||
|
||||
func (x *SimpleMessage) Reset() {
|
||||
*x = SimpleMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SimpleMessage) String() string {
|
||||
@@ -421,7 +413,7 @@ func (*SimpleMessage) ProtoMessage() {}
|
||||
|
||||
func (x *SimpleMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -453,11 +445,9 @@ type ComplexMessage struct {
|
||||
|
||||
func (x *ComplexMessage) Reset() {
|
||||
*x = ComplexMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ComplexMessage) String() string {
|
||||
@@ -468,7 +458,7 @@ func (*ComplexMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ComplexMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -502,11 +492,9 @@ type ContainerEvent struct {
|
||||
|
||||
func (x *ContainerEvent) Reset() {
|
||||
*x = ContainerEvent{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ContainerEvent) String() string {
|
||||
@@ -517,7 +505,7 @@ func (*ContainerEvent) ProtoMessage() {}
|
||||
|
||||
func (x *ContainerEvent) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -574,11 +562,9 @@ type Host struct {
|
||||
|
||||
func (x *Host) Reset() {
|
||||
*x = Host{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_types_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_types_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Host) String() string {
|
||||
@@ -589,7 +575,7 @@ func (*Host) ProtoMessage() {}
|
||||
|
||||
func (x *Host) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_types_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -846,92 +832,6 @@ func file_types_proto_init() {
|
||||
if File_types_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_types_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*Container); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ContainerStat); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*LogEvent); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*SimpleMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ComplexMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*ContainerEvent); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_types_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*Host); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
|
||||
@@ -12,11 +12,12 @@ import (
|
||||
type simpleAuthContext struct {
|
||||
UserDatabase UserDatabase
|
||||
tokenAuth *jwtauth.JWTAuth
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
var ErrInvalidCredentials = errors.New("invalid credentials")
|
||||
|
||||
func NewSimpleAuth(userDatabase UserDatabase) *simpleAuthContext {
|
||||
func NewSimpleAuth(userDatabase UserDatabase, ttl time.Duration) *simpleAuthContext {
|
||||
h := sha256.New()
|
||||
for _, user := range userDatabase.Users {
|
||||
h.Write([]byte(user.Password))
|
||||
@@ -27,6 +28,7 @@ func NewSimpleAuth(userDatabase UserDatabase) *simpleAuthContext {
|
||||
return &simpleAuthContext{
|
||||
UserDatabase: userDatabase,
|
||||
tokenAuth: tokenAuth,
|
||||
ttl: ttl,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +38,14 @@ func (a *simpleAuthContext) CreateToken(username, password string) (string, erro
|
||||
return "", ErrInvalidCredentials
|
||||
}
|
||||
|
||||
_, tokenString, err := a.tokenAuth.Encode(map[string]interface{}{"username": user.Username, "email": user.Email, "name": user.Name, "timestamp": time.Now()})
|
||||
claims := map[string]interface{}{"username": user.Username, "email": user.Email, "name": user.Name}
|
||||
jwtauth.SetIssuedNow(claims)
|
||||
|
||||
if a.ttl > 0 {
|
||||
jwtauth.SetExpiryIn(claims, a.ttl)
|
||||
}
|
||||
|
||||
_, tokenString, err := a.tokenAuth.Encode(claims)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (s *ContainerStore) checkConnectivity() error {
|
||||
}
|
||||
|
||||
running := lo.Filter(containers, func(item Container, index int) bool {
|
||||
return item.State == "running"
|
||||
return item.State != "exited"
|
||||
})
|
||||
|
||||
sem := semaphore.NewWeighted(maxFetchParallelism)
|
||||
|
||||
@@ -177,7 +177,9 @@ func createEvent(message string, streamType StdType) *LogEvent {
|
||||
logEvent.Timestamp = timestamp.UnixMilli()
|
||||
message = strings.TrimSuffix(message[index+1:], "\n")
|
||||
logEvent.Message = message
|
||||
if json.Valid([]byte(message)) {
|
||||
if message == "" {
|
||||
logEvent.Message = "" // empty message so do nothing
|
||||
} else if json.Valid([]byte(message)) {
|
||||
data := orderedmap.New[string, any]()
|
||||
if err := json.Unmarshal([]byte(message), &data); err != nil {
|
||||
var jsonErr *json.UnmarshalTypeError
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
orderedmap "github.com/wk8/go-ordered-map/v2"
|
||||
)
|
||||
|
||||
var keyValueRegex = regexp.MustCompile(`level=(\w+)`)
|
||||
var SupportedLogLevels map[string]struct{}
|
||||
|
||||
// Changing this also needs to change the logContext.ts file
|
||||
var logLevels = []string{"error", "warn", "warning", "info", "debug", "trace", "severe", "critical", "fatal"}
|
||||
var plainLevels = map[string]*regexp.Regexp{}
|
||||
var bracketLevels = map[string]*regexp.Regexp{}
|
||||
@@ -21,6 +23,12 @@ func init() {
|
||||
for _, level := range logLevels {
|
||||
bracketLevels[level] = regexp.MustCompile("(?i)\\[ ?" + level + " ?\\]")
|
||||
}
|
||||
|
||||
SupportedLogLevels = make(map[string]struct{}, len(logLevels)+1)
|
||||
for _, level := range logLevels {
|
||||
SupportedLogLevels[level] = struct{}{}
|
||||
}
|
||||
SupportedLogLevels["unknown"] = struct{}{}
|
||||
}
|
||||
|
||||
func guessLogLevel(logEvent *LogEvent) string {
|
||||
@@ -28,26 +36,32 @@ func guessLogLevel(logEvent *LogEvent) string {
|
||||
case string:
|
||||
value = stripANSI(value)
|
||||
for _, level := range logLevels {
|
||||
// Look for the level at the beginning of the message
|
||||
if plainLevels[level].MatchString(value) {
|
||||
return level
|
||||
}
|
||||
|
||||
// Look for the level in brackets
|
||||
if bracketLevels[level].MatchString(value) {
|
||||
return level
|
||||
}
|
||||
|
||||
// Look for the level in the middle of the message that are uppercase
|
||||
if strings.Contains(value, " "+strings.ToUpper(level)+" ") {
|
||||
return level
|
||||
}
|
||||
|
||||
// Look for levels with equal sign and quotes around them
|
||||
if strings.Contains(value, level+"=") {
|
||||
return level
|
||||
}
|
||||
}
|
||||
|
||||
if matches := keyValueRegex.FindStringSubmatch(value); matches != nil {
|
||||
return matches[1]
|
||||
}
|
||||
return "unknown"
|
||||
|
||||
case *orderedmap.OrderedMap[string, any]:
|
||||
if value == nil {
|
||||
return ""
|
||||
return "unknown"
|
||||
}
|
||||
if level, ok := value.Get("level"); ok {
|
||||
if level, ok := level.(string); ok {
|
||||
@@ -61,7 +75,7 @@ func guessLogLevel(logEvent *LogEvent) string {
|
||||
|
||||
case *orderedmap.OrderedMap[string, string]:
|
||||
if value == nil {
|
||||
return ""
|
||||
return "unknown"
|
||||
}
|
||||
if level, ok := value.Get("level"); ok {
|
||||
return strings.ToLower(level)
|
||||
@@ -79,5 +93,5 @@ func guessLogLevel(logEvent *LogEvent) string {
|
||||
log.Debug().Type("type", value).Msg("unknown logEvent type")
|
||||
}
|
||||
|
||||
return ""
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
@@ -20,15 +20,15 @@ func TestGuessLogLevel(t *testing.T) {
|
||||
{"debug Something happened", "debug"},
|
||||
{"TRACE: Something happened", "trace"},
|
||||
{"FATAL: Something happened", "fatal"},
|
||||
{"level=error Something went wrong", "error"},
|
||||
{"[ERROR] Something went wrong", "error"},
|
||||
{"[error] Something went wrong", "error"},
|
||||
{"[ ERROR ] Something went wrong", "error"},
|
||||
{"[error] Something went wrong", "error"},
|
||||
{"[test] [error] Something went wrong", "error"},
|
||||
{"Some test with error=test", "error"},
|
||||
{"[foo] [ ERROR] Something went wrong", "error"},
|
||||
{"123 ERROR Something went wrong", "error"},
|
||||
{"123 Something went wrong", ""},
|
||||
{"123 Something went wrong", "unknown"},
|
||||
{orderedmap.New[string, string](
|
||||
orderedmap.WithInitialData(
|
||||
orderedmap.Pair[string, string]{Key: "key", Value: "value"},
|
||||
@@ -53,8 +53,8 @@ func TestGuessLogLevel(t *testing.T) {
|
||||
orderedmap.Pair[string, any]{Key: "severity", Value: "info"},
|
||||
),
|
||||
), "info"},
|
||||
{nilOrderedMap, ""},
|
||||
{nil, ""},
|
||||
{nilOrderedMap, "unknown"},
|
||||
{nil, "unknown"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -15,6 +15,7 @@ type Args struct {
|
||||
Hostname string `arg:"env:DOZZLE_HOSTNAME" help:"sets the hostname for display. This is useful with multiple Dozzle instances."`
|
||||
Level string `arg:"env:DOZZLE_LEVEL" default:"info" help:"set Dozzle log level. Use debug for more logging."`
|
||||
AuthProvider string `arg:"--auth-provider,env:DOZZLE_AUTH_PROVIDER" default:"none" help:"sets the auth provider to use. Currently only forward-proxy is supported."`
|
||||
AuthTTL string `arg:"--auth-ttl,env:DOZZLE_AUTH_TTL" default:"session" help:"sets the TTL for the auth token. Accepts duration values like 12h. Valid time units are s, m, h"`
|
||||
AuthHeaderUser string `arg:"--auth-header-user,env:DOZZLE_AUTH_HEADER_USER" default:"Remote-User" help:"sets the HTTP Header to use for username in Forward Proxy configuration."`
|
||||
AuthHeaderEmail string `arg:"--auth-header-email,env:DOZZLE_AUTH_HEADER_EMAIL" default:"Remote-Email" help:"sets the HTTP Header to use for email in Forward Proxy configuration."`
|
||||
AuthHeaderName string `arg:"--auth-header-name,env:DOZZLE_AUTH_HEADER_NAME" default:"Remote-Name" help:"sets the HTTP Header to use for name in Forward Proxy configuration."`
|
||||
@@ -25,7 +26,7 @@ type Args struct {
|
||||
RemoteAgent []string `arg:"env:DOZZLE_REMOTE_AGENT,--remote-agent,separate" help:"list of agents to connect remotely"`
|
||||
NoAnalytics bool `arg:"--no-analytics,env:DOZZLE_NO_ANALYTICS" help:"disables anonymous analytics"`
|
||||
Mode string `arg:"env:DOZZLE_MODE" default:"server" help:"sets the mode to run in (server, swarm)"`
|
||||
TimeoutString string `arg:"env:DOZZLE_TIMEOUT" default:"3s" help:"sets the timeout for docker client"`
|
||||
TimeoutString string `arg:"--timeout,env:DOZZLE_TIMEOUT" default:"3s" help:"sets the timeout for docker client"`
|
||||
Timeout time.Duration `arg:"-"`
|
||||
Healthcheck *HealthcheckCmd `arg:"subcommand:healthcheck" help:"checks if the server is running"`
|
||||
Generate *GenerateCmd `arg:"subcommand:generate" help:"generates a configuration file for simple auth"`
|
||||
|
||||
@@ -12,12 +12,18 @@ func (h *handler) createToken(w http.ResponseWriter, r *http.Request) {
|
||||
pass := r.PostFormValue("password")
|
||||
|
||||
if token, err := h.config.Authorization.Authorizer.CreateToken(user, pass); err == nil {
|
||||
expires := time.Time{}
|
||||
if h.config.Authorization.TTL > 0 {
|
||||
expires = time.Now().Add(h.config.Authorization.TTL)
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "jwt",
|
||||
Value: token,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
Expires: expires,
|
||||
})
|
||||
log.Info().Str("user", user).Msg("Token created")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"testing"
|
||||
|
||||
@@ -32,7 +33,7 @@ func Test_createRoutes_simple_redirect(t *testing.T) {
|
||||
Password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}, time.Second*100),
|
||||
},
|
||||
})
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
@@ -57,7 +58,7 @@ func Test_createRoutes_simple_valid_token(t *testing.T) {
|
||||
Password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}, time.Second*100),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -102,7 +103,7 @@ func Test_createRoutes_simple_bad_password(t *testing.T) {
|
||||
Password: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}, time.Second*100),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ func Test_createRoutes_version(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, afero.WriteFile(fs, "index.html", []byte("index page"), 0644), "WriteFile should have no error.")
|
||||
handler := createHandler(nil, afero.NewIOFS(fs), Config{Base: "/", Version: "dev", Authorization: Authorization{Provider: NONE}})
|
||||
req, err := http.NewRequest("GET", "/version", nil)
|
||||
req, err := http.NewRequest("GET", "/api/version", nil)
|
||||
require.NoError(t, err, "NewRequest should not return an error.")
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (h *handler) debugStore(w http.ResponseWriter, r *http.Request) {
|
||||
respone := make(map[string]interface{})
|
||||
respone["hosts"] = h.multiHostService.Hosts()
|
||||
containers, errors := h.multiHostService.ListAllContainers()
|
||||
respone["containers"] = containers
|
||||
respone["errors"] = errors
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(respone)
|
||||
}
|
||||
@@ -9,11 +9,19 @@ import (
|
||||
func (h *handler) healthcheck(w http.ResponseWriter, r *http.Request) {
|
||||
log.Trace().Msg("Healthcheck request received")
|
||||
|
||||
_, errors := h.multiHostService.ListAllContainers()
|
||||
if len(errors) > 0 {
|
||||
log.Error().Err(errors[0]).Msg("Error listing containers")
|
||||
http.Error(w, "Error listing containers", http.StatusInternalServerError)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
for _, host := range h.multiHostService.Hosts() {
|
||||
if host.Type == "agent" {
|
||||
log.Debug().Str("host", host.ID).Msg("Skipping agent host for healthcheck")
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := h.multiHostService.ListContainersForHost(host.ID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("host", host.ID).Msg("Error listing containers")
|
||||
http.Error(w, "Error listing containers", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
@@ -141,6 +141,11 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
levels := make(map[string]struct{})
|
||||
for _, level := range r.URL.Query()["levels"] {
|
||||
levels[level] = struct{}{}
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(w)
|
||||
for {
|
||||
if buffer.Len() > minimum {
|
||||
@@ -157,25 +162,30 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
for event := range events {
|
||||
if regex != nil {
|
||||
if search.Search(regex, event) {
|
||||
buffer.Push(event)
|
||||
}
|
||||
} else {
|
||||
if onlyComplex {
|
||||
if _, ok := event.Message.(string); ok {
|
||||
continue
|
||||
}
|
||||
if everything {
|
||||
if err := encoder.Encode(event); err != nil {
|
||||
log.Error().Err(err).Msg("error encoding log event")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if everything {
|
||||
if err := encoder.Encode(event); err != nil {
|
||||
log.Error().Err(err).Msg("error encoding log event")
|
||||
}
|
||||
} else {
|
||||
buffer.Push(event)
|
||||
if onlyComplex {
|
||||
if _, ok := event.Message.(string); ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if regex != nil {
|
||||
if !search.Search(regex, event) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := levels[event.Level]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
buffer.Push(event)
|
||||
}
|
||||
|
||||
if everything || from.Before(containerService.Container.Created) {
|
||||
@@ -272,6 +282,11 @@ func streamLogsForContainers(w http.ResponseWriter, r *http.Request, multiHostCl
|
||||
events := make(chan *docker.ContainerEvent, 1)
|
||||
backfill := make(chan []*docker.LogEvent)
|
||||
|
||||
levels := make(map[string]struct{})
|
||||
for _, level := range r.URL.Query()["levels"] {
|
||||
levels[level] = struct{}{}
|
||||
}
|
||||
|
||||
if r.URL.Query().Has("filter") {
|
||||
var err error
|
||||
regex, err = search.ParseRegex(r.URL.Query().Get("filter"))
|
||||
@@ -309,6 +324,9 @@ func streamLogsForContainers(w http.ResponseWriter, r *http.Request, multiHostCl
|
||||
}
|
||||
|
||||
for log := range logs {
|
||||
if _, ok := levels[log.Level]; !ok {
|
||||
continue
|
||||
}
|
||||
if search.Search(regex, log) {
|
||||
events = append(events, log)
|
||||
}
|
||||
@@ -369,6 +387,10 @@ loop:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := levels[logEvent.Level]; !ok {
|
||||
continue
|
||||
}
|
||||
sseWriter.Message(logEvent)
|
||||
case container := <-newContainers:
|
||||
events <- &docker.ContainerEvent{ActorID: container.ID, Name: "container-started", Host: container.Host}
|
||||
|
||||
@@ -28,6 +28,7 @@ func Test_handler_streamLogs_happy(t *testing.T) {
|
||||
q := req.URL.Query()
|
||||
q.Add("stdout", "true")
|
||||
q.Add("stderr", "true")
|
||||
q.Add("levels", "info")
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
require.NoError(t, err, "NewRequest should not return an error.")
|
||||
@@ -70,6 +71,7 @@ func Test_handler_streamLogs_happy_with_id(t *testing.T) {
|
||||
q := req.URL.Query()
|
||||
q.Add("stdout", "true")
|
||||
q.Add("stderr", "true")
|
||||
q.Add("levels", "info")
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
require.NoError(t, err, "NewRequest should not return an error.")
|
||||
@@ -218,6 +220,7 @@ func Test_handler_between_dates(t *testing.T) {
|
||||
q.Add("to", to.Format(time.RFC3339))
|
||||
q.Add("stdout", "true")
|
||||
q.Add("stderr", "true")
|
||||
q.Add("levels", "info")
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
@@ -258,6 +261,7 @@ func Test_handler_between_dates_with_fill(t *testing.T) {
|
||||
q.Add("stdout", "true")
|
||||
q.Add("stderr", "true")
|
||||
q.Add("fill", "true")
|
||||
q.Add("levels", "info")
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package web
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -36,6 +37,7 @@ type Config struct {
|
||||
type Authorization struct {
|
||||
Provider AuthProvider
|
||||
Authorizer Authorizer
|
||||
TTL time.Duration
|
||||
}
|
||||
|
||||
type Authorizer interface {
|
||||
@@ -65,6 +67,7 @@ func CreateServer(multiHostService *MultiHostService, content fs.FS, config Conf
|
||||
var fileServer http.Handler
|
||||
|
||||
func createRouter(h *handler) *chi.Mux {
|
||||
fileServer = http.FileServer(http.FS(h.content))
|
||||
base := h.config.Base
|
||||
r := chi.NewRouter()
|
||||
|
||||
@@ -80,41 +83,46 @@ func createRouter(h *handler) *chi.Mux {
|
||||
if h.config.Authorization.Provider != NONE {
|
||||
r.Use(h.config.Authorization.Authorizer.AuthMiddleware)
|
||||
}
|
||||
r.Group(func(r chi.Router) {
|
||||
|
||||
r.Route("/api", func(r chi.Router) {
|
||||
// Authenticated routes
|
||||
r.Group(func(r chi.Router) {
|
||||
if h.config.Authorization.Provider != NONE {
|
||||
r.Use(auth.RequireAuthentication)
|
||||
}
|
||||
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/{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)
|
||||
r.Get("/api/events/stream", h.streamEvents)
|
||||
r.Get("/hosts/{host}/containers/{id}/logs/stream", h.streamContainerLogs)
|
||||
r.Get("/hosts/{host}/containers/{id}/logs/download", h.downloadLogs)
|
||||
r.Get("/hosts/{host}/containers/{id}/logs", h.fetchLogsBetweenDates)
|
||||
r.Get("/hosts/{host}/logs/mergedStream/{ids}", h.streamLogsMerged)
|
||||
r.Get("/stacks/{stack}/logs/stream", h.streamStackLogs)
|
||||
r.Get("/services/{service}/logs/stream", h.streamServiceLogs)
|
||||
r.Get("/groups/{group}/logs/stream", h.streamGroupedLogs)
|
||||
r.Get("/events/stream", h.streamEvents)
|
||||
if h.config.EnableActions {
|
||||
r.Post("/api/hosts/{host}/containers/{id}/actions/{action}", h.containerActions)
|
||||
r.Post("/hosts/{host}/containers/{id}/actions/{action}", h.containerActions)
|
||||
}
|
||||
r.Get("/api/releases", h.releases)
|
||||
r.Get("/api/profile/avatar", h.avatar)
|
||||
r.Patch("/api/profile", h.updateProfile)
|
||||
r.Get("/releases", h.releases)
|
||||
r.Get("/profile/avatar", h.avatar)
|
||||
r.Patch("/profile", h.updateProfile)
|
||||
r.Get("/version", h.version)
|
||||
if log.Debug().Enabled() {
|
||||
r.Get("/debug/store", h.debugStore)
|
||||
}
|
||||
})
|
||||
|
||||
defaultHandler := http.StripPrefix(strings.Replace(base+"/", "//", "/", 1), http.HandlerFunc(h.index))
|
||||
r.Get("/*", func(w http.ResponseWriter, req *http.Request) {
|
||||
defaultHandler.ServeHTTP(w, req)
|
||||
})
|
||||
// Public API routes
|
||||
if h.config.Authorization.Provider == SIMPLE {
|
||||
r.Post("/token", h.createToken)
|
||||
r.Delete("/token", h.deleteToken)
|
||||
}
|
||||
})
|
||||
|
||||
if h.config.Authorization.Provider == SIMPLE {
|
||||
r.Post("/api/token", h.createToken)
|
||||
r.Delete("/api/token", h.deleteToken)
|
||||
}
|
||||
|
||||
r.Get("/healthcheck", h.healthcheck)
|
||||
|
||||
defaultHandler := http.StripPrefix(strings.Replace(base+"/", "//", "/", 1), http.HandlerFunc(h.index))
|
||||
r.Get("/*", func(w http.ResponseWriter, req *http.Request) {
|
||||
defaultHandler.ServeHTTP(w, req)
|
||||
})
|
||||
})
|
||||
|
||||
if base != "/" {
|
||||
@@ -123,8 +131,6 @@ func createRouter(h *handler) *chi.Mux {
|
||||
})
|
||||
}
|
||||
|
||||
fileServer = http.FileServer(http.FS(h.content))
|
||||
|
||||
// r.Mount("/debug", middleware.Profiler())
|
||||
|
||||
return r
|
||||
|
||||
@@ -2,8 +2,8 @@ toolbar:
|
||||
clear: Clear
|
||||
download: Download
|
||||
search: Search
|
||||
show: Show only {std}
|
||||
show-all: Show all streams
|
||||
show: Show {std}
|
||||
show-all: Show all
|
||||
stop: Stop
|
||||
start: Start
|
||||
restart: Restart
|
||||
|
||||
@@ -229,7 +229,24 @@ func createServer(args cli.Args, multiHostService *docker_support.MultiHostServi
|
||||
}
|
||||
|
||||
log.Debug().Int("users", len(db.Users)).Msg("Loaded users")
|
||||
authorizer = auth.NewSimpleAuth(db)
|
||||
ttl := time.Duration(0)
|
||||
if args.AuthTTL != "session" {
|
||||
ttl, err = time.ParseDuration(args.AuthTTL)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Could not parse auth ttl")
|
||||
}
|
||||
}
|
||||
authorizer = auth.NewSimpleAuth(db, ttl)
|
||||
}
|
||||
|
||||
authTTL := time.Duration(0)
|
||||
|
||||
if args.AuthTTL != "session" {
|
||||
ttl, err := time.ParseDuration(args.AuthTTL)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Could not parse auth ttl")
|
||||
}
|
||||
authTTL = ttl
|
||||
}
|
||||
|
||||
config := web.Config{
|
||||
@@ -242,6 +259,7 @@ func createServer(args cli.Args, multiHostService *docker_support.MultiHostServi
|
||||
Authorization: web.Authorization{
|
||||
Provider: provider,
|
||||
Authorizer: authorizer,
|
||||
TTL: authTTL,
|
||||
},
|
||||
EnableActions: args.EnableActions,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "dozzle",
|
||||
"version": "8.5.5",
|
||||
"version": "8.7.2",
|
||||
"description": "Realtime log viewer for docker containers.",
|
||||
"homepage": "https://github.com/amir20/dozzle#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/amir20/dozzle/issues"
|
||||
},
|
||||
"packageManager": "pnpm@9.11.0",
|
||||
"packageManager": "pnpm@9.12.3",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -29,22 +29,22 @@
|
||||
"docs:preview": "vitepress preview docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@duckdb/duckdb-wasm": "1.28.1-dev288.0",
|
||||
"@iconify-json/carbon": "^1.2.1",
|
||||
"@iconify-json/cil": "^1.2.0",
|
||||
"@iconify-json/ic": "^1.2.0",
|
||||
"@iconify-json/material-symbols": "^1.2.1",
|
||||
"@iconify-json/mdi": "^1.2.0",
|
||||
"@iconify-json/mdi-light": "^1.2.0",
|
||||
"@iconify-json/octicon": "^1.2.0",
|
||||
"@iconify-json/ph": "^1.2.0",
|
||||
"@duckdb/duckdb-wasm": "1.29.0",
|
||||
"@iconify-json/carbon": "^1.2.4",
|
||||
"@iconify-json/cil": "^1.2.1",
|
||||
"@iconify-json/ic": "^1.2.1",
|
||||
"@iconify-json/material-symbols": "^1.2.6",
|
||||
"@iconify-json/mdi": "^1.2.1",
|
||||
"@iconify-json/mdi-light": "^1.2.1",
|
||||
"@iconify-json/octicon": "^1.2.1",
|
||||
"@iconify-json/ph": "^1.2.1",
|
||||
"@intlify/unplugin-vue-i18n": "^5.2.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@vueuse/components": "^11.1.0",
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"@vueuse/integrations": "^11.1.0",
|
||||
"@vueuse/router": "^11.1.0",
|
||||
"@vueuse/components": "^11.2.0",
|
||||
"@vueuse/core": "^11.2.0",
|
||||
"@vueuse/integrations": "^11.2.0",
|
||||
"@vueuse/router": "^11.2.0",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"d3-array": "^3.2.4",
|
||||
@@ -53,45 +53,47 @@
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-shape": "^3.2.0",
|
||||
"d3-transition": "^3.0.1",
|
||||
"daisyui": "^4.12.10",
|
||||
"daisyui": "^4.12.14",
|
||||
"date-fns": "^4.1.0",
|
||||
"entities": "^5.0.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"pinia": "^2.2.3",
|
||||
"pinia": "^2.2.5",
|
||||
"postcss": "^8.4.47",
|
||||
"sortablejs": "^1.15.3",
|
||||
"splitpanes": "^3.1.5",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"unplugin-auto-import": "^0.18.3",
|
||||
"unplugin-icons": "^0.19.3",
|
||||
"unplugin-icons": "^0.20.0",
|
||||
"unplugin-vue-components": "^0.27.4",
|
||||
"unplugin-vue-macros": "^2.12.3",
|
||||
"unplugin-vue-macros": "^2.13.3",
|
||||
"unplugin-vue-router": "^0.10.8",
|
||||
"vite": "5.4.8",
|
||||
"vite": "5.4.10",
|
||||
"vite-plugin-compression2": "^1.3.0",
|
||||
"vite-plugin-vue-layouts": "^0.11.0",
|
||||
"vitepress": "1.3.4",
|
||||
"vue": "^3.5.10",
|
||||
"vue-i18n": "^10.0.3",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vitepress": "1.4.3",
|
||||
"vue": "^3.5.12",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-router": "^4.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apache-arrow/esnext-esm": "^18.0.0",
|
||||
"@pinia/testing": "^0.1.6",
|
||||
"@playwright/test": "^1.47.2",
|
||||
"@playwright/test": "^1.48.2",
|
||||
"@types/d3-array": "^3.2.1",
|
||||
"@types/d3-ease": "^3.0.2",
|
||||
"@types/d3-scale": "^4.0.8",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-selection": "^3.0.11",
|
||||
"@types/d3-shape": "^3.1.6",
|
||||
"@types/d3-transition": "^3.0.8",
|
||||
"@types/d3-transition": "^3.0.9",
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
"@types/node": "^22.7.4",
|
||||
"@types/node": "^22.8.6",
|
||||
"@vitejs/plugin-vue": "5.1.4",
|
||||
"@vue/compiler-sfc": "^3.5.10",
|
||||
"@vue/compiler-sfc": "^3.5.12",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"bumpp": "^9.6.1",
|
||||
"bumpp": "^9.8.0",
|
||||
"c8": "^10.1.2",
|
||||
"concurrently": "^9.0.1",
|
||||
"eventsourcemock": "^2.0.0",
|
||||
@@ -101,10 +103,10 @@
|
||||
"prettier-plugin-tailwindcss": "^0.6.8",
|
||||
"simple-git-hooks": "^2.11.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.6.2",
|
||||
"vitest": "^2.1.1",
|
||||
"vue-component-type-helpers": "^2.1.6",
|
||||
"vue-tsc": "^2.1.6"
|
||||
"typescript": "^5.6.3",
|
||||
"vitest": "^2.1.4",
|
||||
"vue-component-type-helpers": "^2.1.10",
|
||||
"vue-tsc": "^2.1.10"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue,css,ts,html,md}": [
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -1,4 +1,4 @@
|
||||
import path from "path";
|
||||
import path from "node:path";
|
||||
import { defineConfig } from "vite";
|
||||
import Vue from "@vitejs/plugin-vue";
|
||||
import VueMacros from "unplugin-vue-macros/vite";
|
||||
@@ -11,6 +11,7 @@ import Layouts from "vite-plugin-vue-layouts";
|
||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
||||
import { compression } from "vite-plugin-compression2";
|
||||
import { VueRouterAutoImports } from "unplugin-vue-router";
|
||||
import svgLoader from "vite-svg-loader";
|
||||
|
||||
export default defineConfig(() => ({
|
||||
resolve: {
|
||||
@@ -71,21 +72,8 @@ export default defineConfig(() => ({
|
||||
include: [path.resolve(__dirname, "locales/**")],
|
||||
}),
|
||||
compression({ algorithm: "brotliCompress", exclude: [/\.(html)$/] }),
|
||||
svgLoader({}),
|
||||
],
|
||||
server: {
|
||||
watch: {
|
||||
ignored: ["**/data/**"],
|
||||
},
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: {
|
||||
host: "127.0.0.1",
|
||||
port: 3100,
|
||||
},
|
||||
changeOrigin: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
test: {
|
||||
include: ["assets/**/*.spec.ts"],
|
||||
},
|
||||
|
||||