Files
jules/engine/jlog/log.go
T
2026-04-20 13:30:26 +03:00

140 lines
3.4 KiB
Go

package jlog
import (
"context"
"log/slog"
"slices"
"time"
"github.com/d1nch8g/jules/chat"
"github.com/d1nch8g/jules/database"
"github.com/d1nch8g/jules/engine/prompt"
)
type Event struct {
ctx context.Context
attrs []slog.Attr
start time.Time
}
func FromMessage(ctx context.Context, msg chat.Message) *Event {
e := &Event{start: time.Now(), ctx: ctx}
e.attrs = append(e.attrs,
slog.String("type", "message_processing"),
slog.String("platform", msg.Chat),
slog.String("platform_user_id", msg.ID),
slog.String("message", msg.Text),
)
return e
}
func FromNotification(ctx context.Context, notif database.Notification) *Event {
e := &Event{start: time.Now(), ctx: ctx}
e.attrs = append(e.attrs,
slog.String("type", "notification_processing"),
slog.String("notification_id", notif.ID.String()),
slog.String("user_id", notif.UserID.String()),
slog.String("initiator_id", notif.InitiatorID.String()),
slog.String("content", notif.Content),
)
return e
}
func (e *Event) User(u *database.User) *Event {
e.attrs = append(e.attrs,
slog.String("user_id", u.ID.String()),
slog.String("user_lang", u.Language),
slog.String("user_tz", u.Timezone),
slog.String("user_chat", u.PreferredChat),
slog.String("user_role", u.Role),
)
return e
}
func (e *Event) Context(ctx *prompt.Context) *Event {
if ctx == nil {
return e
}
e.attrs = append(e.attrs,
slog.String("user_lang", ctx.UserLanguage),
slog.String("user_tz", ctx.UserTimezone),
slog.String("user_chat", ctx.UserPreferredChat),
slog.String("user_bind_code", ctx.UserBindCode.String()),
slog.String("user_contact_code", ctx.UserContactCode.String()),
)
for _, chat := range ctx.Chats {
e.attrs = append(e.attrs, slog.String("chat", chat.Platform))
}
for _, fact := range ctx.Facts {
e.attrs = append(e.attrs, slog.String("fact", fact.Value))
}
for _, contact := range ctx.Contacts {
e.attrs = append(e.attrs, slog.String("contact", contact.Name))
}
for _, n := range ctx.IncomingNotifications {
e.attrs = append(e.attrs, slog.String("incoming_notif", n.Content))
}
for _, n := range ctx.OutgoingNotificaions {
e.attrs = append(e.attrs, slog.String("outgoing_notif", n.Content))
}
for _, a := range ctx.RecentActions {
e.attrs = append(e.attrs, slog.String("action", string(a.Payload)))
}
return e
}
func (e *Event) LLMResponse(content string) *Event {
for i, attr := range e.attrs {
if attr.Key == "llm_response" {
e.attrs[i] = slog.String("llm_response", content)
return e
}
}
e.attrs = append(e.attrs, slog.String("llm_response", content))
return e
}
func (e *Event) Actions(actions []any) *Event {
e.attrs = slices.DeleteFunc(e.attrs, func(a slog.Attr) bool {
return a.Key == "action"
})
for _, action := range actions {
e.attrs = append(e.attrs, slog.Any("action", action))
}
return e
}
func (e *Event) Info(msg string) {
e.log(slog.LevelInfo, msg)
}
func (e *Event) Warn(msg string, errs ...error) {
if len(errs) > 0 {
for _, err := range errs {
e.attrs = append(e.attrs, slog.Any("error", err))
}
}
e.log(slog.LevelWarn, msg)
}
func (e *Event) Error(msg string, err error) {
e.attrs = append(e.attrs, slog.String("error", err.Error()))
e.log(slog.LevelError, msg)
}
func (e *Event) log(level slog.Level, msg string) {
if e.ctx == nil {
e.ctx = context.Background()
}
attrs := append(e.attrs, slog.String("duration", time.Since(e.start).String()))
slog.LogAttrs(e.ctx, level, msg, attrs...)
}