logging.go raw
1 // Package subscribers provides domain event subscriber implementations.
2 package subscribers
3
4 import (
5 "encoding/hex"
6
7 "next.orly.dev/pkg/lol/log"
8
9 "next.orly.dev/pkg/domain/events"
10 )
11
12 // LoggingSubscriber logs domain events for analytics and debugging.
13 type LoggingSubscriber struct {
14 logLevel string // "debug", "info", "trace"
15 }
16
17 // NewLoggingSubscriber creates a new logging subscriber.
18 // logLevel controls verbosity: "trace" logs all events, "debug" logs important events,
19 // "info" logs only significant events like membership changes.
20 func NewLoggingSubscriber(logLevel string) *LoggingSubscriber {
21 if logLevel == "" {
22 logLevel = "debug"
23 }
24 return &LoggingSubscriber{logLevel: logLevel}
25 }
26
27 // Handle processes a domain event by logging it.
28 func (s *LoggingSubscriber) Handle(event events.DomainEvent) {
29 switch e := event.(type) {
30 case *events.EventSaved:
31 s.logEventSaved(e)
32 case *events.EventDeleted:
33 s.logEventDeleted(e)
34 case *events.FollowListUpdated:
35 s.logFollowListUpdated(e)
36 case *events.ACLMembershipChanged:
37 s.logACLMembershipChanged(e)
38 case *events.PolicyConfigUpdated:
39 s.logPolicyConfigUpdated(e)
40 case *events.UserAuthenticated:
41 s.logUserAuthenticated(e)
42 case *events.MemberJoined:
43 s.logMemberJoined(e)
44 case *events.MemberLeft:
45 s.logMemberLeft(e)
46 case *events.ConnectionOpened:
47 s.logConnectionOpened(e)
48 case *events.ConnectionClosed:
49 s.logConnectionClosed(e)
50 default:
51 if s.logLevel == "trace" {
52 log.T.F("domain event: %s", event.EventType())
53 }
54 }
55 }
56
57 // Supports returns true for all event types.
58 func (s *LoggingSubscriber) Supports(eventType string) bool {
59 return true
60 }
61
62 func (s *LoggingSubscriber) logEventSaved(e *events.EventSaved) {
63 if s.logLevel == "trace" {
64 pubkeyHex := hex.EncodeToString(e.Event.Pubkey)
65 log.T.F("event saved: kind=%d pubkey=%s admin=%v owner=%v",
66 e.Event.Kind, pubkeyHex[:16], e.IsAdmin, e.IsOwner)
67 }
68 }
69
70 func (s *LoggingSubscriber) logEventDeleted(e *events.EventDeleted) {
71 if s.logLevel == "trace" || s.logLevel == "debug" {
72 eventIDHex := hex.EncodeToString(e.EventID)
73 deletedByHex := hex.EncodeToString(e.DeletedBy)
74 log.D.F("event deleted: id=%s by=%s", eventIDHex[:16], deletedByHex[:16])
75 }
76 }
77
78 func (s *LoggingSubscriber) logFollowListUpdated(e *events.FollowListUpdated) {
79 if s.logLevel == "trace" || s.logLevel == "debug" {
80 adminHex := hex.EncodeToString(e.AdminPubkey)
81 log.D.F("follow list updated: admin=%s added=%d removed=%d",
82 adminHex[:16], len(e.AddedFollows), len(e.RemovedFollows))
83 }
84 }
85
86 func (s *LoggingSubscriber) logACLMembershipChanged(e *events.ACLMembershipChanged) {
87 // Always log ACL changes at info level - they're significant
88 pubkeyHex := hex.EncodeToString(e.Pubkey)
89 log.I.F("ACL membership changed: pubkey=%s %s->%s reason=%s",
90 pubkeyHex[:16], e.PrevLevel, e.NewLevel, e.Reason)
91 }
92
93 func (s *LoggingSubscriber) logPolicyConfigUpdated(e *events.PolicyConfigUpdated) {
94 // Always log policy changes at info level
95 updatedByHex := hex.EncodeToString(e.UpdatedBy)
96 log.I.F("policy config updated by %s: %d changes", updatedByHex[:16], len(e.Changes))
97 }
98
99 func (s *LoggingSubscriber) logUserAuthenticated(e *events.UserAuthenticated) {
100 if s.logLevel == "trace" || s.logLevel == "debug" {
101 pubkeyHex := hex.EncodeToString(e.Pubkey)
102 log.D.F("user authenticated: pubkey=%s level=%s firstTime=%v",
103 pubkeyHex[:16], e.AccessLevel, e.IsFirstTime)
104 }
105 }
106
107 func (s *LoggingSubscriber) logMemberJoined(e *events.MemberJoined) {
108 // Always log member joins at info level
109 pubkeyHex := hex.EncodeToString(e.Pubkey)
110 log.I.F("member joined: pubkey=%s invite=%s", pubkeyHex[:16], e.InviteCode)
111 }
112
113 func (s *LoggingSubscriber) logMemberLeft(e *events.MemberLeft) {
114 // Always log member departures at info level
115 pubkeyHex := hex.EncodeToString(e.Pubkey)
116 log.I.F("member left: pubkey=%s", pubkeyHex[:16])
117 }
118
119 func (s *LoggingSubscriber) logConnectionOpened(e *events.ConnectionOpened) {
120 if s.logLevel == "trace" {
121 log.T.F("connection opened: id=%s remote=%s", e.ConnectionID, e.RemoteAddr)
122 }
123 }
124
125 func (s *LoggingSubscriber) logConnectionClosed(e *events.ConnectionClosed) {
126 if s.logLevel == "trace" || s.logLevel == "debug" {
127 log.D.F("connection closed: id=%s duration=%v events_rx=%d events_tx=%d",
128 e.ConnectionID, e.Duration, e.EventsReceived, e.EventsPublished)
129 }
130 }
131