Compare commits

...

72 Commits

Author SHA1 Message Date
Amir Raminfar e22d54cf74 chore: release v8.7.2 2024-11-02 10:47:03 -07:00
renovate[bot] 7bf331cf6e fix(deps): update all non-major dependencies (#3369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 17:46:01 +00:00
Amir Raminfar d529ed7855 feat: checks level with equal sign (#3368) 2024-11-02 10:40:49 -07:00
Amir Raminfar 46d124b11a chore: updates version 2024-11-01 16:39:22 -07:00
Amir Raminfar d09aa5d481 chore: updates log 2024-11-01 14:17:24 -07:00
Amir Raminfar cc77c16f92 feat: skips healthcheck for agents (#3366) 2024-11-01 08:28:10 -07:00
renovate[bot] 63be3bf2d8 fix(deps): update all non-major dependencies (#3363)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-30 21:53:50 +00:00
Amir Raminfar ec29c78052 chore: updates to node v23 (#3362) 2024-10-30 08:57:06 -07:00
renovate[bot] df3f04dd50 chore(deps): update dependency @apache-arrow/esnext-esm to v18 (#3361)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-30 07:55:41 -07:00
renovate[bot] 7af7956b7f chore(deps): update all non-major dependencies (#3360)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-30 14:53:33 +00:00
renovate[bot] d21473fe0b chore(deps): update all non-major dependencies (#3359)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-29 17:00:09 +00:00
Jérémy Touati 4093512497 fix: fix link color when using colorized logs (#3357) 2024-10-28 12:36:45 -07:00
Amir Raminfar 0ef6252158 chore: release v8.7.1 2024-10-28 09:51:24 -07:00
Amir Raminfar 5947338966 chore: fixes vue-ignore 2024-10-28 09:37:48 -07:00
renovate[bot] db5e760ae3 chore(deps): update all non-major dependencies (#3351)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 15:32:26 +00:00
Amir Raminfar 1ab4464f9a chore: cleans up types (#3356) 2024-10-28 15:27:31 +00:00
renovate[bot] 45ea4ac095 chore(config): migrate renovate config (#3354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 14:40:33 +00:00
Amir Raminfar c6339effd1 fix: fix base ANSI convertor colors (#3353)
Co-authored-by: Jérémy Touati <sielver@gmail.com>
2024-10-27 20:37:02 +00:00
Amir Raminfar 4e217f4e3a chore: release v8.7.0 2024-10-27 08:18:51 -07:00
Amir Raminfar c58f3b4254 chore: reverts changes to proto 2024-10-27 08:15:22 -07:00
Amir Raminfar a7680940ab chore: removes drop shadow for icons (#3350) 2024-10-27 14:21:53 +00:00
Amir Raminfar cce2e8a8b5 fix: fixes toggle all when fields have not been set for JSON (#3349) 2024-10-27 14:16:20 +00:00
Amir Raminfar 8513824fb4 chore: updates protos 2024-10-27 07:04:18 -07:00
renovate[bot] 00da15c2fc fix(deps): update all non-major dependencies (#3348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-26 15:20:11 +00:00
Amir Raminfar c1d31313b2 fix: unfound fields are shown by default instead of hidden (#3342) 2024-10-26 15:15:29 +00:00
Amir Raminfar 6f7c1d8ba6 chore: updates snapshots 2024-10-25 16:06:50 -07:00
Amir Raminfar f1982c094d chore: fixes logo on mobile 2024-10-25 15:54:08 -07:00
yubiuser cd63b5ded8 fix: limit default SQL log entries to 100 (#3346)
Signed-off-by: yubiuser <github@yubiuser.dev>
2024-10-25 21:08:12 +00:00
Amir Raminfar 96fbee9ece feat: updates logo (#3340) 2024-10-25 17:55:23 +00:00
Amir Raminfar 36a5d7e6b9 fix: fixes timeout flag (#3345) 2024-10-25 17:48:54 +00:00
renovate[bot] 520d82246f chore(deps): update all non-major dependencies (#3343)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-25 16:21:34 +00:00
Amir Raminfar ddfd00aaed chore: release v8.6.2 2024-10-21 13:15:30 -07:00
Amir Raminfar f3ab541ad1 fix: fixes an edge case where a container might get stuck in created state (#3338) 2024-10-21 13:14:50 -07:00
renovate[bot] 4026e927f5 fix(deps): update all non-major dependencies (#3336)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-21 01:27:15 +00:00
Amir Raminfar b1643d490c chore: fixes typescript error 2024-10-18 10:06:50 -07:00
Amir Raminfar eab380b70d chore: fixes typescript error 2024-10-18 09:49:36 -07:00
renovate[bot] 070f1c7bdb chore(deps): update all non-major dependencies (#3335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-18 15:59:53 +00:00
Amir Raminfar 8b1adb51c8 feat: removes rounded corners in compact mode (#3332) 2024-10-16 18:50:50 -07:00
renovate[bot] 46465356ab chore(deps): update all non-major dependencies (#3333)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 14:44:22 +00:00
renovate[bot] ce096983ca fix(deps): update all non-major dependencies (#3330)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 15:14:00 +00:00
Amir Raminfar ddd3a80ddb chore: updates renovate 2024-10-14 08:09:24 -07:00
Amir Raminfar aeb1fd96e2 chore: release v8.6.1 2024-10-13 08:58:18 -07:00
renovate[bot] dc9f402a1d fix(deps): update all non-major dependencies (#3327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-13 15:55:21 +00:00
Amir Raminfar 2c2e3d5790 fix: fixes empty blank links to not show up as json (#3324) 2024-10-12 08:52:56 -07:00
Amir Raminfar 5e33094517 feat: adds a toggle for all levels (#3321) 2024-10-11 18:53:19 +00:00
renovate[bot] 853a5d4f0d fix(deps): update all non-major dependencies (#3322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-11 18:46:49 +00:00
Amir Raminfar 8ea5876615 chore: clean up 2024-10-10 08:17:40 -07:00
Amir Raminfar c4aacb211f chore: uses path instead 2024-10-09 21:05:54 -07:00
renovate[bot] 8cf0912af0 chore(deps): update all non-major dependencies (#3320)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-09 22:42:14 +00:00
Amir Raminfar cedd112f6b chore: updates duckdb 2024-10-08 18:39:27 -07:00
Amir Raminfar 01cf239569 chore: updates grpc (#3319) 2024-10-08 19:01:19 +00:00
Amir Raminfar f4f14b900c chore: fixes typescript error 2024-10-08 11:56:38 -07:00
renovate[bot] 6722a0129e fix(deps): update all non-major dependencies (#3318)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-08 11:56:33 -07:00
Amir Raminfar 277beb940b chore: clean up home page 2024-10-08 11:49:12 -07:00
Amir Raminfar 2d62257a33 chore: fixes typecheck for arrow (#3317) 2024-10-08 16:39:52 +00:00
Amir Raminfar 5a890cbb94 chore: release v8.6.0 2024-10-06 08:03:20 -07:00
renovate[bot] 39b3b1b59d fix(deps): update all non-major dependencies (#3315)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-06 14:59:08 +00:00
Amir Raminfar 567337649e feat: supports auth ttl to override session with DOZZLE_AUTH_TTL env. (#3313) 2024-10-06 06:31:40 -07:00
Amir Raminfar 423e4e11a3 chore: cleans up urls for levels (#3314) 2024-10-04 22:22:19 +00:00
Amir Raminfar 049214d529 chore: clean up sql and introduce another component (#3312) 2024-10-04 20:48:22 +00:00
Amir Raminfar d11f997999 chore: updates duckdb 2024-10-04 13:47:59 -07:00
Amir Raminfar 1e5264a00b feat: adds support for levels (#3306) 2024-10-04 13:47:12 -07:00
Amir Raminfar 157b2cb304 fix: fixes broken download logs for agent. fixes #3308 (#3311) 2024-10-04 20:21:11 +00:00
renovate[bot] dc18e0f4a4 fix(deps): update all non-major dependencies (#3310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-04 14:47:57 +00:00
Amir Raminfar 9bbe35e7fd perf: fixes performance issue with sql table 2024-10-03 18:29:22 -07:00
renovate[bot] add108dc04 chore(deps): update all non-major dependencies (#3307)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 23:14:17 +00:00
Amir Raminfar 45ec05419d chore(docs): updates remote info 2024-10-02 08:08:10 -07:00
renovate[bot] 00f0cb606a fix(deps): update all non-major dependencies (#3303)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-02 15:01:37 +00:00
Amir Raminfar 896c402adc chore: adds static check as a different build step (#3305) 2024-10-02 07:57:01 -07:00
Amir Raminfar f9f0f8f1e0 chore(docs): updates faqs 2024-10-02 07:50:08 -07:00
James O'Claire 3b014dc0c7 docs: Add Show Stopped Containers to Dozzle (#3304) 2024-10-02 07:39:33 -07:00
Amir Raminfar 3dcd5b3b78 chore: updates go version 2024-10-02 07:35:57 -07:00
71 changed files with 2232 additions and 1831 deletions
+1 -1
View File
@@ -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
+2 -3
View File
@@ -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"
}
+1 -1
View File
@@ -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:
+1 -1
View File
@@ -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:
+10 -2
View File
@@ -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
+2 -2
View File
@@ -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\
+2 -15
View File
@@ -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']>
+2
View File
@@ -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']
+4 -4
View File
@@ -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>
+1 -1
View File
@@ -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();
+7 -37
View File
@@ -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>
+23 -15
View File
@@ -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>`;
},
);
}
+4
View File
@@ -97,6 +97,10 @@ useIntersectionObserver(
> li {
@apply py-0;
}
:deep(.tag) {
@apply rounded-none;
}
}
}
</style>
+40
View File
@@ -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>
+14 -3
View File
@@ -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>
+10 -8
View File
@@ -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>
+8 -3
View File
@@ -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 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+21 -14
View File
@@ -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 };
}
+16
View File
@@ -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),
}),
);
-5
View File
@@ -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

+1
View File
@@ -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

+1
View File
@@ -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

+1 -1
View File
@@ -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"] {
+24 -6
View File
@@ -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 {
+5 -10
View File
@@ -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' },
+1 -1
View File
@@ -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
+1
View File
@@ -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>
+2 -4
View File
@@ -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%;
}
+28
View File
@@ -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:
+8
View File
@@ -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.
+1 -1
View File
@@ -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:
+1
View File
@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+7 -7
View File
@@ -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
+14
View File
@@ -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=
+12 -4
View File
@@ -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")
+78 -346
View File
@@ -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{
+79 -212
View File
@@ -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)
+30 -130
View File
@@ -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{
+11 -2
View File
@@ -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
}
+1 -1
View File
@@ -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)
+3 -1
View File
@@ -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
+21 -7
View File
@@ -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"
}
+4 -4
View File
@@ -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 {
+2 -1
View File
@@ -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"`
+6
View File
@@ -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)
+4 -3
View File
@@ -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),
},
})
+1 -1
View File
@@ -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()
+18
View File
@@ -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)
}
+14 -6
View File
@@ -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)
}
+37 -15
View File
@@ -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}
+4
View File
@@ -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()
+30 -24
View File
@@ -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 -2
View File
@@ -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
+19 -1
View File
@@ -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,
}
+36 -34
View File
@@ -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}": [
+1448 -798
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

+1 -20
View File
File diff suppressed because one or more lines are too long
+3 -15
View File
@@ -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"],
},