fix: enforce log level, validate config values, ensure dedup dir, wire main to config and logging
This commit is contained in:
parent
ec17691cb4
commit
b5d4526d91
@ -2,34 +2,34 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/yourname/reddit-scraper/internal/config"
|
||||||
|
"github.com/yourname/reddit-scraper/internal/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
keyword := flag.String("keyword", "", "Search keyword (required)")
|
cfg, err := config.Load()
|
||||||
limit := flag.Int("limit", 100, "Max posts to fetch")
|
if err != nil {
|
||||||
flag.Parse()
|
fmt.Fprintln(os.Stderr, "config load:", err)
|
||||||
|
|
||||||
if *keyword == "" {
|
|
||||||
fmt.Fprintln(os.Stderr, "-keyword is required")
|
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger := logging.Init(cfg.LogLevel)
|
||||||
|
logger.Info("starting", "keyword", cfg.Keyword, "limit", cfg.Limit, "concurrency", cfg.Concurrency)
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// placeholder: in future wire up controller
|
// placeholder: in future wire up controller
|
||||||
fmt.Printf("Starting crawl for keyword=%s limit=%d\n", *keyword, *limit)
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(1 * time.Second):
|
case <-time.After(1 * time.Second):
|
||||||
fmt.Println("Done (placeholder)")
|
logger.Info("done (placeholder)")
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
fmt.Println("Cancelled")
|
logger.Info("cancelled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,28 @@ func Load() (*Config, error) {
|
|||||||
return nil, fmt.Errorf("creating output dir: %w", err)
|
return nil, fmt.Errorf("creating output dir: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic validation
|
||||||
|
if cfg.Limit <= 0 {
|
||||||
|
return nil, fmt.Errorf("limit must be > 0")
|
||||||
|
}
|
||||||
|
if cfg.Concurrency <= 0 {
|
||||||
|
return nil, fmt.Errorf("concurrency must be > 0")
|
||||||
|
}
|
||||||
|
if cfg.RetryLimit < 0 {
|
||||||
|
return nil, fmt.Errorf("retry-limit must be >= 0")
|
||||||
|
}
|
||||||
|
if cfg.RateLimitDelay <= 0 {
|
||||||
|
return nil, fmt.Errorf("rate-limit delay must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure dedup cache parent dir exists
|
||||||
|
dedupDir := filepath.Dir(cfg.DedupCachePath)
|
||||||
|
if dedupDir != "" && dedupDir != "." {
|
||||||
|
if err := os.MkdirAll(filepath.Clean(dedupDir), 0o755); err != nil {
|
||||||
|
return nil, fmt.Errorf("creating dedup cache dir: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,13 +3,30 @@ package logging
|
|||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func parseLevel(s string) slog.Level {
|
||||||
|
s = strings.ToUpper(strings.TrimSpace(s))
|
||||||
|
switch s {
|
||||||
|
case "TRACE":
|
||||||
|
return slog.LevelDebug
|
||||||
|
case "DEBUG":
|
||||||
|
return slog.LevelDebug
|
||||||
|
case "INFO":
|
||||||
|
return slog.LevelInfo
|
||||||
|
case "WARN", "WARNING":
|
||||||
|
return slog.LevelWarn
|
||||||
|
case "ERROR":
|
||||||
|
return slog.LevelError
|
||||||
|
default:
|
||||||
|
return slog.LevelInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Init initializes a global logger and returns it. Level is a string like "INFO" or "DEBUG".
|
// Init initializes a global logger and returns it. Level is a string like "INFO" or "DEBUG".
|
||||||
func Init(level string) *slog.Logger {
|
func Init(level string) *slog.Logger {
|
||||||
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{AddSource: false})
|
lvl := parseLevel(level)
|
||||||
logger := slog.New(handler)
|
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{AddSource: false, Level: lvl})
|
||||||
// Note: slog's level filtering is configured per Handler via HandlerOptions in Go 1.25;
|
return slog.New(handler)
|
||||||
// here we rely on consumer code to not spam at debug when level is INFO.
|
|
||||||
return logger
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user