# Repository: amir20/dozzle # Stars: 12405 ## CLAUDE.md # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Comment Style **Always use ultra-brief mode for all PR reviews and responses.** Format: - Critical issues only (bugs, security, blockers) - Brief bullet points, no lengthy explanations - Skip verbose sections (no "Strengths", "Summary", etc.) - Include file:line references when relevant - Maximum ~10-15 lines per response ## Project Overview Dozzle is a lightweight, web-based Docker log viewer with real-time monitoring capabilities. It's a hybrid application with: - **Backend**: Go (HTTP server, Docker API client, WebSocket streaming) - **Frontend**: Vue 3 (SPA with Vite, TypeScript) The application supports multiple deployment modes: standalone server, Docker Swarm, and Kubernetes (k8s). ## Development Commands ### Setup ```bash # Install dependencies pnpm install # Generate certificates and protobuf files make generate ``` ### Development ```bash # Run full development environment (backend + frontend with hot reload) make dev # Alternative: Run backend and frontend separately pnpm run watch:backend # Go backend with air (port 3100) pnpm run watch:frontend # Vite dev server (port 3100) # Run in agent mode for development pnpm run agent:dev ``` ### Building ```bash # Build frontend assets pnpm build # or make dist # Build entire application (includes frontend build) make build # Build Docker image make docker ``` ### Testing ```bash # Run Go tests make test # Run frontend tests (Vitest) pnpm test # Run in watch mode TZ=UTC pnpm test --watch # Type checking pnpm typecheck ``` ### Preview & Other ```bash # Preview production build locally pnpm preview # or make preview # Run integration tests (Playwright) make int ``` ## Architecture ### Backend (Go) The Go backend is organized into these key packages: - **`internal/web/`** - HTTP server and routing layer - Routes defined in `routes.go` using chi router - WebSocket/SSE handlers for log streaming (`logs.go`) - Authentication middleware and token management (`auth.go`) - Container action handlers (`actions.go`) - **`internal/docker/`** - Docker API client implementation - `client.go`: Main Docker client wrapper with container operations - `log_reader.go`: Streaming container logs - `stats_collector.go`: Real-time container stats collection - **`internal/agent/`** - gRPC agent for multi-host support - Uses Protocol Buffers (protos defined in `protos/`) - Enables distributed log collection across Docker hosts - **`internal/cloud/`** - Dozzle Cloud integration (tool execution engine) - `client.go`: Bidirectional gRPC stream client with auto-reconnect and exponential backoff - `tools.go`: Tool registration, dispatch (`executeTool`), and `ToolHostService` interface - `tools_containers.go`: Container listing, finding, stats, and inspection tools - `tools_logs.go`: Log fetching with level/query/regex filtering (max 100 lines) - `tools_actions.go`: Container start/stop/restart actions (gated by `enableActions`) - `tools_helpers.go`: Proto conversion utilities and host name resolution - Uses `protos/cloud.proto` for service and message definitions - **`internal/k8s/`** - Kubernetes client support - Alternative to Docker client for k8s deployments - **`internal/support/`** - Support utilities - `cli/`: Command-line argument parsing and validation - `docker/`: Multi-host Docker management and Swarm support - `container/`: Container service abstractions - `web/`: Web service utilities - **`internal/auth/`** - Authentication providers - Simple file-based auth (`simple.go`) - Forward proxy auth (`proxy.go`) - Role-based authorization (`roles.go`) - **`internal/container/`** - Container domain models and interfaces - `event_generator.go`: Log parsing and grouping logic (multi-line, JSON detection) - **`internal/notification/`** - Alert and notification system - `manager.go`: Notification rule evaluation and dispatching - `log_listener.go`: Log pattern matching for alerts - `dispatcher/`: Notification channel implementations (email, webhook, etc.) - **`graph/`** - GraphQL API layer - `schema.graphqls`: GraphQL schema definitions - `*.resolvers.go`: GraphQL resolver implementations - **`main.go`** - Application entry point with mode switching (server/swarm/k8s/agent) ### Frontend (Vue 3) The frontend uses file-based routing with these conventions: - **`assets/pages/`** - File-based routes (unplugin-vue-router) - `container/[id].vue`: Single container view - `merged/[ids].vue`: Multi-container merged view - `host/[id].vue`: Host-level logs - `service/[name].vue`: Swarm service logs - `stack/[name].vue`: Docker stack logs - `group/[name].vue`: Custom grouped logs - **`assets/components/`** - Vue components (auto-imported) - `LogViewer/`: Core log viewing components - `SimpleLogItem.vue`: Single-line log entries - `ComplexLogItem.vue`: JSON/structured log entries - `GroupedLogItem.vue`: Multi-line grouped log entries - `ContainerEventLogItem.vue`: Container lifecycle events - `SkippedEntriesLogItem.vue`: Placeholder for skipped logs - `LoadMoreLogItem.vue`: Load more historical logs - `ContainerViewer/`: Container-specific UI - `common/`: Reusable UI components - `BarChart.vue`: Lightweight bar chart with automatic downsampling - `HostCard.vue`: Host overview card with metrics - `MetricCard.vue`: Reusable metric display component - `ContainerTable.vue`: Container table with historical stat visualization - **`assets/stores/`** - Pinia stores (auto-imported) - `config.ts`: App configuration and feature flags (injected from backend HTML, frozen immutable) - `container.ts`: Container state management with EventSource streaming (`/api/events/stream`) - `hosts.ts`: Multi-host state - `settings.ts`: User preferences (localStorage-backed via profileStorage) - `pinned.ts`: Pinned container logs for side-by-side viewing - `swarm.ts`, `k8s.ts`: Deployment mode-specific state - `announcements.ts`: Feature announcements - **`assets/composable/`** - Vue composables (auto-imported) - `eventStreams.ts`: SSE connection management with buffer-based flushing (250ms debounce) - `historicalLogs.ts`: Historical log fetching - `logContext.ts`: Log filtering and search context (provide/inject pattern) - `scrollContext.ts`: Scroll state management (paused, progress, currentDate) - `storage.ts`: LocalStorage abstractions with reactivity - `visible.ts`: Log filtering by visible keys for complex logs - `containerActions.ts`: Container control operations - `duckdb.ts`: DuckDB WASM for SQL queries on logs - **`assets/modules/`** - Vue plugins - `router.ts`: Vue Router configuration - `pinia.ts`: Pinia store setup - `i18n.ts`: Internationalization ### Communication Flow 1. **Real-time Logs**: Frontend establishes SSE connections to `/api/hosts/{host}/containers/{id}/logs/stream` 2. **Container Events**: SSE stream at `/api/events/stream` pushes container lifecycle events 3. **Stats**: Real-time CPU/memory stats streamed via SSE alongside events 4. **Actions**: POST to `/api/hosts/{host}/containers/{id}/actions/{action}` (start/stop/restart) 5. **Terminal**: WebSocket connections for container attach/exec at `/api/hosts/{host}/containers/{id}/attach` 6. **GraphQL**: POST to `/api/graphql` for queries and mutations (container metadata, historical logs, notifications) ### Build System - **Frontend**: Vite builds to `dist/` with manifest - **Backend**: Embeds `dist/` using Go embed directive - **Hot Reload**: In development, `DEV=true` disables embedded assets, `LIVE_FS=true` serves from filesystem - **Makefile**: Orchestrates builds and dependency generation ## Important Development Notes ### Frontend - Auto-imports are configured for Vue composables, components, and Pinia stores (see `vite.config.ts`) - Icons use unplugin-icons with multiple icon sets (mdi, carbon, material-symbols, etc.) - Tailwind CSS with DaisyUI for styling - TypeScript definitions auto-generated in `assets/auto-imports.d.ts` and `assets/components.d.ts` - **Log Entry Types**: Three types of log messages supported - `SimpleLogEntry`: Single-line text logs (`string`) - `ComplexLogEntry`: Structured JSON logs (`JSONObject`) - `GroupedLogEntry`: Multi-line grouped logs (`string[]`) - **Type consistency**: Use `LogMessage` type alias instead of `string | string[] | JSONObject` for log entry messages - **Log Entry Factory Pattern**: Use `LogEntry.create(logEvent)` to instantiate the correct entry type based on `logEvent.t` field - **EventSource Buffering**: Log streams use buffer-based flushing (250ms debounce, 1000ms max) to batch UI updates - **Charts/Visualizations**: Custom lightweight implementations (no D3.js) - `BarChart.vue`: Self-contained bar chart with responsive downsampling - Downsampling algorithm: Averages data into buckets based on available screen width - All stat history tracked in `Container.statsHistory` (max 300 items via rolling window) - `chartData` is always a rolling window of max 300 items — array length stays constant - Uses `ref` (not `computed`) for `downsampledBars` to enable in-place mutation of the last bar, avoiding full re-renders - Component instance is reused when switching containers; parent must call exposed `recalculate()` to force refresh ### Backend - The application uses Go 1.25+ with module support - Certificate generation is required (`make generate` creates shared_key.pem and shared_cert.pem) - Protocol buffer generation happens via `go generate` directive in `main.go` - Docker client uses API version negotiation for compatibility - **GraphQL API**: Uses gqlgen with schema in `graph/schema.graphqls`, generated code in `graph/generated.go` - Run `pnpm codegen` to regenerate GraphQL types - Resolvers follow-schema layout in `graph/*.resolvers.go` - **Service Layer Architecture**: - `ClientService` interface abstracts Docker/K8s/Agent backends - `MultiHostService` orchestrates multi-host operations - `ClientManager` implementations: `RetriableClientManager` (server mode), `SwarmClientManager` (swarm mode) ### Authentication - Three modes: none, simple (file-based users.yml), forward-proxy (e.g., Authelia) - JWT tokens for simple auth with configurable TTL - User file location: `./data/users.yml` or `./data/users.yaml` ### Testing - Go tests use standard `testing` package with testify assertions - Frontend uses Vitest with `@vue/test-utils` - Integration tests with Playwright in `e2e/` - Tests must run with `TZ=UTC` for consistent timestamps ### Container Stats & Metrics - Stats are tracked using exponential moving average (EMA) with alpha=0.2 - History stored in rolling window (300 items max) via `useSimpleRefHistory` - CPU metrics normalized by core count (respects `cpuLimit` or falls back to host `nCPU`) - Memory metrics include both percentage and absolute usage (`memoryUsage` vs `memory`) - Stats visualization uses adaptive downsampling for performance ### Container Labels - `dev.dozzle.name`: Custom container display name - `dev.dozzle.group`: Group containers together - Label-based filtering throughout the application ### Deployment Modes - **Server mode** (default): Single or multi-host Docker monitoring - Uses `RetriableClientManager` with local + remote agent clients - **Swarm mode**: Automatic discovery of Swarm nodes via Docker API - Creates gRPC agent server on each node (port 7007) - Uses `SwarmClientManager` for node discovery - **K8s mode**: Pod log monitoring in Kubernetes cluster - Implements `container.Client` interface via Kubernetes API - **Agent mode**: Lightweight gRPC agent for remote log collection - Run with `dozzle agent` or `pnpm run agent:dev` - Listens on port 7007 with TLS certificate authentication ## Key Architectural Patterns ### Backend Abstraction Layers The backend follows a clean layered architecture: ``` HTTP Handlers (internal/web) ↓ HostService Interface (MultiHostService) ↓ ClientService Interface (per host) ↓ container.Client Interface ↓ Implementation (DockerClient, K8sClient, AgentClient) ``` **When adding new container operations:** 1. Define method in `container.Client` interface (`internal/container/client.go`) 2. Implement in `internal/docker/client.go` (and `internal/k8s/client.go` if applicable) 3. Add wrapper method in `ClientService` interface (`internal/support/container/service.go`) 4. Add HTTP handler in `internal/web/` with appropriate route ### Frontend Data Flow **Real-time Log Viewing:** 1. User navigates to `/container/{id}` route 2. Page component calls `useContainerStream(container)` composable 3. Composable creates EventSource connection to `/api/hosts/{host}/containers/{id}/logs/stream` 4. Backend streams `LogEvent` objects via SSE 5. Frontend buffers events (250ms debounce, max 1000ms) 6. Batched buffer flushes update reactive `messages` array 7. `LogViewer.vue` renders using appropriate component (`SimpleLogItem`, `ComplexLogItem`, `GroupedLogItem`) 8. When messages exceed `maxLogs` (400), oldest entries replaced or marked as `SkippedLogsEntry` **Stats Streaming:** 1. `container.ts` store connects to `/api/events/stream` on app init 2. Backend multiplexes container events and stats into single SSE stream 3. `container-stat` events update `Container._stat` and append to `_statsHistory` 4. EMA calculation provides smoothed `movingAverageStat` (alpha=0.2) 5. `ContainerTable.vue` displays mini bar charts using `statsHistory` with downsampling ### Protocol Buffer Flow (Agent Mode) 1. Main server creates `agent.NewClient(endpoint, certs)` for each remote host 2. AgentClient implements `container.Client` interface 3. Method calls translate to gRPC requests defined in `protos/rpc.proto` 4. Remote agent receives gRPC call, delegates to local `DockerClient` 5. Streaming RPCs (logs, stats, events) use bidirectional channels 6. Responses converted back to domain models via `FromProto()` methods ### Cloud Tool Execution Flow 1. `cloud.Client.Run()` blocks until `Notify()` signals a cloud dispatcher is configured 2. `connect()` establishes bidirectional gRPC stream (`ToolStream` RPC) to cloud endpoint 3. Cloud sends `ToolRequest` (ListTools or CallTool), client dispatches via `executeTool()` 4. Tool calls run concurrently (max 5 via weighted semaphore), responses sent back on stream 5. On disconnect, exponential backoff (1s→30s with jitter) triggers reconnection 6. `PermissionDenied` errors stop retrying permanently (invalid API key / no pro plan) 7. Tool definitions cached via `sync.Once`; zero overhead for non-cloud users ### Log Parsing Pipeline 1. Docker API returns multiplexed stream (8-byte headers + payload) 2. `log_reader.go` parses headers, extracts stdout/stderr type 3. `event_generator.go` receives raw log lines 4. Detection logic identifies: - JSON structure → `ComplexLogEntry` - Multi-line patterns (stack traces) → `GroupedLogEntry` - Single lines → `SimpleLogEntry` 5. Log level extraction via regex patterns 6. `LogEvent` serialized to JSON and sent via SSE 7. Frontend deserializes and renders with appropriate component ## Adding New Features ### Adding a New HTTP Route 1. Define route in `internal/web/routes.go` using chi router: ```go r.Get("/api/custom-endpoint", h.customHandler) ``` 2. Implement handler method in appropriate file (e.g., `actions.go`, `logs.go`) 3. Use `hostService` to find container/host via `FindContainer()` or `FindHost()` 4. Return JSON response or establish SSE/WebSocket stream ### Adding a New Log View Type 1. Create route file in `assets/pages/` (e.g., `custom/[id].vue`) 2. Create composable in `assets/composable/eventStreams.ts` (e.g., `useCustomStream()`) 3. Composable should: - Build API URL with appropriate filters - Create EventSource connection - Handle buffering and message batching - Return reactive `messages` array and control methods 4. Use `LogViewer.vue` component to render messages 5. Add backend API endpoint if needed (see above) ### Adding a New GraphQL Query/Mutation 1. Define in `graph/schema.graphqls` 2. Run `pnpm codegen` to regenerate types 3. Implement resolver in `graph/schema.resolvers.go` 4. Use `hostService` from resolver context to access backend services 5. Frontend calls via urql client (auto-imported via `@urql/vue`) ### Adding Container Stats/Metrics 1. Add field to `Stat` type in `internal/container/types.go` 2. Update `stats_collector.go` to extract metric from Docker API response 3. Add calculation logic in `docker/calculation.go` if needed 4. Ensure protobuf definition includes field in `protos/rpc.proto` 5. Frontend automatically receives updates via existing SSE stream 6. Update `Container` model in `assets/models/Container.ts` if UI needs access ### Working with Notifications/Alerts **Backend** (`internal/notification/`): - `manager.go`: Rule evaluation engine, manages alert state - `log_listener.go`: Subscribes to container log streams, evaluates rules against incoming logs - `types.go`: Alert rule definitions (log pattern matching, thresholds) - `dispatcher/`: Notification channel implementations **Frontend** (`assets/pages/notifications.vue`, `assets/components/Notification/`): - `AlertForm.vue`, `DestinationForm.vue`: UI for creating rules - Rules stored via GraphQL mutations - Alert state displayed in notification cards **Adding a new notification channel:** 1. Implement dispatcher interface in `internal/notification/dispatcher/` 2. Register in `manager.go` dispatcher factory 3. Add UI form in `assets/components/Notification/DestinationForm.vue` 4. Add GraphQL schema fields if needed ### Adding a New Cloud Tool 1. Define the tool in `AvailableTools()` in `internal/cloud/tools.go` with name, description, and parameter schema 2. Add a response message type in `protos/cloud.proto` and add it to the `CallToolResponse.result` oneof 3. Run `make generate` to regenerate protobuf code 4. Add a case in the `executeTool()` switch in `internal/cloud/tools.go` 5. Implement the execution function in the appropriate `tools_*.go` file 6. Use `ToolHostService` interface methods to access container/host data 7. Add tests in `tools_test.go` ## Common Development Patterns ### Testing - Always run Go tests with race detector: `go test -race` - Frontend tests require `TZ=UTC` for timestamp consistency - Integration tests use Playwright with `make int` (runs docker-compose setup) - Use `testify/assert` for Go test assertions ### Hot Reload Development - `make dev` runs both backend (air) and frontend (vite) with hot reload - `DEV=true` disables embedded asset serving - `LIVE_FS=true` serves assets from filesystem instead of embedded - Backend changes trigger air restart automatically - Frontend changes trigger vite HMR ### Debugging - Backend logs: Set `--level debug` flag or `DOZZLE_LEVEL=debug` env var - Frontend: Vue DevTools browser extension - GraphQL: Use GraphQL Playground at `/api/graphql` (when enabled) - SSE streams: Browser DevTools Network tab shows EventSource connections ## README.md

Dozzle Logo

# Dozzle - [dozzle.dev](https://dozzle.dev/) Dozzle is a lightweight, web-based application for monitoring Docker logs in real time. It doesn't store any log files—it's designed purely for live log viewing. https://github.com/user-attachments/assets/66a7b4b2-d6c9-4fca-ab04-aef6cd7c0c31 [![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/amir20/dozzle)](https://hub.docker.com/r/amir20/dozzle/) [![Docker Pulls](https://img.shields.io/docker/pulls/amir20/dozzle.svg)](https://hub.docker.com/r/amir20/dozzle/) [![Docker Version](https://img.shields.io/docker/v/amir20/dozzle?sort=semver)](https://hub.docker.com/r/amir20/dozzle/) ![Test](https://github.com/amir20/dozzle/workflows/Test/badge.svg) > [!NOTE] > If you like Dozzle, check out [`dtop`](https://github.com/amir20/dtop), a top-like application for monitoring Docker containers. It integrates with Dozzle to link directly to container logs. ## Features - Intelligent fuzzy search for container names - Search logs using regex - Search logs using [SQL queries](https://dozzle.dev/guide/sql-engine) - Small memory footprint - Split screen for viewing multiple logs - Live stats with memory and CPU usage - Multi-user [authentication](https://dozzle.dev/guide/authentication) with support for forward proxy authorization - [Swarm mode](https://dozzle.dev/guide/swarm-mode) support - [Agent mode](https://dozzle.dev/guide/agent) for monitoring multiple Docker hosts - Dark mode Dozzle has been tested with hundreds of containers. However, it doesn't support offline searching. Products like [Loggly](https://www.loggly.com), [Papertrail](https://papertrailapp.com), or [Kibana](https://www.elastic.co/products/kibana) are better suited for full search capabilities. ## Getting Started Dozzle is a small container (7 MB compressed). Pull the latest release with: $ docker pull amir20/dozzle:latest ### Running Dozzle The simplest way to use Dozzle is to run the Docker container. Mount the Docker Unix socket with `--volume` to `/var/run/docker.sock`: $ docker run --name dozzle -d --volume=/var/run/docker.sock:/var/run/docker.sock -p 8080:8080 amir20/dozzle:latest Dozzle will be available at [http://localhost:8080/](http://localhost:8080/). Here is a Docker Compose example: services: dozzle: container_name: dozzle image: amir20/dozzle:latest volumes: - /var/run/docker.sock:/var/run/docker.sock ports: - 8080:8080 For advanced options like [authentication](https://dozzle.dev/guide/authentication), [remote hosts](https://dozzle.dev/guide/remote-hosts), or common [questions](https://dozzle.dev/guide/faq), see the documentation at [dozzle.dev](https://dozzle.dev/guide/getting-started). ## Swarm Mode Dozzle works with Docker Swarm. You can run Dozzle as a global service: $ docker service create --name dozzle --env DOZZLE_MODE=swarm --mode global --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock -p 8080:8080 amir20/dozzle:latest See the [Swarm Mode](https://dozzle.dev/guide/swarm-mode) documentation for more details. ## Agent Mode Dozzle can monitor multiple Docker hosts. Run Dozzle in agent mode with: $ docker run -v /var/run/docker.sock:/var/run/docker.sock -p 7007:7007 amir20/dozzle:latest agent See the [Agent Mode](https://dozzle.dev/guide/agent) documentation for more details. ## Technical Details Dozzle uses automatic API negotiation, which works with most Docker configurations. Dozzle also works with [Colima](https://github.com/abiosoft/colima) and [Podman](https://podman.io/). ### Installation on Podman By default, Podman doesn't have a background process, but you can enable the remote socket for Dozzle to work. First, verify if your Podman installation has the remote socket enabled: ``` podman info ``` If you see output like this under the remote socket key, it's already enabled: ``` remoteSocket: exists: true path: /run/user/1000/podman/podman.sock ``` If it's not enabled, follow [this tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/socket_activation.md) to enable it. Once the Podman remote socket is enabled, you can run Dozzle: ``` podman run --volume=/run/user/1000/podman/podman.sock:/var/run/docker.sock -d -p 8080:8080 docker.io/amir20/dozzle:latest ``` Additionally, you need to create a fake engine-id to prevent `host not found` errors. Podman doesn't generate an engine-id like Docker does, due to its daemonless architecture. Create a file named `engine-id` under `/var/lib/docker`. On a system with Podman, you'll need to create the folder path as well. Place a UUID inside the file, for example using `uuidgen > engine-id`. The file should contain an identifier like: `b9f1d7fc-b459-4b6e-9f7a-e3d1cd2e14a9`. For more details, see [Podman Info](docs/guide/podman.md) or the [FAQ](docs/guide/faq.md#i-am-seeing-host-not-found-error-in-the-logs-how-do-i-fix-it). ## Security Dozzle supports file-based authentication and forward proxy authentication with tools like [Authelia](https://www.authelia.com/). See the documentation at https://dozzle.dev/guide/authentication. ## Analytics Dozzle collects anonymous user configurations using Google Analytics. Why? Dozzle is an open source project with no funding, so there's no time for formal user studies. Analytics help prioritize features and fixes based on how people use Dozzle. This data is completely public and can be viewed live on the [Data Studio dashboard](https://datastudio.google.com/s/naeIu0MiWsY). To disable analytics, use the `--no-analytics` flag. ## Environment Variables and Configuration Dozzle follows the [12-factor](https://12factor.net/) model. Configuration can be done via CLI flags or environment variables. See the documentation at [dozzle.dev/guide/supported-env-vars](https://dozzle.dev/guide/supported-env-vars) for more details. ## Support There are many ways to support Dozzle: - Use it! Write about it! Star it! If you love Dozzle, drop me a line and tell me what you love. - Blog about Dozzle to spread the word. If you're good at writing, send PRs to improve the documentation at [dozzle.dev](https://dozzle.dev/). - Sponsor my work at https://www.buymeacoffee.com/amirraminfar Buy Me A Coffee ## License [MIT](LICENSE) ## Building To build and test locally: 1. Install [Node.js](https://nodejs.org/en/download/) and [pnpm](https://pnpm.io/installation). 2. Install [Go](https://go.dev/doc/install). 3. Install [protoc](https://grpc.io/docs/protoc-installation/). 4. Install Go tools with `go install tool`. 5. Install Node modules with `pnpm install`. 6. Run `make dev` to start a development server with hot reload.