diff --git a/internal/api/server.go b/internal/api/server.go index 5d40ec3..53ef89d 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -250,29 +250,22 @@ func (s *Server) setupRoutes() { // Mount management routes (if manager initialized) if s.mountsHandlers != nil { s.mountsHandlers.RegisterRoutes(s.router) - log.Println("[API] Mount management routes registered at /api/mounts/*") } - log.Println("[API] Metadata Editor routes registered at /api/metadata/*") - log.Println("[API] KV Browser routes registered at /api/kv/*") - // File watcher routes (if watcher initialized) if s.watcherHandlers != nil { s.watcherHandlers.RegisterRoutes(s.router) - log.Println("[API] File watcher routes registered at /api/events/*, /api/scan/*") } // Watchers management routes (if watchers initialized) if s.watchersHandlers != nil { s.watchersHandlers.RegisterRoutes(s.router) - log.Println("[API] Watchers management routes registered at /api/watchers/*") } // WebDAV handler (caching is handled by nginx proxy_cache) if s.webdavHandler != nil { s.router.PathPrefix("/webdav/").Handler(s.webdavHandler) s.router.PathPrefix("/webdav").Handler(s.webdavHandler) - log.Println("[API] WebDAV routes registered at /webdav/*") } // Add middleware @@ -421,12 +414,49 @@ func (s *Server) RepublishMetadata() (int, error) { return s.metaPublisher.RepublishAllMetadata(republishFunc) } -// loggingMiddleware logs all requests +// statusRecorder captures the response status so loggingMiddleware can stay +// silent on success and only report failures. It forwards Flush/Unwrap so SSE +// and other streaming handlers keep working through the wrapper. +type statusRecorder struct { + http.ResponseWriter + status int + written bool +} + +func (r *statusRecorder) WriteHeader(code int) { + if !r.written { + r.status = code + r.written = true + } + r.ResponseWriter.WriteHeader(code) +} + +func (r *statusRecorder) Write(b []byte) (int, error) { + if !r.written { + r.status = http.StatusOK + r.written = true + } + return r.ResponseWriter.Write(b) +} + +func (r *statusRecorder) Flush() { + if f, ok := r.ResponseWriter.(http.Flusher); ok { + f.Flush() + } +} + +func (r *statusRecorder) Unwrap() http.ResponseWriter { return r.ResponseWriter } + +// loggingMiddleware logs a request only when it fails (status >= 400), keeping +// the nominal case quiet. Successful requests are not logged. func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() - next.ServeHTTP(w, r) - log.Printf("[API] %s %s %s", r.Method, r.URL.Path, time.Since(start)) + rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK} + next.ServeHTTP(rec, r) + if rec.status >= 400 { + log.Printf("[API] %s %s -> %d (%s)", r.Method, r.URL.Path, rec.status, time.Since(start)) + } }) } diff --git a/internal/mounts/poller.go b/internal/mounts/poller.go index 4870cd0..f2e0109 100644 --- a/internal/mounts/poller.go +++ b/internal/mounts/poller.go @@ -44,6 +44,8 @@ type PollingStatus struct { CurrentScanStartedAt int64 `json:"currentScanStartedAt,omitempty"` // ms; start of in-flight scan LastScanDurationMs int64 `json:"lastScanDurationMs,omitempty"` // duration of the previous scan NextScanAt int64 `json:"nextScanAt,omitempty"` // ms; planned start of next adaptive scan + LastFileCount int `json:"-"` // last observed file count; used to suppress no-change scan logs + scanned bool // true once at least one scan has completed for this mount } // Poller manages per-mount polling goroutines @@ -309,16 +311,22 @@ func (p *Poller) executeScan(mountID, mountPath string) (time.Duration, error) { end := time.Now() duration := end.Sub(start) + // Only log a completed scan when the file count changed (or on the very + // first scan) so a steady mount doesn't emit one line per poll tick. + changed := true p.mu.Lock() if status, exists := p.status[mountID]; exists { status.Scanning = false status.CurrentScanStartedAt = 0 status.LastScan = end.UnixMilli() status.LastScanDurationMs = duration.Milliseconds() + changed = !status.scanned || status.LastFileCount != fileCount + status.LastFileCount = fileCount + status.scanned = true } p.mu.Unlock() - if err == nil { + if err == nil && changed { log.Printf("[Poller] Poll scan complete for mount %s: %d files in %s", mountID, fileCount, duration.Round(time.Millisecond)) } diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index 03dab3f..8b940d5 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -422,10 +422,9 @@ func (w *Watcher) ScanMountPath(mountPath string) (int, error) { return 0, nil } - // Scan the directory - log.Printf("[Watcher] Scanning mount path: %s", mountPath) + // Scan the directory. The mount poller reports completed scans (only when + // the file count changes), so nothing is logged per scan here. count := w.ScanDirectory(mountPath) - log.Printf("[Watcher] Mount scan complete: %s (%d files)", mountPath, count) return count, nil } diff --git a/internal/webdav/handler.go b/internal/webdav/handler.go index 9f06c5b..95aa883 100644 --- a/internal/webdav/handler.go +++ b/internal/webdav/handler.go @@ -50,8 +50,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { path = "/" } - log.Printf("[WebDAV] %s %s", r.Method, path) - switch r.Method { case "GET", "HEAD": h.handleRead(w, r, path)