diff --git a/docker-compose.yml b/docker-compose.yml index 7b7a98fc5793..9e918d2e1e10 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: - DOZZLE_FILTER=name=dozzle - DOZZLE_NO_ANALYTICS=1 - DOZZLE_HOSTNAME=localhost + - DOZZLE_LEVEL=debug ports: - 7070:8080 build: diff --git a/internal/container/container_store.go b/internal/container/container_store.go index baca0df0d45b..0d844ac0c270 100644 --- a/internal/container/container_store.go +++ b/internal/container/container_store.go @@ -26,6 +26,8 @@ type ContainerStore struct { filter ContainerFilter } +const defaultTimeout = 10 * time.Second + func NewContainerStore(ctx context.Context, client Client, filter ContainerFilter) *ContainerStore { log.Debug().Str("host", client.Host().Name).Interface("filter", filter).Msg("initializing container store") @@ -64,7 +66,7 @@ func (s *ContainerStore) checkConnectivity() error { s.connected.Store(false) }() - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s is enough to fetch all containers + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() if containers, err := s.client.ListContainers(ctx, s.filter); err != nil { return err @@ -88,7 +90,7 @@ func (s *ContainerStore) checkConnectivity() error { } go func(c Container, i int) { defer sem.Release(1) - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // 2s is hardcoded timeout for fetching container + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() if container, err := s.client.FindContainer(ctx, c.ID); err == nil { s.containers.Store(c.ID, &container) @@ -114,22 +116,29 @@ func (s *ContainerStore) ListContainers(filter ContainerFilter) ([]Container, er return nil, err } - validContainers, err := s.client.ListContainers(s.ctx, filter) - if err != nil { - return nil, err - } + containers := make([]Container, 0) + if filter.Exists() { + validContainers, err := s.client.ListContainers(s.ctx, filter) + if err != nil { + return nil, err + } - validIDMap := lo.KeyBy(validContainers, func(item Container) string { - return item.ID - }) + validIDMap := lo.KeyBy(validContainers, func(item Container) string { + return item.ID + }) - containers := make([]Container, 0) - s.containers.Range(func(_ string, c *Container) bool { - if _, ok := validIDMap[c.ID]; ok { + s.containers.Range(func(_ string, c *Container) bool { + if _, ok := validIDMap[c.ID]; ok { + containers = append(containers, *c) + } + return true + }) + } else { + s.containers.Range(func(_ string, c *Container) bool { containers = append(containers, *c) - } - return true - }) + return true + }) + } return containers, nil } @@ -158,7 +167,7 @@ func (s *ContainerStore) FindContainer(id string, filter ContainerFilter) (Conta log.Debug().Str("id", id).Msg("container doesn't have detailed information, fetching it") if newContainer, ok := s.containers.Compute(id, func(c *Container, loaded bool) (*Container, bool) { if loaded { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() if newContainer, err := s.client.FindContainer(ctx, id); err == nil { return &newContainer, false @@ -237,7 +246,7 @@ func (s *ContainerStore) init() { log.Trace().Str("event", event.Name).Str("id", event.ActorID).Msg("received container event") switch event.Name { case "start": - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) if container, err := s.client.FindContainer(ctx, event.ActorID); err == nil { list, _ := s.client.ListContainers(ctx, s.filter) diff --git a/internal/container/stats_collector.go b/internal/container/stats_collector.go index d3e48a9dcf4c..8245f8687ceb 100644 --- a/internal/container/stats_collector.go +++ b/internal/container/stats_collector.go @@ -99,7 +99,7 @@ func (sc *StatsCollector) Start(parentCtx context.Context) bool { ctx, sc.stopper = context.WithCancel(parentCtx) sc.mu.Unlock() - timeoutCtx, cancel := context.WithTimeout(parentCtx, 3*time.Second) // 3 seconds to list containers is hard limit + timeoutCtx, cancel := context.WithTimeout(parentCtx, defaultTimeout) if containers, err := sc.client.ListContainers(timeoutCtx, sc.filter); err == nil { for _, c := range containers { if c.State == "running" { diff --git a/internal/docker/client.go b/internal/docker/client.go index b80d3394c302..ef25b8c15f02 100644 --- a/internal/docker/client.go +++ b/internal/docker/client.go @@ -69,7 +69,7 @@ func NewClient(cli DockerCLI, host container.Host) container.Client { // NewClientWithFilters creates a new instance of Client with docker filters func NewLocalClient(hostname string) (container.Client, error) { - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation(), client.WithUserAgent("Docker-Client/Dozzle")) if err != nil { return nil, err @@ -109,7 +109,7 @@ func NewRemoteClient(host container.Host) (container.Client, error) { log.Debug().Msg("Not using TLS for remote client") } - opts = append(opts, client.WithAPIVersionNegotiation()) + opts = append(opts, client.WithAPIVersionNegotiation(), client.WithUserAgent("Docker-Client/Dozzle")) cli, err := client.NewClientWithOpts(opts...) diff --git a/internal/support/cli/args.go b/internal/support/cli/args.go index da67c8c68aa0..1cfecb58bef4 100644 --- a/internal/support/cli/args.go +++ b/internal/support/cli/args.go @@ -27,7 +27,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:"--timeout,env:DOZZLE_TIMEOUT" default:"3s" help:"sets the timeout for docker client"` + TimeoutString string `arg:"--timeout,env:DOZZLE_TIMEOUT" default:"10s" 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"`