...

Source file src/github.com/launchdarkly/go-sdk-events/v2/inputs.go

Documentation: github.com/launchdarkly/go-sdk-events/v2

     1  package ldevents
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
     7  	"github.com/launchdarkly/go-sdk-common/v3/ldreason"
     8  	"github.com/launchdarkly/go-sdk-common/v3/ldtime"
     9  	"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
    10  )
    11  
    12  // EventInputContext represents context information that is being used as part of the inputs to an
    13  // event-generating action. It is a combination of the standard Context struct with additional
    14  // information that may be relevant outside of the standard SDK event generation context.
    15  //
    16  // Specifically, this is because ld-relay uses go-sdk-events to post-process events it has
    17  // received from the PHP SDK. In this scenario the PHP SDK will have already applied the
    18  // private-attribute-redaction logic, so there is no need to do any further transformation
    19  // of the context.
    20  //
    21  // That requirement is specific to ld-relay. In regular usage of the Go SDK, we always just use the
    22  // plain Context constructor.
    23  type EventInputContext struct {
    24  	context       ldcontext.Context
    25  	preserialized json.RawMessage
    26  }
    27  
    28  // Context creates an EventInputContext that is exactly equivalent to the given Context.
    29  func Context(context ldcontext.Context) EventInputContext {
    30  	return EventInputContext{context: context}
    31  }
    32  
    33  // PreserializedContext creates an EventInputContext that contains both a Context and its already-computed
    34  // JSON representation. This representation will be written directly to the output with no further
    35  // processing. The properties of the wrapped Context are not important except for its Kind, Key, and
    36  // FullyQualifiedKey, which are used for context deduplication.
    37  func PreserializedContext(context ldcontext.Context, jsonData json.RawMessage) EventInputContext {
    38  	return EventInputContext{context: context, preserialized: jsonData}
    39  }
    40  
    41  // BaseEvent provides properties common to all events.
    42  type BaseEvent struct {
    43  	CreationDate ldtime.UnixMillisecondTime
    44  	Context      EventInputContext
    45  }
    46  
    47  // EvaluationData is generated by evaluating a feature flag or one of a flag's prerequisites.
    48  type EvaluationData struct {
    49  	BaseEvent
    50  	// Key is the flag key.
    51  	Key string
    52  	// Variation is the result variation index. It is empty if evaluation failed.
    53  	Variation ldvalue.OptionalInt
    54  	// Value is the result value.
    55  	Value ldvalue.Value
    56  	// Default is the default value that was passed in by the application.
    57  	Default ldvalue.Value
    58  	// Version is the flag version. It is empty if the flag was not found.
    59  	Version ldvalue.OptionalInt
    60  	// PrereqOf is normally empty, but if this evaluation was done for a prerequisite, it is the key of the
    61  	// original key that referenced this flag as a prerequisite.
    62  	PrereqOf ldvalue.OptionalString
    63  	// Reason is the evaluation reason, if the reason should be included in the event, or empty otherwise.
    64  	Reason ldreason.EvaluationReason
    65  	// RequireFullEvent is true if an individual evaluation event should be included in the output event data,
    66  	// or false if this evaluation should only produce summary data (and potentially an index event).
    67  	RequireFullEvent bool
    68  	// DebugEventsUntilDate is non-zero if event debugging has been temporarily enabled for the flag. It is the
    69  	// time at which debugging mode should expire.
    70  	DebugEventsUntilDate ldtime.UnixMillisecondTime
    71  	// debug is true if this is a copy of an evaluation event that we have queued to be output as a debug
    72  	// event. This field is not exported because it is never part of the input parameters from the application;
    73  	// we debug events only internally, based on DebugEventsUntilDate.
    74  	debug bool
    75  }
    76  
    77  // CustomEventData is generated by calling the client's Track method.
    78  type CustomEventData struct {
    79  	BaseEvent
    80  	Key         string
    81  	Data        ldvalue.Value
    82  	HasMetric   bool
    83  	MetricValue float64
    84  }
    85  
    86  // IdentifyEventData is generated by calling the client's Identify method.
    87  type IdentifyEventData struct {
    88  	BaseEvent
    89  }
    90  
    91  // indexEvent is generated internally to capture user details from other events. It is an implementation
    92  // detail of DefaultEventProcessor, so it is not exported.
    93  type indexEvent struct {
    94  	BaseEvent
    95  }
    96  
    97  // rawEvent is used internally when the Relay Proxy needs to inject a JSON event into the outbox that
    98  // will be sent exactly as is with no processing.
    99  type rawEvent struct {
   100  	data json.RawMessage
   101  }
   102  
   103  // FlagEventProperties contains basic information about a feature flag that the events package needs. This allows
   104  // go-sdk-events to be implemented independently of go-server-side-evaluation where the flag model is defined. It
   105  // also allows us to use go-sdk-events in a client-side Go SDK, where the flag model will be different, if we ever
   106  // implement a client-side Go SDK.
   107  type FlagEventProperties struct {
   108  	// Key is the feature flag key.
   109  	Key string
   110  	// Version is the feature flag version.
   111  	Version int
   112  	// RequireFullEvent is true if the flag has been configured to always generate detailed event data.
   113  	RequireFullEvent bool
   114  	// DebugEventsUntilDate is non-zero if event debugging has been temporarily enabled for the flag. It is the
   115  	// time at which debugging mode should expire.
   116  	DebugEventsUntilDate ldtime.UnixMillisecondTime
   117  }
   118  
   119  // EventFactory is a configurable factory for event objects.
   120  type EventFactory struct {
   121  	includeReasons bool
   122  	timeFn         func() ldtime.UnixMillisecondTime
   123  }
   124  
   125  // NewEventFactory creates an EventFactory.
   126  //
   127  // The includeReasons parameter is true if evaluation events should always include the EvaluationReason (this is
   128  // used by the SDK when one of the "VariationDetail" methods is called). The timeFn parameter is normally nil but
   129  // can be used to instrument the EventFactory with a source of time data other than the standard clock.
   130  //
   131  // The isExperimentFn parameter is necessary to provide the additional experimentation behavior that is
   132  func NewEventFactory(includeReasons bool, timeFn func() ldtime.UnixMillisecondTime) EventFactory {
   133  	if timeFn == nil {
   134  		timeFn = ldtime.UnixMillisNow
   135  	}
   136  	return EventFactory{includeReasons, timeFn}
   137  }
   138  
   139  // NewUnknownFlagEvaluationData creates EvaluationData for a missing flag.
   140  func (f EventFactory) NewUnknownFlagEvaluationData(
   141  	key string,
   142  	context EventInputContext,
   143  	defaultVal ldvalue.Value,
   144  	reason ldreason.EvaluationReason,
   145  ) EvaluationData {
   146  	ed := EvaluationData{
   147  		BaseEvent: BaseEvent{
   148  			CreationDate: f.timeFn(),
   149  			Context:      context,
   150  		},
   151  		Key:     key,
   152  		Value:   defaultVal,
   153  		Default: defaultVal,
   154  	}
   155  	if f.includeReasons {
   156  		ed.Reason = reason
   157  	}
   158  	return ed
   159  }
   160  
   161  // NewEvaluationData creates EvaluationData for an existing flag.
   162  //
   163  // The isExperiment parameter, if true, means that a full evaluation event should be generated (regardless
   164  // of whether flagProps.RequireFullEvent is true) and the evaluation reason should be included in the event
   165  // (even if it normally would not have been). In the server-side SDK, that is determined by the IsExperiment
   166  // field returned by the evaluator.
   167  func (f EventFactory) NewEvaluationData(
   168  	flagProps FlagEventProperties,
   169  	context EventInputContext,
   170  	detail ldreason.EvaluationDetail,
   171  	isExperiment bool,
   172  	defaultVal ldvalue.Value,
   173  	prereqOf string,
   174  ) EvaluationData {
   175  	ed := EvaluationData{
   176  		BaseEvent: BaseEvent{
   177  			CreationDate: f.timeFn(),
   178  			Context:      context,
   179  		},
   180  		Key:                  flagProps.Key,
   181  		Version:              ldvalue.NewOptionalInt(flagProps.Version),
   182  		Variation:            detail.VariationIndex,
   183  		Value:                detail.Value,
   184  		Default:              defaultVal,
   185  		RequireFullEvent:     isExperiment || flagProps.RequireFullEvent,
   186  		DebugEventsUntilDate: flagProps.DebugEventsUntilDate,
   187  	}
   188  	if f.includeReasons || isExperiment {
   189  		ed.Reason = detail.Reason
   190  	}
   191  	if prereqOf != "" {
   192  		ed.PrereqOf = ldvalue.NewOptionalString(prereqOf)
   193  	}
   194  	return ed
   195  }
   196  
   197  // NewCustomEventData creates input parameters for a custom event. No event is actually generated until you
   198  // call EventProcessor.RecordCustomEvent.
   199  func (f EventFactory) NewCustomEventData(
   200  	key string,
   201  	context EventInputContext,
   202  	data ldvalue.Value,
   203  	withMetric bool,
   204  	metricValue float64,
   205  ) CustomEventData {
   206  	ce := CustomEventData{
   207  		BaseEvent: BaseEvent{
   208  			CreationDate: f.timeFn(),
   209  			Context:      context,
   210  		},
   211  		Key:         key,
   212  		Data:        data,
   213  		HasMetric:   withMetric,
   214  		MetricValue: metricValue,
   215  	}
   216  	return ce
   217  }
   218  
   219  // NewIdentifyEventData constructs input parameters for an identify event. No event is actually generated until you
   220  // call EventProcessor.RecordIdentifyEvent.
   221  func (f EventFactory) NewIdentifyEventData(context EventInputContext) IdentifyEventData {
   222  	return IdentifyEventData{
   223  		BaseEvent: BaseEvent{
   224  			CreationDate: f.timeFn(),
   225  			Context:      context,
   226  		},
   227  	}
   228  }
   229  

View as plain text