github.com/blend/go-sdk@v1.20220411.3/logger/audit_event.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package logger 9 10 import ( 11 "context" 12 "fmt" 13 "io" 14 "strings" 15 16 "github.com/blend/go-sdk/ansi" 17 ) 18 19 // these are compile time assertions 20 var ( 21 _ Event = (*AuditEvent)(nil) 22 _ TextWritable = (*AuditEvent)(nil) 23 _ JSONWritable = (*AuditEvent)(nil) 24 ) 25 26 // NewAuditEvent returns a new audit event. 27 func NewAuditEvent(principal, verb string, options ...AuditEventOption) AuditEvent { 28 ae := AuditEvent{ 29 Principal: principal, 30 Verb: verb, 31 } 32 for _, option := range options { 33 option(&ae) 34 } 35 return ae 36 } 37 38 // NewAuditEventListener returns a new audit event listener. 39 func NewAuditEventListener(listener func(context.Context, AuditEvent)) Listener { 40 return func(ctx context.Context, e Event) { 41 if typed, isTyped := e.(AuditEvent); isTyped { 42 listener(ctx, typed) 43 } 44 } 45 } 46 47 // NewAuditEventFilter returns a new audit event filter. 48 func NewAuditEventFilter(filter func(context.Context, AuditEvent) (AuditEvent, bool)) Filter { 49 return func(ctx context.Context, e Event) (Event, bool) { 50 if typed, isTyped := e.(AuditEvent); isTyped { 51 return filter(ctx, typed) 52 } 53 return e, false 54 } 55 } 56 57 // AuditEventOption is an option for AuditEvents. 58 type AuditEventOption func(*AuditEvent) 59 60 // OptAuditContext sets a field on an AuditEvent. 61 func OptAuditContext(value string) AuditEventOption { 62 return func(ae *AuditEvent) { ae.Context = value } 63 } 64 65 // OptAuditPrincipal sets a field on an AuditEvent. 66 func OptAuditPrincipal(value string) AuditEventOption { 67 return func(ae *AuditEvent) { ae.Principal = value } 68 } 69 70 // OptAuditVerb sets a field on an AuditEvent. 71 func OptAuditVerb(value string) AuditEventOption { 72 return func(ae *AuditEvent) { ae.Verb = value } 73 } 74 75 // OptAuditNoun sets a field on an AuditEvent. 76 func OptAuditNoun(value string) AuditEventOption { 77 return func(ae *AuditEvent) { ae.Noun = value } 78 } 79 80 // OptAuditSubject sets a field on an AuditEvent. 81 func OptAuditSubject(value string) AuditEventOption { 82 return func(ae *AuditEvent) { ae.Subject = value } 83 } 84 85 // OptAuditProperty sets a field on an AuditEvent. 86 func OptAuditProperty(value string) AuditEventOption { 87 return func(ae *AuditEvent) { ae.Property = value } 88 } 89 90 // OptAuditRemoteAddress sets a field on an AuditEvent. 91 func OptAuditRemoteAddress(value string) AuditEventOption { 92 return func(ae *AuditEvent) { ae.RemoteAddress = value } 93 } 94 95 // OptAuditUserAgent sets a field on an AuditEvent. 96 func OptAuditUserAgent(value string) AuditEventOption { 97 return func(ae *AuditEvent) { ae.UserAgent = value } 98 } 99 100 // OptAuditExtra sets a field on an AuditEvent. 101 func OptAuditExtra(values map[string]string) AuditEventOption { 102 return func(ae *AuditEvent) { ae.Extra = values } 103 } 104 105 // AuditEvent is a common type of event detailing a business action by a subject. 106 type AuditEvent struct { 107 Context string 108 Principal string 109 Verb string 110 Noun string 111 Subject string 112 Property string 113 RemoteAddress string 114 UserAgent string 115 Extra map[string]string 116 } 117 118 // GetFlag implements Event. 119 func (e AuditEvent) GetFlag() string { return Audit } 120 121 // WriteText implements TextWritable. 122 func (e AuditEvent) WriteText(formatter TextFormatter, wr io.Writer) { 123 if len(e.Context) > 0 { 124 fmt.Fprint(wr, formatter.Colorize("Context:", ansi.ColorLightBlack)) 125 fmt.Fprint(wr, e.Context) 126 fmt.Fprint(wr, Space) 127 } 128 if len(e.Principal) > 0 { 129 fmt.Fprint(wr, formatter.Colorize("Principal:", ansi.ColorLightBlack)) 130 fmt.Fprint(wr, e.Principal) 131 fmt.Fprint(wr, Space) 132 } 133 if len(e.Verb) > 0 { 134 fmt.Fprint(wr, formatter.Colorize("Verb:", ansi.ColorLightBlack)) 135 fmt.Fprint(wr, e.Verb) 136 fmt.Fprint(wr, Space) 137 } 138 if len(e.Noun) > 0 { 139 fmt.Fprint(wr, formatter.Colorize("Noun:", ansi.ColorLightBlack)) 140 fmt.Fprint(wr, e.Noun) 141 fmt.Fprint(wr, Space) 142 } 143 if len(e.Subject) > 0 { 144 fmt.Fprint(wr, formatter.Colorize("Subject:", ansi.ColorLightBlack)) 145 fmt.Fprint(wr, e.Subject) 146 fmt.Fprint(wr, Space) 147 } 148 if len(e.Property) > 0 { 149 fmt.Fprint(wr, formatter.Colorize("Property:", ansi.ColorLightBlack)) 150 fmt.Fprint(wr, e.Property) 151 fmt.Fprint(wr, Space) 152 } 153 if len(e.RemoteAddress) > 0 { 154 fmt.Fprint(wr, formatter.Colorize("Remote Addr:", ansi.ColorLightBlack)) 155 fmt.Fprint(wr, e.RemoteAddress) 156 fmt.Fprint(wr, Space) 157 } 158 if len(e.UserAgent) > 0 { 159 fmt.Fprint(wr, formatter.Colorize("UA:", ansi.ColorLightBlack)) 160 fmt.Fprint(wr, e.UserAgent) 161 fmt.Fprint(wr, Space) 162 } 163 if len(e.Extra) > 0 { 164 var values []string 165 for key, value := range e.Extra { 166 values = append(values, fmt.Sprintf("%s%s", formatter.Colorize(key+":", ansi.ColorLightBlack), value)) 167 } 168 fmt.Fprint(wr, strings.Join(values, " ")) 169 } 170 } 171 172 // Decompose implements Decomposer. 173 func (e AuditEvent) Decompose() map[string]interface{} { 174 return map[string]interface{}{ 175 "context": e.Context, 176 "principal": e.Principal, 177 "verb": e.Verb, 178 "noun": e.Noun, 179 "subject": e.Subject, 180 "property": e.Property, 181 "remoteAddr": e.RemoteAddress, 182 "ua": e.UserAgent, 183 "extra": e.Extra, 184 } 185 }