...

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

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

     1  package ldevents
     2  
     3  import (
     4  	"github.com/launchdarkly/go-jsonstream/v3/jwriter"
     5  	"github.com/launchdarkly/go-sdk-common/v3/ldcontext"
     6  	"github.com/launchdarkly/go-sdk-common/v3/ldtime"
     7  )
     8  
     9  // In this file we create the analytics event JSON data that we send to LaunchDarkly. This does not
    10  // always correspond to the shape of the event objects that are fed into EventProcessor.
    11  
    12  // Event types
    13  const (
    14  	FeatureRequestEventKind = "feature"
    15  	FeatureDebugEventKind   = "debug"
    16  	CustomEventKind         = "custom"
    17  	IdentifyEventKind       = "identify"
    18  	IndexEventKind          = "index"
    19  	SummaryEventKind        = "summary"
    20  )
    21  
    22  type eventOutputFormatter struct {
    23  	contextFormatter eventContextFormatter
    24  	config           EventsConfiguration
    25  }
    26  
    27  func (ef eventOutputFormatter) makeOutputEvents(events []anyEventOutput, summary eventSummary) ([]byte, int) {
    28  	n := len(events)
    29  
    30  	w := jwriter.NewWriter()
    31  	arr := w.Array()
    32  
    33  	for _, e := range events {
    34  		ef.writeOutputEvent(&w, e)
    35  	}
    36  	if summary.hasCounters() {
    37  		ef.writeSummaryEvent(&w, summary)
    38  		n++
    39  	}
    40  
    41  	if n > 0 {
    42  		arr.End()
    43  		return w.Bytes(), n
    44  	}
    45  	return nil, 0
    46  }
    47  
    48  func (ef eventOutputFormatter) writeOutputEvent(w *jwriter.Writer, evt anyEventOutput) {
    49  	if raw, ok := evt.(rawEvent); ok {
    50  		w.Raw(raw.data)
    51  		return
    52  	}
    53  
    54  	obj := w.Object()
    55  
    56  	switch evt := evt.(type) {
    57  	case EvaluationData:
    58  		kind := FeatureRequestEventKind
    59  		if evt.debug {
    60  			kind = FeatureDebugEventKind
    61  		}
    62  		beginEventFields(&obj, kind, evt.BaseEvent.CreationDate)
    63  		obj.Name("key").String(evt.Key)
    64  		obj.Maybe("version", evt.Version.IsDefined()).Int(evt.Version.IntValue())
    65  		if evt.debug {
    66  			ef.contextFormatter.WriteContext(obj.Name("context"), &evt.Context)
    67  		} else {
    68  			writeContextKeys(&obj, &evt.Context.context)
    69  		}
    70  		obj.Maybe("variation", evt.Variation.IsDefined()).Int(evt.Variation.IntValue())
    71  		evt.Value.WriteToJSONWriter(obj.Name("value"))
    72  		evt.Default.WriteToJSONWriter(obj.Name("default"))
    73  		obj.Maybe("prereqOf", evt.PrereqOf.IsDefined()).String(evt.PrereqOf.StringValue())
    74  		if evt.Reason.GetKind() != "" {
    75  			evt.Reason.WriteToJSONWriter(obj.Name("reason"))
    76  		}
    77  
    78  	case CustomEventData:
    79  		beginEventFields(&obj, CustomEventKind, evt.BaseEvent.CreationDate)
    80  		obj.Name("key").String(evt.Key)
    81  		if !evt.Data.IsNull() {
    82  			evt.Data.WriteToJSONWriter(obj.Name("data"))
    83  		}
    84  		writeContextKeys(&obj, &evt.Context.context)
    85  		obj.Maybe("metricValue", evt.HasMetric).Float64(evt.MetricValue)
    86  
    87  	case IdentifyEventData:
    88  		beginEventFields(&obj, IdentifyEventKind, evt.BaseEvent.CreationDate)
    89  		ef.contextFormatter.WriteContext(obj.Name("context"), &evt.Context)
    90  
    91  	case indexEvent:
    92  		beginEventFields(&obj, IndexEventKind, evt.BaseEvent.CreationDate)
    93  		ef.contextFormatter.WriteContext(obj.Name("context"), &evt.Context)
    94  	}
    95  
    96  	obj.End()
    97  }
    98  
    99  func beginEventFields(obj *jwriter.ObjectState, kind string, creationDate ldtime.UnixMillisecondTime) {
   100  	obj.Name("kind").String(kind)
   101  	obj.Name("creationDate").Float64(float64(creationDate))
   102  }
   103  
   104  func writeContextKeys(obj *jwriter.ObjectState, c *ldcontext.Context) {
   105  	keysObj := obj.Name("contextKeys").Object()
   106  	for i := 0; i < c.IndividualContextCount(); i++ {
   107  		if ic := c.IndividualContextByIndex(i); ic.IsDefined() {
   108  			keysObj.Name(string(ic.Kind())).String(ic.Key())
   109  		}
   110  	}
   111  	keysObj.End()
   112  }
   113  
   114  // Transforms the summary data into the format used for event sending.
   115  func (ef eventOutputFormatter) writeSummaryEvent(w *jwriter.Writer, snapshot eventSummary) {
   116  	obj := w.Object()
   117  
   118  	obj.Name("kind").String(SummaryEventKind)
   119  	obj.Name("startDate").Float64(float64(snapshot.startDate))
   120  	obj.Name("endDate").Float64(float64(snapshot.endDate))
   121  
   122  	allFlagsObj := obj.Name("features").Object()
   123  	for flagKey, flagSummary := range snapshot.flags {
   124  		flagObj := allFlagsObj.Name(flagKey).Object()
   125  
   126  		flagSummary.defaultValue.WriteToJSONWriter(flagObj.Name("default"))
   127  
   128  		countersArr := flagObj.Name("counters").Array()
   129  		for counterKey, counterValue := range flagSummary.counters {
   130  			counterObj := countersArr.Object()
   131  			counterObj.Maybe("variation", counterKey.variation.IsDefined()).Int(counterKey.variation.IntValue())
   132  			if counterKey.version.IsDefined() {
   133  				counterObj.Name("version").Int(counterKey.version.IntValue())
   134  			} else {
   135  				counterObj.Name("unknown").Bool(true)
   136  			}
   137  			counterValue.flagValue.WriteToJSONWriter(counterObj.Name("value"))
   138  			counterObj.Name("count").Int(counterValue.count)
   139  			counterObj.End()
   140  		}
   141  		countersArr.End()
   142  
   143  		contextKindsArr := flagObj.Name("contextKinds").Array()
   144  		for kind := range flagSummary.contextKinds {
   145  			contextKindsArr.String(string(kind))
   146  		}
   147  		contextKindsArr.End()
   148  
   149  		flagObj.End()
   150  	}
   151  	allFlagsObj.End()
   152  
   153  	obj.End()
   154  }
   155  

View as plain text