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  }