webterm: add docker watcher event logging
Add structured server-side logs for Docker watcher lifecycle, event stream connectivity/decoding failures, start/die event handling, and container add/remove actions. This complements HTTP/WebSocket request logs with Docker-specific observability for debugging dynamic tile/session behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -111,6 +112,7 @@ func (w *DockerWatcher) addContainer(container map[string]any) {
|
|||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
|
|
||||||
w.sessionManager.AddApp(name, command, slug, true, theme)
|
w.sessionManager.AddApp(name, command, slug, true, theme)
|
||||||
|
log.Printf("docker event: added container id=%s slug=%s name=%s", containerID, slug, name)
|
||||||
if w.onContainerAdded != nil {
|
if w.onContainerAdded != nil {
|
||||||
w.onContainerAdded(slug, name, command)
|
w.onContainerAdded(slug, name, command)
|
||||||
}
|
}
|
||||||
@@ -135,6 +137,7 @@ func (w *DockerWatcher) removeContainer(containerID string) {
|
|||||||
w.sessionManager.CloseSession(sessionID)
|
w.sessionManager.CloseSession(sessionID)
|
||||||
}
|
}
|
||||||
w.sessionManager.RemoveApp(slug)
|
w.sessionManager.RemoveApp(slug)
|
||||||
|
log.Printf("docker event: removed container id=%s slug=%s", containerID, slug)
|
||||||
if w.onContainerRemoved != nil {
|
if w.onContainerRemoved != nil {
|
||||||
w.onContainerRemoved(slug)
|
w.onContainerRemoved(slug)
|
||||||
}
|
}
|
||||||
@@ -174,13 +177,16 @@ func (w *DockerWatcher) handleEvent(event map[string]any) {
|
|||||||
}
|
}
|
||||||
switch action {
|
switch action {
|
||||||
case "start":
|
case "start":
|
||||||
|
log.Printf("docker event: action=start container=%s", containerID)
|
||||||
path := fmt.Sprintf("/containers/%s/json", url.PathEscape(containerID))
|
path := fmt.Sprintf("/containers/%s/json", url.PathEscape(containerID))
|
||||||
status, body, err := unixJSONRequest(w.socketPath, http.MethodGet, path, nil)
|
status, body, err := unixJSONRequest(w.socketPath, http.MethodGet, path, nil)
|
||||||
if err != nil || status != http.StatusOK {
|
if err != nil || status != http.StatusOK {
|
||||||
|
log.Printf("docker event: start inspect failed container=%s status=%d err=%v", containerID, status, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var detail map[string]any
|
var detail map[string]any
|
||||||
if err := json.Unmarshal(body, &detail); err != nil {
|
if err := json.Unmarshal(body, &detail); err != nil {
|
||||||
|
log.Printf("docker event: start decode failed container=%s err=%v", containerID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
config := toAnyMap(detail["Config"])
|
config := toAnyMap(detail["Config"])
|
||||||
@@ -195,6 +201,7 @@ func (w *DockerWatcher) handleEvent(event map[string]any) {
|
|||||||
}
|
}
|
||||||
w.addContainer(container)
|
w.addContainer(container)
|
||||||
case "die":
|
case "die":
|
||||||
|
log.Printf("docker event: action=die container=%s", containerID)
|
||||||
w.removeContainer(containerID)
|
w.removeContainer(containerID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,6 +219,7 @@ func (w *DockerWatcher) watchEvents(ctx context.Context, waitDone chan struct{})
|
|||||||
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
|
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
|
||||||
resp, err := w.httpClient.Do(req)
|
resp, err := w.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("docker event stream connect failed err=%v", err)
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
@@ -219,10 +227,12 @@ func (w *DockerWatcher) watchEvents(ctx context.Context, waitDone chan struct{})
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("docker event stream connected")
|
||||||
decoder := json.NewDecoder(resp.Body)
|
decoder := json.NewDecoder(resp.Body)
|
||||||
for {
|
for {
|
||||||
var event map[string]any
|
var event map[string]any
|
||||||
if err := decoder.Decode(&event); err != nil {
|
if err := decoder.Decode(&event); err != nil {
|
||||||
|
log.Printf("docker event stream decode error err=%v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
w.handleEvent(event)
|
w.handleEvent(event)
|
||||||
@@ -239,8 +249,10 @@ func (w *DockerWatcher) watchEvents(ctx context.Context, waitDone chan struct{})
|
|||||||
func (w *DockerWatcher) ScanExisting() {
|
func (w *DockerWatcher) ScanExisting() {
|
||||||
containers, err := w.listLabeledContainers()
|
containers, err := w.listLabeledContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("docker scan failed err=%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("docker scan found %d labeled container(s)", len(containers))
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
w.addContainer(container)
|
w.addContainer(container)
|
||||||
}
|
}
|
||||||
@@ -258,6 +270,7 @@ func (w *DockerWatcher) Start() {
|
|||||||
w.waitDone = waitDone
|
w.waitDone = waitDone
|
||||||
w.running = true
|
w.running = true
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
|
log.Printf("docker watcher started")
|
||||||
w.ScanExisting()
|
w.ScanExisting()
|
||||||
go w.watchEvents(ctx, waitDone)
|
go w.watchEvents(ctx, waitDone)
|
||||||
}
|
}
|
||||||
@@ -276,4 +289,5 @@ func (w *DockerWatcher) Stop() {
|
|||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
<-waitDone
|
<-waitDone
|
||||||
|
log.Printf("docker watcher stopped")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user