mirror of
https://github.com/amir20/dozzle.git
synced 2026-08-08 05:51:57 +00:00
Compare commits
2 Commits
v9.x
..
issue-4348
| Author | SHA1 | Date | |
|---|---|---|---|
| f794a6fa99 | |||
| 56d53d037d |
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)) != "" {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user