Compare commits

..

2 Commits

Author SHA1 Message Date
Amir Raminfar f794a6fa99 clean up 2026-01-22 18:57:04 -08:00
Amir Raminfar 56d53d037d chore: adds logging 2026-01-22 18:55:48 -08:00
10 changed files with 38 additions and 79 deletions
@@ -1,12 +1,12 @@
<template>
<div class="@container flex min-w-0 flex-1 items-center gap-1.5 md:gap-2">
<div class="@container flex flex-1 items-center gap-1.5 md:gap-2">
<label class="swap swap-rotate size-4">
<input type="checkbox" v-model="pinned" />
<carbon:star-filled class="swap-on text-secondary" />
<carbon:star class="swap-off" />
</label>
<div class="inline-flex min-w-0 items-center text-sm">
<div class="breadcrumbs min-w-0 overflow-x-visible p-0 font-mono">
<div class="inline-flex items-center text-sm">
<div class="breadcrumbs overflow-x-visible p-0 font-mono">
<ul>
<li v-if="config.hosts.length > 1" class="font-thin max-md:hidden">
{{ container.hostLabel }}
@@ -1,7 +1,7 @@
<template>
<div class="flex gap-1 md:gap-4">
<div
class="grid hidden min-w-15 grid-cols-[auto_1fr_auto_1fr] items-center gap-0.5 text-xs leading-none sm:grid md:grid-cols-[auto_1fr]"
class="grid min-w-15 grid-cols-[auto_1fr_auto_1fr] items-center gap-0.5 text-xs leading-none md:grid-cols-[auto_1fr]"
>
<PhArrowUp class="text-primary" />
<span class="tabular-nums">{{ formatBytes(networkRate.tx, { short: true, decimals: 1 }) }}/s</span>
+2 -11
View File
@@ -274,17 +274,8 @@ func (c *Client) StreamNewContainers(ctx context.Context, containers chan<- cont
}
}
func (c *Client) FindContainer(ctx context.Context, containerID string, labels container.ContainerLabels) (container.Container, error) {
in := &pb.FindContainerRequest{ContainerId: containerID}
if labels != nil {
in.Filter = make(map[string]*pb.RepeatedString)
for k, v := range labels {
in.Filter[k] = &pb.RepeatedString{Values: v}
}
}
response, err := c.client.FindContainer(ctx, in)
func (c *Client) FindContainer(ctx context.Context, containerID string) (container.Container, error) {
response, err := c.client.FindContainer(ctx, &pb.FindContainerRequest{ContainerId: containerID})
if err != nil {
return container.Container{}, err
}
+1 -1
View File
@@ -138,7 +138,7 @@ func TestFindContainer(t *testing.T) {
t.Fatal(err)
}
c, _ := rpc.FindContainer(context.Background(), "123456", container.ContainerLabels{})
c, _ := rpc.FindContainer(context.Background(), "123456")
assert.Equal(t, wantedContainer, c)
}
+1 -3
View File
@@ -46,9 +46,7 @@ func (p *proxyAuthContext) AuthMiddleware(next http.Handler) http.Handler {
if r.Header.Get(p.headerUser) != "" {
containerFilter, err := container.ParseContainerFilter(r.Header.Get(p.headerFilter))
if err != nil {
log.Warn().Err(err).Str("filter", r.Header.Get(p.headerFilter)).Msg("Failed to parse container filter")
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
log.Fatal().Str("filter", r.Header.Get(p.headerFilter)).Msg("Failed to parse container filter")
}
userRoles := All
if strings.TrimSpace(r.Header.Get(p.headerRoles)) != "" {
-56
View File
@@ -1,56 +0,0 @@
package auth
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/go-chi/jwtauth/v5"
"github.com/stretchr/testify/require"
)
func TestForwardProxyAuthRejectsInvalidFilter(t *testing.T) {
auth := NewForwardProxyAuth("Remote-User", "Remote-Email", "Remote-Name", "Remote-Filter", "Remote-Roles")
called := false
handler := auth.AuthMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Remote-User", "alice")
req.Header.Set("Remote-Filter", "invalid-filter")
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
require.Equal(t, http.StatusBadRequest, resp.Code)
require.False(t, called)
}
func TestUserFromContextInvalidFilterReturnsNil(t *testing.T) {
tokenAuth := jwtauth.New("HS256", []byte("secret"), nil)
_, tokenString, err := tokenAuth.Encode(map[string]interface{}{
"username": "alice",
"email": "alice@example.com",
"name": "Alice",
"filter": "invalid-filter",
})
require.NoError(t, err)
handler := jwtauth.Verifier(tokenAuth)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if UserFromContext(r.Context()) == nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tokenString)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
require.Equal(t, http.StatusUnauthorized, resp.Code)
}
+1 -2
View File
@@ -212,8 +212,7 @@ func UserFromContext(ctx context.Context) *User {
if filter, ok := claims["filter"].(string); ok {
containerFilter, err = container.ParseContainerFilter(filter)
if err != nil {
log.Warn().Err(err).Str("filter", filter).Msg("Failed to parse container filter")
return nil
log.Fatal().Err(err).Str("filter", filter).Msg("Failed to parse container filter")
}
}
roles := None
+1 -1
View File
@@ -26,7 +26,7 @@ func NewAgentService(client *agent.Client) ClientService {
}
func (a *agentService) FindContainer(ctx context.Context, id string, labels container.ContainerLabels) (container.Container, error) {
return a.client.FindContainer(ctx, id, labels)
return a.client.FindContainer(ctx, id)
}
func (a *agentService) RawLogs(ctx context.Context, container container.Container, from time.Time, to time.Time, stdTypes container.StdType) (io.ReadCloser, error) {
+27
View File
@@ -116,6 +116,14 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
levels[level] = struct{}{}
}
log.Debug().
Str("id", id).
Time("from", from).
Time("to", to).
Interface("levels", r.URL.Query()["levels"]).
Int("minimum", minimum).
Msg("fetchLogsBetweenDates request")
lastSeenId := uint32(0)
if r.URL.Query().Has("lastSeenId") {
to = to.Add(50 * time.Millisecond) // Add a little buffer to ensure we get the last event
@@ -135,6 +143,7 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
encoder = json.NewEncoder(writer)
}
iteration := 0
for {
if minimum > 0 && buffer.Len() >= minimum {
break
@@ -149,7 +158,11 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
return
}
totalFromDocker := 0
filteredByRegex := 0
filteredByLevel := 0
for event := range events {
totalFromDocker++
if everything {
if _, ok := event.Message.(string); onlyComplex && ok {
continue
@@ -160,11 +173,13 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
} else {
if regex != nil {
if !support_web.Search(regex, event) {
filteredByRegex++
continue
}
}
if _, ok := levels[event.Level]; !ok {
filteredByLevel++
continue
}
@@ -182,6 +197,17 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
}
}
log.Debug().
Int("iteration", iteration).
Time("from", from).
Time("to", to).
Int("totalFromDocker", totalFromDocker).
Int("filteredByRegex", filteredByRegex).
Int("filteredByLevel", filteredByLevel).
Int("bufferLen", buffer.Len()).
Int("minimum", minimum).
Msg("fetchLogsBetweenDates iteration stats")
if everything || from.Before(containerService.Container.Created) {
break
}
@@ -192,6 +218,7 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
from = from.Add(-delta)
delta = delta * 2
iteration++
}
log.Debug().Int("buffer_size", buffer.Len()).Msg("sending logs to client")
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "dozzle",
"version": "9.0.3",
"version": "9.0.2",
"description": "Realtime log viewer for docker containers.",
"homepage": "https://github.com/amir20/dozzle#readme",
"bugs": {