refactor: migrate from log standard library to structured logger
This commit replaces usages of the standard library `log` package (specifically `log.Printf` and `log.Fatalf`) with the custom `jane/pkg/logger` structured logger across multiple backend files (`web/backend/main.go`, `web/backend/api/gateway.go`, `web/backend/api/oauth.go`, `web/backend/embed.go`, `cmd/picoclaw/internal/gateway/helpers.go`, and `pkg/agent/instance.go`). This fulfills the pending "Structured Logging" task outlined in `docs/design/ETL_TODO.md` to ensure a unified JSON structured logging pattern throughout the codebase. Co-authored-by: hobbyistlabs-coder <267281733+hobbyistlabs-coder@users.noreply.github.com>
This commit is contained in:
parent
c31965f35e
commit
c952fb97ca
12 changed files with 75 additions and 81 deletions
|
|
@ -3,7 +3,6 @@ package gateway
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
|
@ -15,6 +14,7 @@ import (
|
|||
"jane/pkg/channels"
|
||||
_ "jane/pkg/channels/dingtalk"
|
||||
_ "jane/pkg/channels/discord"
|
||||
_ "jane/pkg/channels/gmessages"
|
||||
_ "jane/pkg/channels/irc"
|
||||
_ "jane/pkg/channels/line"
|
||||
_ "jane/pkg/channels/maixcam"
|
||||
|
|
@ -23,7 +23,6 @@ import (
|
|||
_ "jane/pkg/channels/pico"
|
||||
_ "jane/pkg/channels/qq"
|
||||
_ "jane/pkg/channels/slack"
|
||||
_ "jane/pkg/channels/gmessages"
|
||||
_ "jane/pkg/channels/telegram"
|
||||
_ "jane/pkg/channels/whatsapp"
|
||||
_ "jane/pkg/channels/whatsapp_native"
|
||||
|
|
@ -248,7 +247,7 @@ func setupCronTool(
|
|||
var err error
|
||||
cronTool, err = tools.NewCronTool(cronService, agentLoop, msgBus, workspace, restrict, execTimeout, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("Critical error during CronTool initialization: %v", err)
|
||||
logger.FatalCF("gateway", "Critical error during CronTool initialization", map[string]any{"error": err.Error()})
|
||||
}
|
||||
|
||||
agentLoop.RegisterTool(cronTool)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This document tracks the tasks required to implement the "Ultimate Visibility" E
|
|||
|
||||
## 1. Extract (Ingestion & Telemetry Collection)
|
||||
|
||||
- [ ] **Structured Logging:** Ensure `zerolog` is used consistently across the codebase for structured JSON logging. Add context to logs where missing (session IDs, tool inputs/outputs).
|
||||
- [x] **Structured Logging:** Ensure `zerolog` is used consistently across the codebase for structured JSON logging. Add context to logs where missing (session IDs, tool inputs/outputs).
|
||||
- [x] **Basic Metrics Implementation:** Introduce a metrics package (e.g., using `expvar` or a Prometheus client) to expose basic application metrics.
|
||||
- [x] **Goroutine Tracking:** Implement a metric to track the number of active Goroutines.
|
||||
- [x] **Memory Tracking:** Implement a metric to track heap allocation and GC pauses.
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ package agent
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"jane/pkg/config"
|
||||
"jane/pkg/logger"
|
||||
"jane/pkg/memory"
|
||||
"jane/pkg/providers"
|
||||
"jane/pkg/routing"
|
||||
|
|
@ -86,7 +86,7 @@ func NewAgentInstance(
|
|||
if cfg.Tools.IsToolEnabled("exec") {
|
||||
execTool, err := tools.NewExecToolWithConfig(workspace, restrict, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("Critical error: unable to initialize exec tool: %v", err)
|
||||
logger.FatalCF("agent", "Critical error: unable to initialize exec tool", map[string]any{"error": err.Error()})
|
||||
}
|
||||
toolsRegistry.Register(execTool)
|
||||
}
|
||||
|
|
@ -225,8 +225,7 @@ func NewAgentInstance(
|
|||
})
|
||||
lightCandidates = resolved
|
||||
} else {
|
||||
log.Printf("routing: light_model %q not found in model_list — routing disabled for agent %q",
|
||||
rc.LightModel, agentID)
|
||||
logger.WarnCF("agent", "routing: light_model not found in model_list — routing disabled for agent", map[string]any{"lightModel": rc.LightModel, "agentID": agentID})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +313,7 @@ func (a *AgentInstance) Close() error {
|
|||
func initSessionStore(dir string) session.SessionStore {
|
||||
store, err := memory.NewJSONLStore(dir)
|
||||
if err != nil {
|
||||
log.Printf("memory: init store: %v; using json sessions", err)
|
||||
logger.WarnCF("agent", "memory: init store failed; using json sessions", map[string]any{"error": err.Error()})
|
||||
return session.NewSessionManager(dir)
|
||||
}
|
||||
|
||||
|
|
@ -322,11 +321,11 @@ func initSessionStore(dir string) session.SessionStore {
|
|||
// Migration failure means the store could not write data.
|
||||
// Fall back to SessionManager to avoid a split state where
|
||||
// some sessions are in JSONL and others remain in JSON.
|
||||
log.Printf("memory: migration failed: %v; falling back to json sessions", merr)
|
||||
logger.WarnCF("agent", "memory: migration failed; falling back to json sessions", map[string]any{"error": merr.Error()})
|
||||
store.Close()
|
||||
return session.NewSessionManager(dir)
|
||||
} else if n > 0 {
|
||||
log.Printf("memory: migrated %d session(s) to jsonl", n)
|
||||
logger.InfoCF("agent", "memory: migrated session(s) to jsonl", map[string]any{"count": n})
|
||||
}
|
||||
|
||||
return session.NewJSONLBackend(store)
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"jane/pkg/logger"
|
||||
"github.com/mdp/qrterminal/v3"
|
||||
"github.com/rs/zerolog"
|
||||
"jane/pkg/logger"
|
||||
|
||||
"go.mau.fi/mautrix-gmessages/pkg/libgm"
|
||||
"go.mau.fi/mautrix-gmessages/pkg/libgm/events"
|
||||
|
|
@ -221,7 +221,6 @@ func (c *GMessagesChannel) handlePairing(ctx context.Context, client *GMClient)
|
|||
qrterminal.GenerateHalfBlock(qrURL, qrterminal.L, os.Stdout)
|
||||
fmt.Println("Waiting for pairing...")
|
||||
|
||||
|
||||
select {
|
||||
case <-pairingCh:
|
||||
if pairErr != nil {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
|
@ -18,6 +17,7 @@ import (
|
|||
"time"
|
||||
|
||||
"jane/pkg/config"
|
||||
"jane/pkg/logger"
|
||||
"jane/web/backend/utils"
|
||||
)
|
||||
|
||||
|
|
@ -57,20 +57,20 @@ func (h *Handler) TryAutoStartGateway() {
|
|||
|
||||
ready, reason, err := h.gatewayStartReady()
|
||||
if err != nil {
|
||||
log.Printf("Skip auto-starting gateway: %v", err)
|
||||
logger.WarnCF("gateway", "Skip auto-starting gateway", map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if !ready {
|
||||
log.Printf("Skip auto-starting gateway: %s", reason)
|
||||
logger.WarnCF("gateway", "Skip auto-starting gateway", map[string]any{"reason": reason})
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := h.startGatewayLocked()
|
||||
if err != nil {
|
||||
log.Printf("Failed to auto-start gateway: %v", err)
|
||||
logger.ErrorCF("gateway", "Failed to auto-start gateway", map[string]any{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
log.Printf("Gateway auto-started (PID: %d)", pid)
|
||||
logger.InfoCF("gateway", "Gateway auto-started", map[string]any{"pid": pid})
|
||||
}
|
||||
|
||||
// gatewayStartReady validates whether current config can start the gateway.
|
||||
|
|
@ -162,7 +162,7 @@ func (h *Handler) startGatewayLocked() (int, error) {
|
|||
|
||||
// Ensure Pico Channel is configured before starting gateway
|
||||
if _, err := h.ensurePicoChannel(); err != nil {
|
||||
log.Printf("Warning: failed to ensure pico channel: %v", err)
|
||||
logger.WarnCF("gateway", "failed to ensure pico channel", map[string]any{"error": err.Error()})
|
||||
// Non-fatal: gateway can still start without pico channel
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ func (h *Handler) startGatewayLocked() (int, error) {
|
|||
|
||||
gateway.cmd = cmd
|
||||
pid := cmd.Process.Pid
|
||||
log.Printf("Started picoclaw gateway (PID: %d) from %s", pid, execPath)
|
||||
logger.InfoCF("gateway", "Started picoclaw gateway", map[string]any{"pid": pid, "execPath": execPath})
|
||||
|
||||
// Broadcast starting event
|
||||
gateway.events.Broadcast(GatewayEvent{Status: "starting", PID: pid})
|
||||
|
|
@ -184,9 +184,9 @@ func (h *Handler) startGatewayLocked() (int, error) {
|
|||
// Wait for exit in background and clean up
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Printf("Gateway process exited: %v", err)
|
||||
logger.WarnCF("gateway", "Gateway process exited with error", map[string]any{"error": err.Error()})
|
||||
} else {
|
||||
log.Printf("Gateway process exited normally")
|
||||
logger.InfoCF("gateway", "Gateway process exited normally", nil)
|
||||
}
|
||||
|
||||
gateway.mu.Lock()
|
||||
|
|
@ -317,7 +317,7 @@ func (h *Handler) handleGatewayStop(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
log.Printf("Sent stop signal to gateway (PID: %d)", pid)
|
||||
logger.InfoCF("gateway", "Sent stop signal to gateway", map[string]any{"pid": pid})
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"jane/pkg/auth"
|
||||
"jane/pkg/config"
|
||||
"jane/pkg/logger"
|
||||
"jane/pkg/providers"
|
||||
)
|
||||
|
||||
|
|
@ -714,7 +714,7 @@ func (h *Handler) persistCredentialAndConfig(provider, authMethod string, cred *
|
|||
if cp.Email == "" {
|
||||
email, err := oauthFetchGoogleUserEmailFunc(cp.AccessToken)
|
||||
if err != nil {
|
||||
log.Printf("oauth warning: could not fetch google email: %v", err)
|
||||
logger.WarnCF("oauth", "could not fetch google email", map[string]any{"error": err.Error()})
|
||||
} else {
|
||||
cp.Email = email
|
||||
}
|
||||
|
|
@ -722,7 +722,7 @@ func (h *Handler) persistCredentialAndConfig(provider, authMethod string, cred *
|
|||
if cp.ProjectID == "" {
|
||||
projectID, err := oauthFetchAntigravityProject(cp.AccessToken)
|
||||
if err != nil {
|
||||
log.Printf("oauth warning: could not fetch antigravity project id: %v", err)
|
||||
logger.WarnCF("oauth", "could not fetch antigravity project id", map[string]any{"error": err.Error()})
|
||||
} else {
|
||||
cp.ProjectID = projectID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ package main
|
|||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"jane/pkg/logger"
|
||||
)
|
||||
|
||||
//go:embed all:dist
|
||||
|
|
@ -19,18 +20,14 @@ func registerEmbedRoutes(mux *http.ServeMux) {
|
|||
// Go's built-in mime.TypeByExtension returns "image/svg" which is incorrect
|
||||
// The correct MIME type per RFC 6838 is "image/svg+xml"
|
||||
if err := mime.AddExtensionType(".svg", "image/svg+xml"); err != nil {
|
||||
log.Printf("Warning: failed to register SVG MIME type: %v", err)
|
||||
logger.WarnCF("embed", "failed to register SVG MIME type", map[string]any{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Attempt to get the subdirectory 'dist' where Vite usually builds
|
||||
subFS, err := fs.Sub(frontendFS, "dist")
|
||||
if err != nil {
|
||||
// Log a warning if dist doesn't exist yet (e.g., during development before a frontend build)
|
||||
log.Printf(
|
||||
"Warning: no 'dist' folder found in embedded frontend. " +
|
||||
"Ensure you run `pnpm build:backend` in the frontend directory " +
|
||||
"before building the Go backend.",
|
||||
)
|
||||
logger.WarnCF("embed", "no 'dist' folder found in embedded frontend. Ensure you run `pnpm build:backend` in the frontend directory before building the Go backend.", nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ import (
|
|||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"jane/pkg/logger"
|
||||
"jane/web/backend/api"
|
||||
"jane/web/backend/launcherconfig"
|
||||
"jane/web/backend/middleware"
|
||||
|
|
@ -59,11 +59,11 @@ func main() {
|
|||
|
||||
absPath, err := filepath.Abs(configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to resolve config path: %v", err)
|
||||
logger.FatalCF("main", "Failed to resolve config path", map[string]any{"error": err.Error()})
|
||||
}
|
||||
err = utils.EnsureOnboarded(absPath)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to initialize PicoClaw config automatically: %v", err)
|
||||
logger.WarnCF("main", "Failed to initialize PicoClaw config automatically", map[string]any{"error": err.Error()})
|
||||
}
|
||||
|
||||
var explicitPort bool
|
||||
|
|
@ -80,7 +80,7 @@ func main() {
|
|||
launcherPath := launcherconfig.PathForAppConfig(absPath)
|
||||
launcherCfg, err := launcherconfig.Load(launcherPath, launcherconfig.Default())
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to load %s: %v", launcherPath, err)
|
||||
logger.WarnCF("main", "Failed to load launcher config", map[string]any{"path": launcherPath, "error": err.Error()})
|
||||
launcherCfg = launcherconfig.Default()
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ func main() {
|
|||
if err == nil {
|
||||
err = errors.New("must be in range 1-65535")
|
||||
}
|
||||
log.Fatalf("Invalid port %q: %v", effectivePort, err)
|
||||
logger.FatalCF("main", "Invalid port", map[string]any{"port": effectivePort, "error": err.Error()})
|
||||
}
|
||||
|
||||
// Determine listen address
|
||||
|
|
@ -122,7 +122,7 @@ func main() {
|
|||
|
||||
accessControlledMux, err := middleware.IPAllowlist(launcherCfg.AllowedCIDRs, mux)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid allowed CIDR configuration: %v", err)
|
||||
logger.FatalCF("main", "Invalid allowed CIDR configuration", map[string]any{"error": err.Error()})
|
||||
}
|
||||
|
||||
// Apply middleware stack
|
||||
|
|
@ -151,7 +151,7 @@ func main() {
|
|||
time.Sleep(500 * time.Millisecond)
|
||||
url := "http://localhost:" + effectivePort
|
||||
if err := utils.OpenBrowser(url); err != nil {
|
||||
log.Printf("Warning: Failed to auto-open browser: %v", err)
|
||||
logger.WarnCF("main", "Failed to auto-open browser", map[string]any{"error": err.Error()})
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
@ -173,6 +173,6 @@ func main() {
|
|||
}
|
||||
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("Server failed to start: %v", err)
|
||||
logger.FatalCF("main", "Server failed to start", map[string]any{"error": err.Error()})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue