From d65d0ea5dc254ceaf6eb25065b721cf0fef9f8d1 Mon Sep 17 00:00:00 2001 From: Mauro Trulli Date: Wed, 18 Feb 2026 10:56:51 +0100 Subject: [PATCH] feat: write log on file --- cmd/picoclaw/main.go | 32 ++++++++++++++++++++++++++++++++ pkg/config/config.go | 12 ++++++++++++ 2 files changed, 44 insertions(+) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index fd7ec484a..bef1b97e4 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -405,6 +405,9 @@ func agentCmd() { os.Exit(1) } + setupLogging(cfg) + defer logger.DisableFileLogging() + msgBus := bus.NewMessageBus() agentLoop := agent.NewAgentLoop(cfg, msgBus, provider) @@ -534,6 +537,9 @@ func gatewayCmd() { os.Exit(1) } + setupLogging(cfg) + defer logger.DisableFileLogging() + provider, err := providers.CreateProvider(cfg) if err != nil { fmt.Printf("Error creating provider: %v\n", err) @@ -1425,3 +1431,29 @@ func skillsShowCmd(loader *skills.SkillsLoader, skillName string) { fmt.Println("----------------------") fmt.Println(content) } + +func setupLogging(cfg *config.Config) { + if strings.ToLower(cfg.Logging.Level) == "debug" { + logger.SetLevel(logger.DEBUG) + } else if strings.ToLower(cfg.Logging.Level) == "warn" { + logger.SetLevel(logger.WARN) + } else if strings.ToLower(cfg.Logging.Level) == "error" { + logger.SetLevel(logger.ERROR) + } else { + logger.SetLevel(logger.INFO) + } + + if cfg.Logging.EnableFile && cfg.Logging.FilePath != "" { + logPath := cfg.Logging.FilePath + if strings.HasPrefix(logPath, "~") { + home, _ := os.UserHomeDir() + logPath = filepath.Join(home, logPath[1:]) + } + + os.MkdirAll(filepath.Dir(logPath), 0755) + + if err := logger.EnableFileLogging(logPath); err != nil { + fmt.Printf("Warning: unable to create log file: %v\n", err) + } + } +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 92a4a5862..ce785cd88 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -51,6 +51,7 @@ type Config struct { Tools ToolsConfig `json:"tools"` Heartbeat HeartbeatConfig `json:"heartbeat"` Devices DevicesConfig `json:"devices"` + Logging LoggingConfig `json:"logging"` mu sync.RWMutex } @@ -166,6 +167,12 @@ type DevicesConfig struct { MonitorUSB bool `json:"monitor_usb" env:"PICOCLAW_DEVICES_MONITOR_USB"` } +type LoggingConfig struct { + EnableFile bool `json:"enable_file" env:"PICOCLAW_LOGGING_ENABLE_FILE"` + FilePath string `json:"file_path" env:"PICOCLAW_LOGGING_FILE_PATH"` + Level string `json:"level" env:"PICOCLAW_LOGGING_LEVEL"` +} + type ProvidersConfig struct { Anthropic ProviderConfig `json:"anthropic"` OpenAI OpenAIProviderConfig `json:"openai"` @@ -356,6 +363,11 @@ func DefaultConfig() *Config { Enabled: false, MonitorUSB: true, }, + Logging: LoggingConfig{ + EnableFile: false, + FilePath: "~/.picoclaw/workspace/picoclaw_audit.log", + Level: "info", + }, } }