Skip to content

Commit ab8c0eb

Browse files
committed
Fix vis-network loading and add structured slog logging throughout
vis-network fix: - Switch from placeholder vendor stub to CDN (unpkg.com) in index.html - Remove vendor/vis-network.min.js from embed.go (no longer embedded) - Add graceful 'vis not loaded' error message in graph.js Structured logging (log/slog): - cmd/root.go: initialise global slog text handler; add --log-level flag (debug/info/warn/error) to control verbosity - cmd/serve.go: replace fmt.Fprintf with slog.Info/Error; log store open, LLM provider init, server start, shutdown lifecycle - cmd/index.go: slog for crawl start/complete, index start/complete, finalization phases - internal/pipeline/pipeline.go: slog throughout all phases — file count, skip/supersede decisions, chunk+embed counts, entity/relationship extraction counts, community detection progress, Finalize phase markers - internal/crawler/crawler.go: slog for sitemap discovery, BFS progress, page fetch errors, crawl summary stats - internal/api/router.go: HTTP logging middleware capturing method, path, status code, duration; 5xx logged at Error, 4xx at Warn, 2xx at Info - internal/api/handlers.go: slog.Error on all 500 responses; Info on search requests and upload jobs https://claude.ai/code/session_012X8wf4jwQFRYfMnbbWCEs5
1 parent 351a27f commit ab8c0eb

10 files changed

Lines changed: 232 additions & 99 deletions

File tree

cmd/index.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package cmd
22

33
import (
44
"fmt"
5-
"os"
5+
"log/slog"
66

77
"github.com/RandomCodeSpace/docsgraphcontext/internal/llm"
88
"github.com/RandomCodeSpace/docsgraphcontext/internal/pipeline"
@@ -39,11 +39,12 @@ var indexCmd = &cobra.Command{
3939
return fmt.Errorf("llm provider: %w", err)
4040
}
4141
pl := pipeline.New(st, prov, cfg)
42-
fmt.Fprintln(os.Stderr, "Running Phase 3-4: community detection + summaries...")
42+
slog.Info("running Phase 3-4: community detection + summaries")
4343
if err := pl.Finalize(cmd.Context(), indexVerbose); err != nil {
44+
slog.Error("finalization failed", "err", err)
4445
return err
4546
}
46-
fmt.Fprintln(os.Stderr, "Finalization complete.")
47+
slog.Info("finalization complete")
4748
return nil
4849
}
4950

@@ -62,23 +63,26 @@ var indexCmd = &cobra.Command{
6263
}
6364

6465
if indexURL != "" {
65-
fmt.Fprintf(os.Stderr, "Crawling %s (workers=%d)...\n", indexURL, indexWorkers)
66+
slog.Info("crawling documentation site", "url", indexURL, "workers", indexWorkers,
67+
"max_pages", indexMaxPages, "max_depth", indexMaxDepth)
6668
if err := pl.IndexURL(cmd.Context(), indexURL, opts); err != nil {
69+
slog.Error("web indexing failed", "url", indexURL, "err", err)
6770
return err
6871
}
69-
fmt.Fprintln(os.Stderr, "Web indexing complete.")
72+
slog.Info("web indexing complete", "url", indexURL)
7073
return nil
7174
}
7275

7376
if len(args) == 0 {
7477
return fmt.Errorf("path or --url required (or use --finalize)")
7578
}
7679

77-
fmt.Fprintf(os.Stderr, "Indexing %s (workers=%d)...\n", args[0], indexWorkers)
80+
slog.Info("indexing path", "path", args[0], "workers", indexWorkers, "force", indexForce)
7881
if err := pl.IndexPath(cmd.Context(), args[0], opts); err != nil {
82+
slog.Error("indexing failed", "path", args[0], "err", err)
7983
return err
8084
}
81-
fmt.Fprintln(os.Stderr, "Indexing complete.")
85+
slog.Info("indexing complete", "path", args[0])
8286
return nil
8387
},
8488
}

cmd/root.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ package cmd
22

33
import (
44
"fmt"
5+
"log/slog"
56
"os"
67

78
"github.com/RandomCodeSpace/docsgraphcontext/internal/config"
89
"github.com/spf13/cobra"
910
)
1011

1112
var (
12-
cfgFile string
13-
cfg *config.Config
13+
cfgFile string
14+
cfg *config.Config
15+
logLevel string
1416
)
1517

1618
var rootCmd = &cobra.Command{
@@ -32,17 +34,32 @@ func Execute() {
3234
func init() {
3335
cobra.OnInitialize(initConfig)
3436
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default ~/.docsgraph/config.yaml)")
37+
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Log level: debug, info, warn, error")
3538
}
3639

3740
func initConfig() {
41+
// Set up structured logger
42+
var level slog.Level
43+
switch logLevel {
44+
case "debug":
45+
level = slog.LevelDebug
46+
case "warn":
47+
level = slog.LevelWarn
48+
case "error":
49+
level = slog.LevelError
50+
default:
51+
level = slog.LevelInfo
52+
}
53+
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: level})))
54+
3855
var err error
3956
cfg, err = config.Load(cfgFile)
4057
if err != nil {
41-
fmt.Fprintln(os.Stderr, "config error:", err)
58+
slog.Error("config error", "err", err)
4259
os.Exit(1)
4360
}
4461
if err := os.MkdirAll(cfg.DataDir, 0755); err != nil {
45-
fmt.Fprintln(os.Stderr, "mkdir error:", err)
62+
slog.Error("failed to create data directory", "path", cfg.DataDir, "err", err)
4663
os.Exit(1)
4764
}
4865
}

cmd/serve.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
"log/slog"
67
"net"
78
"net/http"
89
"os"
@@ -26,7 +27,6 @@ var serveCmd = &cobra.Command{
2627
Use: "serve",
2728
Short: "Start MCP + Web UI server",
2829
RunE: func(cmd *cobra.Command, args []string) error {
29-
// Override config with CLI flags
3030
if serveHost != "" {
3131
cfg.Server.Host = serveHost
3232
}
@@ -39,11 +39,13 @@ var serveCmd = &cobra.Command{
3939
return fmt.Errorf("open store: %w", err)
4040
}
4141
defer st.Close()
42+
slog.Info("store opened", "path", cfg.DBPath())
4243

4344
prov, err := llm.NewProvider(&cfg.LLM)
4445
if err != nil {
4546
return fmt.Errorf("llm provider: %w", err)
4647
}
48+
slog.Info("LLM provider initialised", "provider", prov.Name(), "model", prov.ModelID())
4749

4850
emb := embedder.New(prov, cfg.Indexing.BatchSize)
4951
router := api.NewRouter(st, prov, emb, cfg)
@@ -56,27 +58,32 @@ var serveCmd = &cobra.Command{
5658

5759
srv := &http.Server{Handler: router, ReadTimeout: 60 * time.Second, WriteTimeout: 120 * time.Second}
5860

59-
fmt.Fprintf(os.Stderr, "DocsGraphContext server running on http://%s\n", addr)
60-
fmt.Fprintf(os.Stderr, " Web UI: http://%s/\n", addr)
61-
fmt.Fprintf(os.Stderr, " MCP: http://%s/mcp\n", addr)
62-
fmt.Fprintf(os.Stderr, " API: http://%s/api/\n", addr)
63-
fmt.Fprintf(os.Stderr, " LLM: %s (%s)\n", prov.Name(), prov.ModelID())
61+
slog.Info("server started",
62+
"addr", "http://"+addr,
63+
"ui", "http://"+addr+"/",
64+
"mcp", "http://"+addr+"/mcp",
65+
"api", "http://"+addr+"/api/",
66+
)
6467

65-
// Graceful shutdown
6668
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
6769
defer stop()
6870

6971
go func() {
7072
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
71-
fmt.Fprintln(os.Stderr, "server error:", err)
73+
slog.Error("server error", "err", err)
7274
}
7375
}()
7476

7577
<-ctx.Done()
76-
fmt.Fprintln(os.Stderr, "\nShutting down...")
78+
slog.Info("shutting down...")
7779
shutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
7880
defer cancel()
79-
return srv.Shutdown(shutCtx)
81+
if err := srv.Shutdown(shutCtx); err != nil {
82+
slog.Error("shutdown error", "err", err)
83+
return err
84+
}
85+
slog.Info("shutdown complete")
86+
return nil
8087
},
8188
}
8289

0 commit comments

Comments
 (0)