ldevents

package module
v2.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2023 License: Apache-2.0 Imports: 19 Imported by: 3

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.

Supported Go versions

This version of the project requires a Go version of 1.18 or higher.

Learn more

Read 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. Read our documentation for a complete list.
  • Explore LaunchDarkly

Documentation

Overview

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

Index

Constants

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

Event types

View Source
const DefaultDiagnosticRecordingInterval = 15 * time.Minute

DefaultDiagnosticRecordingInterval is the default value for EventsConfiguration.DiagnosticRecordingInterval.

View Source
const DefaultFlushInterval = 5 * time.Second

DefaultFlushInterval is the default value for EventsConfiguration.FlushInterval.

View Source
const DefaultUserKeysFlushInterval = 5 * time.Minute

DefaultUserKeysFlushInterval is the default value for EventsConfiguration.UserKeysFlushInterval.

View Source
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
	Context      EventInputContext
}

BaseEvent provides properties common to all events.

type CustomEventData

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

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

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 EvaluationData

type EvaluationData struct {
	BaseEvent
	// Key is the flag key.
	Key string
	// Variation is the result variation index. It is empty if evaluation failed.
	Variation ldvalue.OptionalInt
	// Value is the result value.
	Value ldvalue.Value
	// Default is the default value that was passed in by the application.
	Default ldvalue.Value
	// Version is the flag version. It is empty if the flag was not found.
	Version ldvalue.OptionalInt
	// PrereqOf is normally empty, but if this evaluation was done for a prerequisite, it is the key of the
	// original key that referenced this flag as a prerequisite.
	PrereqOf ldvalue.OptionalString
	// Reason is the evaluation reason, if the reason should be included in the event, or empty otherwise.
	Reason ldreason.EvaluationReason
	// RequireFullEvent is true if an individual evaluation event should be included in the output event data,
	// or false if this evaluation should only produce summary data (and potentially an index event).
	RequireFullEvent bool
	// DebugEventsUntilDate is non-zero if event debugging has been temporarily enabled for the flag. It is the
	// time at which debugging mode should expire.
	DebugEventsUntilDate ldtime.UnixMillisecondTime
	// contains filtered or unexported fields
}

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

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) NewCustomEventData

func (f EventFactory) NewCustomEventData(
	key string,
	context EventInputContext,
	data ldvalue.Value,
	withMetric bool,
	metricValue float64,
) CustomEventData

NewCustomEventData creates input parameters for a custom event. No event is actually generated until you call EventProcessor.RecordCustomEvent.

func (EventFactory) NewEvaluationData

func (f EventFactory) NewEvaluationData(
	flagProps FlagEventProperties,
	context EventInputContext,
	detail ldreason.EvaluationDetail,
	isExperiment bool,
	defaultVal ldvalue.Value,
	prereqOf string,
) EvaluationData

NewEvaluationData creates EvaluationData for an existing flag.

The isExperiment parameter, if true, means that a full evaluation event should be generated (regardless of whether flagProps.RequireFullEvent is true) and the evaluation reason should be included in the event (even if it normally would not have been). In the server-side SDK, that is determined by the IsExperiment field returned by the evaluator.

func (EventFactory) NewIdentifyEventData

func (f EventFactory) NewIdentifyEventData(context EventInputContext) IdentifyEventData

NewIdentifyEventData constructs input parameters for an identify event. No event is actually generated until you call EventProcessor.RecordIdentifyEvent.

func (EventFactory) NewUnknownFlagEvaluationData

func (f EventFactory) NewUnknownFlagEvaluationData(
	key string,
	context EventInputContext,
	defaultVal ldvalue.Value,
	reason ldreason.EvaluationReason,
) EvaluationData

NewUnknownFlagEvaluationData creates EvaluationData for a missing flag.

type EventInputContext

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

EventInputContext represents context information that is being used as part of the inputs to an event-generating action. It is a combination of the standard Context struct with additional information that may be relevant outside of the standard SDK event generation context.

Specifically, this is because ld-relay uses go-sdk-events to post-process events it has received from the PHP SDK. In this scenario the PHP SDK will have already applied the private-attribute-redaction logic, so there is no need to do any further transformation of the context.

That requirement is specific to ld-relay. In regular usage of the Go SDK, we always just use the plain Context constructor.

func Context

func Context(context ldcontext.Context) EventInputContext

Context creates an EventInputContext that is exactly equivalent to the given Context.

func PreserializedContext

func PreserializedContext(context ldcontext.Context, jsonData json.RawMessage) EventInputContext

PreserializedContext creates an EventInputContext that contains both a Context and its already-computed JSON representation. This representation will be written directly to the output with no further processing. The properties of the wrapped Context are not important except for its Kind, Key, and FullyQualifiedKey, which are used for context deduplication.

type EventProcessor

type EventProcessor interface {
	// RecordEvaluation records evaluation information 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.
	RecordEvaluation(EvaluationData)

	// RecordIdentifyEvent records an identify event asynchronously.
	RecordIdentifyEvent(IdentifyEventData)

	// RecordCustomEvent records a custom event asynchronously.
	RecordCustomEvent(CustomEventData)

	// RecordRawEvent adds an event to the output buffer that is not parsed or transformed in any way.
	// This is used by the Relay Proxy when forwarding events.
	RecordRawEvent(data json.RawMessage)

	// 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()

	// FlushBlocking attempts to flush any buffered events, blocking until either they have been
	// successfully delivered or delivery has failed. If there were no buffered events, it returns true
	// immediately. The timeout parameter, if non-zero, specifies the maximum amount of time to wait
	// before the method will return; a timeout does not stop the event processor from continuing to
	// try to deliver the events in the background, if applicable. The method returns true on completion
	// or false if timed out.
	FlushBlocking(timeout time.Duration) bool

	// 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 NewServerSideEventSender

func NewServerSideEventSender(
	config EventSenderConfiguration,
	sdkKey string,
) EventSender

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

The underlying behavior is mostly provided by SendEventData. It adds the behavior of putting the SDK key in an Authorization header (in addition to any other headers in config.BaseHeaders), and it forces the schema version to be the latest schema version (since, in the regular use case of EventSender being used within a DefaultEventProcessor, the latter is only ever going to generate output in the current schema).

This object maintains no state other than its configuration, so discarding it does not require any special cleanup.

type EventSenderConfiguration

type EventSenderConfiguration struct {
	// Client is the HTTP client instance to use, or nil to use http.DefaultClient.
	Client *http.Client
	// BaseURI is the base URI to which the event endpoint paths will be added.
	BaseURI string
	// BaseHeaders contains any headers that should be added to the HTTP request, other than the schema version.
	// The event delivery logic will never modify this map; it will clone it if necessary.
	BaseHeaders func() http.Header
	// SchemaVersion specifies the value for the X-LaunchDarkly-Event-Schema header, or 0 to use the latest version.
	SchemaVersion int
	// Loggers is used for logging event delivery status.
	Loggers ldlog.Loggers
	// RetryDelay is the length of time to wait for a retry, or 0 to use the default delay (1 second).
	RetryDelay time.Duration
}

EventSenderConfiguration contains parameters for event delivery that do not vary from one event payload to another.

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.

func SendEventDataWithRetry

func SendEventDataWithRetry(
	config EventSenderConfiguration,
	kind EventDataKind,
	overridePath string,
	data []byte,
	eventCount int,
) EventSenderResult

SendEventDataWithRetry provides an entry point to the same event delivery logic that is used by DefaultEventSender. This is exported separately for convenience in code such as the Relay Proxy which needs to implement the same behavior in situations where EventProcessor and EventSender are not relevant. The behavior provided is specifically:

1. Add headers as follows, besides config.BaseHeaders: Content-Type (application/json); X-LaunchDarkly-Schema-Version (based on config.Schema Version; omitted for diagnostic events); and X-LaunchDarkly-Payload-ID (a UUID value). Unlike NewServerSideEventSender, it does not add an Authorization header.

2. If delivery fails with a recoverable error, such as an HTTP 503 or an I/O error, retry exactly once after a delay configured by config.RetryDelay. This is done synchronously. If the retry fails, return Success: false.

3. If delivery fails with an unrecoverable error, such as an HTTP 401, return Success: false and MustShutDown: true.

4. If the response has a Date header, parse it into TimeFromServer.

The overridePath parameter only needs to be set if you need to customize the URI path. If it is empty, the standard path of /bulk or /diagnostic will be used as appropriate.

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
	// The destination for log output.
	Loggers ldlog.Loggers
	// True if user keys can be included in log messages.
	LogUserKeyInErrors bool
	// PrivateAttributes is a list of attribute references (either simple names, or slash-delimited
	// paths) that should be considered private.
	PrivateAttributes []ldattr.Ref
	// 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 FlagEventProperties

type FlagEventProperties struct {
	// Key is the feature flag key.
	Key string
	// Version is the feature flag version.
	Version int
	// RequireFullEvent is true if the flag has been configured to always generate detailed event data.
	RequireFullEvent bool
	// DebugEventsUntilDate is non-zero if event debugging has been temporarily enabled for the flag. It is the
	// time at which debugging mode should expire.
	DebugEventsUntilDate ldtime.UnixMillisecondTime
}

FlagEventProperties contains basic information about a feature flag that the events package needs. This allows go-sdk-events to be implemented independently of go-server-side-evaluation where the flag model is defined. It also allows us to use go-sdk-events in a client-side Go SDK, where the flag model will be different, if we ever implement a client-side Go SDK.

type IdentifyEventData

type IdentifyEventData struct {
	BaseEvent
}

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL