feat: integrar structured logging en todos los componentes del shell
Se propaga *slog.Logger a todos los componentes impuros del shell: - shell/bus/ — logs de subscribe, send, reply, timeout, unsubscribe - shell/effects/ — duración y resultado de cada action ejecutada - shell/llm/ (anthropic, openai, factory) — request/response con tokens, duración, fallback - shell/memory/sqlite — open, save, recall, close con detalles - shell/ssh/ — inicio, fin, errores y duración de comandos SSH - tools/registry — registro, ejecución y errores de herramientas Se usa el paquete shell/logger para field names consistentes (FieldDurationMS, FieldTokensUsed, etc.). Cada componente recibe el logger por inyección de dependencias, sin globals. Las firmas de New/FromConfig se actualizan para aceptar *slog.Logger. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+17
-3
@@ -4,6 +4,7 @@ package bus
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -30,15 +31,18 @@ type Bus struct {
|
||||
mu sync.RWMutex
|
||||
channels map[AgentID]chan AgentMessage
|
||||
|
||||
replyMu sync.Mutex
|
||||
replyChs map[string]chan AgentMessage // taskID → one-shot reply channel
|
||||
replyMu sync.Mutex
|
||||
replyChs map[string]chan AgentMessage // taskID → one-shot reply channel
|
||||
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// New creates a new Bus.
|
||||
func New() *Bus {
|
||||
func New(logger *slog.Logger) *Bus {
|
||||
return &Bus{
|
||||
channels: make(map[AgentID]chan AgentMessage),
|
||||
replyChs: make(map[string]chan AgentMessage),
|
||||
logger: logger.With("component", "bus"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +52,7 @@ func (b *Bus) Subscribe(id AgentID) <-chan AgentMessage {
|
||||
defer b.mu.Unlock()
|
||||
ch := make(chan AgentMessage, 64)
|
||||
b.channels[id] = ch
|
||||
b.logger.Info("bus_subscribe", "agent", id)
|
||||
return ch
|
||||
}
|
||||
|
||||
@@ -57,12 +62,15 @@ func (b *Bus) Send(msg AgentMessage) error {
|
||||
ch, ok := b.channels[msg.To]
|
||||
b.mu.RUnlock()
|
||||
if !ok {
|
||||
b.logger.Warn("bus_not_found", "to", msg.To, "from", msg.From, "kind", msg.Kind)
|
||||
return fmt.Errorf("agent %q not registered on bus", msg.To)
|
||||
}
|
||||
select {
|
||||
case ch <- msg:
|
||||
b.logger.Debug("bus_send", "from", msg.From, "to", msg.To, "kind", msg.Kind)
|
||||
return nil
|
||||
default:
|
||||
b.logger.Warn("bus_queue_full", "to", msg.To, "from", msg.From, "kind", msg.Kind)
|
||||
return fmt.Errorf("agent %q message queue full", msg.To)
|
||||
}
|
||||
}
|
||||
@@ -86,6 +94,8 @@ func (b *Bus) SendAndWait(ctx context.Context, msg AgentMessage, taskID string,
|
||||
return AgentMessage{}, err
|
||||
}
|
||||
|
||||
b.logger.Debug("bus_send_and_wait", "task", taskID, "to", msg.To, "timeout", timeout)
|
||||
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
@@ -93,6 +103,7 @@ func (b *Bus) SendAndWait(ctx context.Context, msg AgentMessage, taskID string,
|
||||
case reply := <-ch:
|
||||
return reply, nil
|
||||
case <-timer.C:
|
||||
b.logger.Warn("bus_timeout", "task", taskID, "to", msg.To, "timeout", timeout)
|
||||
return AgentMessage{}, fmt.Errorf("task %s: delegation timeout after %s", taskID, timeout)
|
||||
case <-ctx.Done():
|
||||
return AgentMessage{}, ctx.Err()
|
||||
@@ -109,8 +120,10 @@ func (b *Bus) Reply(taskID string, msg AgentMessage) error {
|
||||
if ok {
|
||||
select {
|
||||
case ch <- msg:
|
||||
b.logger.Debug("bus_reply", "task", taskID, "from", msg.From)
|
||||
return nil
|
||||
default:
|
||||
b.logger.Warn("bus_reply_full", "task", taskID)
|
||||
return fmt.Errorf("reply channel full for task %s", taskID)
|
||||
}
|
||||
}
|
||||
@@ -125,5 +138,6 @@ func (b *Bus) Unsubscribe(id AgentID) {
|
||||
if ch, ok := b.channels[id]; ok {
|
||||
close(ch)
|
||||
delete(b.channels, id)
|
||||
b.logger.Info("bus_unsubscribe", "agent", id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user