README

LaunchDarkly Go SDK Events Engine

Circle CI Documentation

Overview

This repository contains the internal analytics event logic and event data model used by the LaunchDarkly Go SDK. It is packaged separately because it is also used by internal LaunchDarkly components. Applications using the LaunchDarkly Go SDK should not need to reference this package directly.

Note that the base import path is gopkg.in/launchdarkly/go-sdk-events.v1, not github.com/launchdarkly/go-sdk-events. This ensures that the package can be referenced not only as a Go module, but also by projects that use older tools like dep and govendor, because the 5.x release of the Go SDK supports either module or non-module usage. Future releases of this package, and of the Go SDK, may drop support for non-module usage.

Supported Go versions

This version of the project has been tested with Go 1.14 and higher.

Learn more

Check out our documentation for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the complete reference guide for the Go SDK, or the generated API documentation for this project.

Contributing

We encourage pull requests and other contributions from the community. Check out our contributing guidelines for instructions on how to contribute to this SDK.

About LaunchDarkly

  • LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
    • Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
    • Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).
    • Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.
    • Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate maintenance, without taking everything offline.
  • LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out our documentation for a complete list.
  • Explore LaunchDarkly
Expand ▾ Collapse ▴

Documentation

Overview

Package ldevents implements the SDK's analytics event pipeline and diagnostic event reporting.

Index

Constants

const (
	FeatureRequestEventKind = "feature"
	FeatureDebugEventKind   = "debug"
	CustomEventKind         = "custom"
	IdentifyEventKind       = "identify"
	IndexEventKind          = "index"
	SummaryEventKind        = "summary"
)

Event types


const DefaultDiagnosticRecordingInterval = 15 * time.Minute

DefaultDiagnosticRecordingInterval is the default value for EventsConfiguration.DiagnosticRecordingInterval.


const DefaultFlushInterval = 5 * time.Second

DefaultFlushInterval is the default value for EventsConfiguration.FlushInterval.


const DefaultUserKeysFlushInterval = 5 * time.Minute

DefaultUserKeysFlushInterval is the default value for EventsConfiguration.UserKeysFlushInterval.


const MinimumDiagnosticRecordingInterval = 1 * time.Minute

MinimumDiagnosticRecordingInterval is the minimum value for EventsConfiguration.DiagnosticRecordingInterval.


Variables

This section is empty.

Functions

func NewDiagnosticID

func NewDiagnosticID(sdkKey string) ldvalue.Value

NewDiagnosticID creates a unique identifier for this SDK instance.

Types

type BaseEvent

type BaseEvent struct {
	CreationDate ldtime.UnixMillisecondTime
	User         EventUser
}

BaseEvent provides properties common to all events.

type CustomEvent

type CustomEvent struct {
	BaseEvent
	Key         string
	Data        ldvalue.Value
	HasMetric   bool
	MetricValue float64
}

CustomEvent is generated by calling the client's Track method.

func (CustomEvent) GetBase

func (evt CustomEvent) GetBase() BaseEvent

GetBase returns the BaseEvent

type DiagnosticsManager

type DiagnosticsManager struct {
	// contains filtered or unexported fields
}

DiagnosticsManager is an object that maintains state for diagnostic events and produces JSON data.

The format of the JSON event data is subject to change. Diagnostic events are represented opaquely with the Value type.

func NewDiagnosticsManager

func NewDiagnosticsManager(
	id ldvalue.Value,
	configData ldvalue.Value,
	sdkData ldvalue.Value,
	startTime time.Time,
	periodicEventGate <-chan struct{},
) *DiagnosticsManager

NewDiagnosticsManager creates an instance of DiagnosticsManager.

func (*DiagnosticsManager) CanSendStatsEvent

func (m *DiagnosticsManager) CanSendStatsEvent() bool

CanSendStatsEvent is strictly for test instrumentation. In unit tests, we need to be able to stop DefaultEventProcessor from constructing the periodic event until the test has finished setting up its preconditions. This is done by passing in a periodicEventGate channel which the test will push to when it's ready.

func (*DiagnosticsManager) CreateInitEvent

func (m *DiagnosticsManager) CreateInitEvent() ldvalue.Value

CreateInitEvent is called by DefaultEventProcessor to create the initial diagnostics event that includes the configuration.

func (*DiagnosticsManager) CreateStatsEventAndReset

func (m *DiagnosticsManager) CreateStatsEventAndReset(
	droppedEvents int,
	deduplicatedUsers int,
	eventsInLastBatch int,
) ldvalue.Value

CreateStatsEventAndReset is called by DefaultEventProcessor to create the periodic event containing usage statistics. Some of the statistics are passed in as parameters because DefaultEventProcessor owns them and can more easily keep track of them internally - pushing them into DiagnosticsManager would require frequent lock usage.

func (*DiagnosticsManager) RecordStreamInit

func (m *DiagnosticsManager) RecordStreamInit(
	timestamp ldtime.UnixMillisecondTime,
	failed bool,
	durationMillis uint64,
)

RecordStreamInit is called by the stream processor when a stream connection has either succeeded or failed.

type Event

type Event interface {
	GetBase() BaseEvent
}

Event represents an analytics event generated by the client, which will be passed to the EventProcessor. The event data that the EventProcessor actually sends to LaunchDarkly may be slightly different.

type EventDataKind

type EventDataKind string

EventDataKind is a parameter passed to EventSender to indicate the type of event data payload.

const (
	// AnalyticsEventDataKind denotes a payload of analytics event data.
	AnalyticsEventDataKind EventDataKind = "analytics"
	// DiagnosticEventDataKind denotes a payload of diagnostic event data.
	DiagnosticEventDataKind EventDataKind = "diagnostic"
)

type EventFactory

type EventFactory struct {
	// contains filtered or unexported fields
}

EventFactory is a configurable factory for event objects.

func NewEventFactory

func NewEventFactory(includeReasons bool, timeFn func() ldtime.UnixMillisecondTime) EventFactory

NewEventFactory creates an EventFactory.

The includeReasons parameter is true if evaluation events should always include the EvaluationReason (this is used by the SDK when one of the "VariationDetail" methods is called). The timeFn parameter is normally nil but can be used to instrument the EventFactory with a source of time data other than the standard clock.

The isExperimentFn parameter is necessary to provide the additional experimentation behavior that is

func (EventFactory) NewCustomEvent

func (f EventFactory) NewCustomEvent(
	key string,
	user EventUser,
	data ldvalue.Value,
	withMetric bool,
	metricValue float64,
) CustomEvent

NewCustomEvent creates a new custom event.

func (EventFactory) NewEvalEvent

func (f EventFactory) NewEvalEvent(
	flagProps FlagEventProperties,
	user EventUser,
	detail ldreason.EvaluationDetail,
	defaultVal ldvalue.Value,
	prereqOf string,
) FeatureRequestEvent

NewEvalEvent creates an evaluation event for an existing flag.

func (EventFactory) NewIdentifyEvent

func (f EventFactory) NewIdentifyEvent(user EventUser) IdentifyEvent

NewIdentifyEvent constructs a new identify event, but does not send it. Typically, Identify should be used to both create the event and send it to LaunchDarkly.

func (EventFactory) NewUnknownFlagEvent

func (f EventFactory) NewUnknownFlagEvent(
	key string,
	user EventUser,
	defaultVal ldvalue.Value,
	reason ldreason.EvaluationReason,
) FeatureRequestEvent

NewUnknownFlagEvent creates an evaluation event for a missing flag.

type EventProcessor

type EventProcessor interface {
	// RecordFeatureRequestEvent records a FeatureRequestEvent asynchronously. Depending on the feature
	// flag properties and event properties, this may be transmitted to the events service as an
	// individual event, or may only be added into summary data.
	RecordFeatureRequestEvent(FeatureRequestEvent)

	// RecordIdentifyEvent records an IdentifyEvent asynchronously.
	RecordIdentifyEvent(IdentifyEvent)

	// RecordCustomEvent records a CustomEvent asynchronously.
	RecordCustomEvent(CustomEvent)

	// Flush specifies that any buffered events should be sent as soon as possible, rather than waiting
	// for the next flush interval. This method is asynchronous, so events still may not be sent
	// until a later time.
	Flush()

	// Close shuts down all event processor activity, after first ensuring that all events have been
	// delivered. Subsequent calls to SendEvent() or Flush() will be ignored.
	Close() error
}

EventProcessor defines the interface for dispatching analytics events.

func NewDefaultEventProcessor

func NewDefaultEventProcessor(config EventsConfiguration) EventProcessor

NewDefaultEventProcessor creates an instance of the default implementation of analytics event processing.

func NewNullEventProcessor

func NewNullEventProcessor() EventProcessor

NewNullEventProcessor creates a no-op implementation of EventProcessor.

type EventSender

type EventSender interface {
	// SendEventData attempts to deliver an event data payload.
	SendEventData(kind EventDataKind, data []byte, eventCount int) EventSenderResult
}

EventSender defines the interface for delivering already-formatted analytics event data to the events service.

func NewDefaultEventSender

func NewDefaultEventSender(
	httpClient *http.Client,
	eventsURI string,
	diagnosticURI string,
	headers http.Header,
	loggers ldlog.Loggers,
) EventSender

NewDefaultEventSender creates the default implementation of EventSender.

func NewServerSideEventSender

func NewServerSideEventSender(
	httpClient *http.Client,
	sdkKey string,
	eventsURI string,
	headers http.Header,
	loggers ldlog.Loggers,
) EventSender

NewServerSideEventSender creates the standard implementation of EventSender for server-side SDKs.

This is a convenience function for calling NewDefaultEventSender with the standard event endpoint URIs and the Authorization header.

type EventSenderResult

type EventSenderResult struct {
	// Success is true if the event payload was delivered.
	Success bool
	// MustShutDown is true if the server returned an error indicating that no further event data should be sent.
	// This normally means that the SDK key is invalid.
	MustShutDown bool
	// TimeFromServer is the last known date/time reported by the server, if available, otherwise zero.
	TimeFromServer ldtime.UnixMillisecondTime
}

EventSenderResult is the return type for EventSender.SendEventData.

type EventUser

type EventUser struct {
	lduser.User
	// AlreadyFilteredAttributes is a list of private attribute names that were already removed
	// from the user before generating the event. If this is non-nil, the usual attribute
	// filtering logic will be skipped and this list will be passed on unchanged in the
	// privateAttrs property of the output user.
	AlreadyFilteredAttributes []string
}

EventUser is a combination of the standard User struct with additional information that may be relevant outside of the standard SDK event generation context.

Specifically, the AlreadyFilteredAttributes property is used by ld-relay when it has received event data from the PHP SDK that has not gone through the summarization process, but *has* gone through private attribute filtering. Since that filtering normally only happens as part of event production and is not actually a property of the user, the lduser builder does not have a way to embed that information in the user so it is added here separately.

func User

func User(baseUser lduser.User) EventUser

User is a convenience function to convert lduser.User to EventUser.

type EventsConfiguration

type EventsConfiguration struct {
	// Sets whether or not all user attributes (other than the key) should be hidden from LaunchDarkly. If this
	// is true, all user attribute values will be private, not just the attributes specified in PrivateAttributeNames.
	AllAttributesPrivate bool
	// The capacity of the events buffer. The client buffers up to this many events in memory before flushing.
	// If the capacity is exceeded before the buffer is flushed, events will be discarded.
	Capacity int
	// The interval at which periodic diagnostic events will be sent, if DiagnosticsManager is non-nil.
	DiagnosticRecordingInterval time.Duration
	// An object that computes and formats diagnostic event data. This is only used within the SDK; for all other usage
	// of the ldevents package, it should be nil.
	DiagnosticsManager *DiagnosticsManager
	// The implementation of event delivery to use.
	EventSender EventSender
	// The time between flushes of the event buffer. Decreasing the flush interval means that the event buffer
	// is less likely to reach capacity.
	FlushInterval time.Duration
	// Set to true if you need to see the full user details in every analytics event.
	InlineUsersInEvents bool
	// The destination for log output.
	Loggers ldlog.Loggers
	// True if user keys can be included in log messages.
	LogUserKeyInErrors bool
	// Marks a set of user attribute names private. Any users sent to LaunchDarkly with this configuration
	// active will have attributes with these names removed.
	PrivateAttributeNames []lduser.UserAttribute
	// The number of user keys that the event processor can remember at any one time, so that
	// duplicate user details will not be sent in analytics events.
	UserKeysCapacity int
	// The interval at which the event processor will reset its set of known user keys.
	UserKeysFlushInterval time.Duration
	// contains filtered or unexported fields
}

EventsConfiguration contains options affecting the behavior of the events engine.

type FeatureRequestEvent

type FeatureRequestEvent struct {
	BaseEvent
	Key                  string
	Variation            ldvalue.OptionalInt
	Value                ldvalue.Value
	Default              ldvalue.Value
	Version              ldvalue.OptionalInt
	PrereqOf             ldvalue.OptionalString
	Reason               ldreason.EvaluationReason
	TrackEvents          bool
	Debug                bool
	DebugEventsUntilDate ldtime.UnixMillisecondTime
}

FeatureRequestEvent is generated by evaluating a feature flag or one of a flag's prerequisites.

func (FeatureRequestEvent) GetBase

func (evt FeatureRequestEvent) GetBase() BaseEvent

GetBase returns the BaseEvent

type FlagEventProperties

type FlagEventProperties interface {
	// GetKey returns the feature flag key.
	GetKey() string
	// GetVersion returns the feature flag version.
	GetVersion() int
	// IsFullEventTrackingEnabled returns true if the flag has been configured to always generate detailed event data.
	IsFullEventTrackingEnabled() bool
	// GetDebugEventsUntilDate returns zero normally, but if event debugging has been temporarily enabled for the flag,
	// it returns the time at which debugging mode should expire.
	GetDebugEventsUntilDate() ldtime.UnixMillisecondTime
	// IsExperimentationEnabled returns true if, based on the EvaluationReason returned by the flag evaluation,
	// an event for that evaluation should have full tracking enabled and always report the reason even if the
	// application didn't explicitly request this. For instance, this is true if a rule was matched that had
	// tracking enabled for that specific rule.
	//
	// This differs from IsFullEventTrackingEnabled() in that it is dependent on the result of a specific
	// evaluation; also, IsFullEventTrackingEnabled() being true does not imply that the event should always
	// contain a reason, whereas IsExperimentationEnabled() being true does force the reason to be included.
	IsExperimentationEnabled(reason ldreason.EvaluationReason) bool
}

FlagEventProperties is an interface that provides the basic information about a feature flag that the events package needs, without having a specific dependency on the server-side data model. An implementation of this interface for server-side feature flags is provided in go-server-sdk-evaluation; if we ever create a client-side Go SDK, that will have its own implementation.

type IdentifyEvent

type IdentifyEvent struct {
	BaseEvent
}

IdentifyEvent is generated by calling the client's Identify method.

func (IdentifyEvent) GetBase

func (evt IdentifyEvent) GetBase() BaseEvent

GetBase returns the BaseEvent