feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out: los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms + E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client). - go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths relativos reajustados a la nueva ubicacion dentro de fn_registry). - app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales. - modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports). agents_and_robots queda archivado como museo de la era Matrix.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
// Package logger provides structured JSONL logging for agents with daily
|
||||
// file rotation, size-based splitting, automatic cleanup, and query helpers.
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Standard field names for structured logging across all agents.
|
||||
const (
|
||||
FieldAgentID = "agent_id"
|
||||
FieldTraceID = "trace_id"
|
||||
FieldAction = "action"
|
||||
FieldReason = "reason"
|
||||
FieldDurationMS = "duration_ms"
|
||||
FieldTokensUsed = "tokens_used"
|
||||
FieldResult = "result"
|
||||
FieldErrorType = "error_type"
|
||||
FieldComponent = "component"
|
||||
)
|
||||
|
||||
// traceKey is the context key for trace IDs.
|
||||
type traceKey struct{}
|
||||
|
||||
// WithTraceID returns a new context carrying the given trace ID.
|
||||
func WithTraceID(ctx context.Context, id string) context.Context {
|
||||
return context.WithValue(ctx, traceKey{}, id)
|
||||
}
|
||||
|
||||
// TraceIDFromCtx extracts the trace ID from ctx, or "" if absent.
|
||||
func TraceIDFromCtx(ctx context.Context) string {
|
||||
if v, ok := ctx.Value(traceKey{}).(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LoggerConfig configures a per-agent logger.
|
||||
type LoggerConfig struct {
|
||||
BaseDir string // root log directory (default: "logs"); empty → stdout only
|
||||
AgentID string // agent identifier (required)
|
||||
MaxSizeMB int64 // max file size before rotation (default: 50)
|
||||
MaxAgeDays int // retention in days (default: 7)
|
||||
Compress bool // gzip rotated files (default: true)
|
||||
CleanupInterval time.Duration // cleanup ticker interval (default: 24h)
|
||||
Level slog.Level // minimum log level (default: INFO)
|
||||
}
|
||||
|
||||
func (c *LoggerConfig) defaults() {
|
||||
if c.BaseDir == "" {
|
||||
c.BaseDir = "logs"
|
||||
}
|
||||
if c.MaxSizeMB <= 0 {
|
||||
c.MaxSizeMB = 50
|
||||
}
|
||||
if c.MaxAgeDays <= 0 {
|
||||
c.MaxAgeDays = 7
|
||||
}
|
||||
if c.CleanupInterval <= 0 {
|
||||
c.CleanupInterval = 24 * time.Hour
|
||||
}
|
||||
}
|
||||
|
||||
// NewAgentLogger creates a structured JSON logger that writes to daily-rotated
|
||||
// JSONL files under BaseDir/<AgentID>/. It returns:
|
||||
// - a *slog.Logger pre-enriched with agent_id
|
||||
// - a cleanup func to call on shutdown (closes files, stops cleanup goroutine)
|
||||
// - an error if the log directory cannot be created
|
||||
//
|
||||
// If BaseDir is literally "stdout", the logger writes to os.Stdout with no
|
||||
// file rotation or cleanup.
|
||||
func NewAgentLogger(cfg LoggerConfig) (*slog.Logger, func(), error) {
|
||||
if cfg.BaseDir == "stdout" {
|
||||
h := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: cfg.Level})
|
||||
l := slog.New(h).With(FieldAgentID, cfg.AgentID)
|
||||
return l, func() {}, nil
|
||||
}
|
||||
|
||||
cfg.defaults()
|
||||
|
||||
w, err := NewDailyRotatingWriter(cfg.BaseDir, cfg.AgentID, cfg.MaxSizeMB, cfg.Compress)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
h := slog.NewJSONHandler(w, &slog.HandlerOptions{Level: cfg.Level})
|
||||
l := slog.New(h).With(FieldAgentID, cfg.AgentID)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go runCleanup(ctx, cfg.BaseDir, cfg.AgentID, cfg.MaxAgeDays, cfg.CleanupInterval)
|
||||
|
||||
cleanup := func() {
|
||||
cancel()
|
||||
w.Close()
|
||||
}
|
||||
|
||||
return l, cleanup, nil
|
||||
}
|
||||
Reference in New Issue
Block a user