ldcontext

package
v3.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2023 License: Apache-2.0 Imports: 10 Imported by: 32

Documentation

Overview

Package ldcontext defines the LaunchDarkly SDK model for contexts and context attributes.

See Context, Builder, and MultiBuilder.

To learn more, read: https://docs.launchdarkly.com/home/contexts

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

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

Builder is a mutable object that uses the builder pattern to specify properties for a Context.

Use this type if you need to construct a Context that has only a single Context.Kind. To define a multi-context, use MultiBuilder instead.

Obtain an instance of Builder by calling NewBuilder. Then, call setter methods such as Builder.Kind or Builder.Name to specify any additional attributes; all of the Builder setters return a reference to the same builder, so they can be chained together. Then, call Builder.Build to produce the immutable Context.

context := ldcontext.NewBuilder("user-key").
	Name("my-name").
	SetString("country", "us").
	Build()

A Builder should not be accessed by multiple goroutines at once. Once you have called Builder.Build, the resulting Context is immutable and is safe to use from multiple goroutines.

Context attributes

There are several built-in attribute names with special meaning in LaunchDarkly, and restrictions on the type of their value. These have their own builder methods: see Builder.Key, Builder.Kind, Builder.Name, and Builder.Anonymous.

You may also set any number of other attributes with whatever names are useful for your application (subject to validation constraints; see Builder.SetValue for rules regarding attribute names). These attributes can have any data type that is supported in JSON: boolean, number, string, array, or object.

Setting attributes with simple value types

For convenience, there are setter methods for simple types:

context := ldcontext.NewBuilder("user-key").
	SetBool("a", true).    // this attribute has a boolean value
	SetString("b", "xyz"). // this attribute has a string value
	SetInt("c", 3).        // this attribute has an integer numeric value
	SetFloat64("d", 4.5).  // this attribute has a floating-point numeric value
	Build()

Setting attributes with complex value types

JSON arrays and objects are represented by the ldvalue.Value type. The Builder.SetValue method takes a value of this type.

The ldvalue package provides several ways to construct such values. Here are some examples; for more information, see ldvalue.Value.

context := ldcontext.NewBuilder("user-key").
	SetValue("arrayAttr1",
		ldvalue.ArrayOf(ldvalue.String("a"), ldvalue.String("b"))).
	SetValue("arrayAttr2",
		ldvalue.CopyArbitraryValue([]string{"a", "b"})).
	SetValue("objectAttr1",
		ldvalue.ObjectBuild().SetString("color", "green").Build()).
	SetValue("objectAttr2",
		ldvalue.FromJSONMarshal(MyStructType{Color: "green"})).
	Build()

Arrays and objects have special meanings in LaunchDarkly flag evaluation:

  • An array of values means "try to match any of these values to the targeting rule."
  • An object allows you to match a property within the object to the targeting rule. For instance, in the example above, a targeting rule could reference /objectAttr1/color to match the value "green". Nested property references like /objectAttr1/address/street are allowed if a property contains another JSON object.

Private attributes

You may designate certain attributes, or values within them, as "private", meaning that their values are not included in analytics data sent to LaunchDarkly. See Builder.Private.

context := ldcontext.NewBuilder("user-key").
	SetString("email", "test@example.com").
	Private("email").
	Build()

func NewBuilder

func NewBuilder(key string) *Builder

NewBuilder creates a Builder for building a Context, initializing its Key property and setting Kind to DefaultKind.

You may use Builder methods to set additional attributes and/or change the Builder.Kind before calling Builder.Build. If you do not change any values, the defaults for the Context are that its Builder.Kind is DefaultKind ("user"), its Builder.Key is set to whatever value you passed to NewBuilder, its Builder.Anonymous attribute is false, and it has no values for any other attributes.

This method is for building a Context that has only a single Kind. To define a multi-Context, use NewMultiBuilder instead.

If the key parameter is an empty string, there is no default. A Context must have a non-empty key, so if you call Builder.Build in this state without using Builder.Key to set the key, you will get an invalid Context.

An empty Builder{} is valid as long as you call Builder.Key to set a non-empty key. This means that in in performance-critical code paths where you want to minimize heap allocations, if you do not want to allocate a Builder on the heap with NewBuilder, you can declare one locally instead:

var b ldcontext.Builder
c := b.Kind("org").Key("my-key").Name("my-name").Build()

func NewBuilderFromContext

func NewBuilderFromContext(fromContext Context) *Builder

NewBuilderFromContext creates a Builder whose properties are the same as an existing single context.

You may then change the Builder's state in any way and call Builder.Build to create a new independent Context.

If fromContext is a multi-context created with NewMulti or MultiBuilder, this method is not applicable and returns an uninitialized Builder.

func (*Builder) Anonymous

func (b *Builder) Anonymous(value bool) *Builder

Anonymous sets whether the Context is only intended for flag evaluations and should not be indexed by LaunchDarkly.

The default value is false. False means that this Context represents an entity such as a user that you want to be able to see on the LaunchDarkly dashboard.

Setting Anonymous to true excludes this Context from the database that is used by the dashboard. It does not exclude it from analytics event data, so it is not the same as making attributes private; all non-private attributes will still be included in events and data export. There is no limitation on what other attributes may be included (so, for instance, Anonymous does not mean there is no Builder.Name).

This value is also addressable in evaluations as the attribute name "anonymous". It is always treated as a boolean true or false in evaluations; it cannot be null/undefined.

func (*Builder) Build

func (b *Builder) Build() Context

Build creates a Context from the current Builder properties.

The Context is immutable and will not be affected by any subsequent actions on the Builder.

It is possible to specify invalid attributes for a Builder, such as an empty Builder.Key. Instead of returning two values (Context, error), the Builder always returns a Context and you can call Context.Err to see if it has an error. Using a single-return-value syntax is more convenient for application code, since in normal usage an application will never build an invalid Context. If you pass an invalid Context to an SDK method, the SDK will detect this and will generally log a description of the error.

You may call Builder.TryBuild instead of Build if you prefer to use two-value return semantics, but the validation behavior is the same for both.

func (*Builder) Key

func (b *Builder) Key(key string) *Builder

Key sets the Context's key attribute.

Every Context has a key, which is always a string. There are no restrictions on its value except that it cannot be empty.

The key attribute can be referenced by flag rules, flag target lists, and segments.

If the key is empty at the time Builder.Build is called, you will receive an invalid Context whose Context.Err value will describe the problem.

func (*Builder) Kind

func (b *Builder) Kind(kind Kind) *Builder

Kind sets the Context's kind attribute.

Every Context has a kind. Setting it to an empty string is equivalent to the default kind of "user". This value is case-sensitive. Validation rules are as follows:

  • It may only contain letters, numbers, and the characters ".", "_", and "-".
  • It cannot equal the literal string "kind".
  • It cannot equal the literal string "multi" (MultiKind).

If the value is invalid at the time Builder.Build is called, you will receive an invalid Context whose Context.Err value will describe the problem.

func (*Builder) Name

func (b *Builder) Name(name string) *Builder

Name sets the Context's name attribute.

This attribute is optional. It has the following special rules:

  • Unlike most other attributes, it is always a string if it is specified.
  • The LaunchDarkly dashboard treats this attribute as the preferred display name for contexts.

func (*Builder) OptName

func (b *Builder) OptName(name ldvalue.OptionalString) *Builder

OptName sets or clears the Context's name attribute.

Calling b.OptName(ldvalue.NewOptionalString("x")) is equivalent to b.Name("x"), but since it uses the OptionalString type, it also allows clearing a previously set name with b.OptName(ldvalue.OptionalString{}).

func (*Builder) Private

func (b *Builder) Private(attrRefStrings ...string) *Builder

Private designates any number of Context attributes, or properties within them, as private: that is, their values will not be sent to LaunchDarkly in analytics data.

This action only affects analytics events that involve this particular Context. To mark some (or all) Context attributes as private for all context, use the overall event configuration for the SDK.

In this example, firstName is marked as private, but lastName is not:

c := ldcontext.NewBuilder("org", "my-key").
	SetString("firstName", "Pierre").
	SetString("lastName", "Menard").
	Private("firstName").
	Build()

The attributes "kind", "key", and "anonymous" cannot be made private.

This is a metadata property, rather than an attribute that can be addressed in evaluations: that is, a rule clause that references the attribute name "private" will not use this value, but instead will use whatever value (if any) you have set for that name with a method such as Builder.SetString.

Designating an entire attribute as private

If the parameter is an attribute name such as "email" that does not start with a '/' character, the entire attribute is private.

Designating a property within a JSON object as private

If the parameter starts with a '/' character, it is interpreted as a slash-delimited path to a property within a JSON object. The first path component is an attribute name, and each following component is a property name.

For instance, suppose that the attribute "address" had the following JSON object value: {"street": {"line1": "abc", "line2": "def"}, "city": "ghi"}

  • Calling either Private("address") or Private("/address") would cause the entire "address" attribute to be private.
  • Calling Private("/address/street") would cause the "street" property to be private, so that only {"city": "ghi"} is included in analytics.
  • Calling Private("/address/street/line2") would cause only "line2" within "street" to be private, so that {"street": {"line1": "abc"}, "city": "ghi"} is included in analytics.

This syntax deliberately resembles JSON Pointer, but other JSON Pointer features such as array indexing are not supported for Private.

If an attribute's actual name starts with a '/' character, you must use the same escaping syntax as JSON Pointer: replace "~" with "~0", and "/" with "~1".

func (*Builder) PrivateRef

func (b *Builder) PrivateRef(attrRefs ...ldattr.Ref) *Builder

PrivateRef is equivalent to Private, but uses the ldattr.Ref type. It designates any number of Context attributes, or properties within them, as private: that is, their values will not be sent to LaunchDarkly.

Application code is unlikely to need to use the ldattr.Ref type directly; however, in cases where you are constructing Contexts constructed repeatedly with the same set of private attributes, if you are also using complex private attribute path references such as "/address/street", converting this to an ldattr.Ref once and reusing it in many PrivateRef calls is slightly more efficient than calling Builder.Private (since it does not need to parse the path repeatedly).

func (*Builder) RemovePrivate

func (b *Builder) RemovePrivate(attrRefStrings ...string) *Builder

RemovePrivate removes any private attribute references previously added with Builder.Private or Builder.PrivateRef that exactly match any of the specified attribute references.

func (*Builder) RemovePrivateRef

func (b *Builder) RemovePrivateRef(attrRefs ...ldattr.Ref) *Builder

RemovePrivateRef removes any private attribute references previously added with Builder.Private or Builder.PrivateRef that exactly match that of any of the specified attribute references.

Application code is unlikely to need to use the ldattr.Ref type directly, and can use RemovePrivate with a string parameter to accomplish the same thing. This method is mainly for use by internal LaunchDarkly SDK and service code which uses ldattr.Ref.

func (*Builder) SetBool

func (b *Builder) SetBool(attributeName string, value bool) *Builder

SetBool sets an attribute to a boolean value.

For rules regarding attribute names and values, see Builder.SetValue. This method is exactly equivalent to calling b.SetValue(attributeName, ldvalue.Bool(value)).

func (*Builder) SetFloat64

func (b *Builder) SetFloat64(attributeName string, value float64) *Builder

SetFloat64 sets an attribute to a float64 numeric value.

For rules regarding attribute names and values, see Builder.SetValue. This method is exactly equivalent to calling b.SetValue(attributeName, ldvalue.Float64(value)).

Note: the LaunchDarkly model for feature flags and user attributes is based on JSON types, and JSON does not distinguish between integer and floating-point types. Therefore, b.SetFloat64(name, float64(1.0)) is exactly equivalent to b.SetInt(name, 1).

func (*Builder) SetInt

func (b *Builder) SetInt(attributeName string, value int) *Builder

SetInt sets an attribute to an int numeric value.

For rules regarding attribute names and values, see Builder.SetValue. This method is exactly equivalent to calling b.SetValue(attributeName, ldvalue.Int(value)).

Note: the LaunchDarkly model for feature flags and user attributes is based on JSON types, and JSON does not distinguish between integer and floating-point types. Therefore, b.SetFloat64(name, float64(1.0)) is exactly equivalent to b.SetInt(name, 1).

func (*Builder) SetString

func (b *Builder) SetString(attributeName string, value string) *Builder

SetString sets an attribute to a string value.

For rules regarding attribute names and values, see Builder.SetValue. This method is exactly equivalent to calling b.SetValue(attributeName, ldvalue.String(value)).

func (*Builder) SetValue

func (b *Builder) SetValue(attributeName string, value ldvalue.Value) *Builder

SetValue sets the value of any attribute for the Context.

This method uses the ldvalue.Value type to represent a value of any JSON type: boolean, number, string, array, or object. The ldvalue package provides several ways to construct values of each type.

The return value is always the same Builder, for convenience (to allow method chaining).

Allowable attribute names

The attribute names "kind", "key", "name", and "anonymous" have special meaning in LaunchDarkly. You may use these names with SetValue, as an alternative to using the methods Builder.Kind, Builder.Key, Builder.Name, and Builder.Anonymous. However, there are restrictions on the value type: "kind" and "key" must be a string, "name" must be a string or null, and "anonymous" must be a boolean. Any value of an unsupported type is ignored (leaving the attribute unchanged).

The string "_meta" cannot be used as an attribute name.

All other non-empty strings are valid as an attribute name, and have no special meaning in LaunchDarkly; their definition is up to you.

Context metadata such as Builder.Private, which is not addressable in evaluations, is not considered an attribute; if you define an attribute of your own with the name "private", it is simply an attribute like any other, unrelated to the context metadata.

Simple value types

Passing a simple value constructed with ldvalue.Bool, ldvalue.Int, ldvalue.Float64, or ldvalue.String, is exactly equivalent to calling one of the typed setter methods Builder.SetBool, Builder.SetInt, Builder.SetFloat64, or Builder.SetString.

Values of different JSON types are always treated as different values. For instance, the number 1 is not the same as the string "1".

The null value, ldvalue.Null(), is a special case: it is a valid value in JSON, but LaunchDarkly considers null to be the same as "no such attribute", so setting an attribute's value to null is the same as removing it.

Complex value types

The ldvalue package provides several ways to construct JSON array or object values. Here are some examples; for more information, see ldvalue.Value.

context := ldcontext.NewBuilder("user-key").
	SetValue("arrayAttr1",
		ldvalue.ArrayOf(ldvalue.String("a"), ldvalue.String("b"))).
	SetValue("arrayAttr2",
		ldvalue.CopyArbitraryValue([]string{"a", "b"})).
	SetValue("objectAttr1",
		ldvalue.ObjectBuild().SetString("color", "green").Build()).
	SetValue("objectAttr2",
		ldvalue.FromJSONMarshal(MyStructType{Color: "green"})).
	Build()

Arrays and objects have special meanings in LaunchDarkly flag evaluation:

  • An array of values means "try to match any of these values to the targeting rule."
  • An object allows you to match a property within the object to the targeting rule. For instance, in the example above, a targeting rule could reference /objectAttr1/color to match the value "green". Nested property references like /objectAttr1/address/street are allowed if a property contains another JSON object.

func (*Builder) TryBuild

func (b *Builder) TryBuild() (Context, error)

TryBuild is an alternative to Build that returns any validation errors as a second value.

As described in Builder.Build, there are several ways the state of a Context could be invalid. Since in normal usage it is possible to be confident that these will not occur, the Build method is designed for convenient use within expressions by returning a single Context value, and any validation problems are contained within that value where they can be detected by calling Context.Err. But, if you prefer to use the two-value pattern that is common in Go, you can call TryBuild instead:

c, err := ldcontext.NewBuilder("my-key").
	Name("my-name").
	TryBuild()
if err != nil {
	// do whatever is appropriate if building the context failed
}

The two return values are the same as to 1. the Context that would be returned by Build(), and 2. the result of calling Err() on that Context. So, the above example is exactly equivalent to:

c := ldcontext.NewBuilder("my-key").
	Name("my-name").
	Build()
if c.Err() != nil {
	// do whatever is appropriate if building the context failed
}

Note that unlike some Go methods where the first return value is normally an uninitialized zero value if the error is non-nil, the Context returned by TryBuild in case of an error is not completely uninitialized: it does contain the error information as well, so that if it is mistakenly passed to an SDK method, the SDK can tell what the error was.

func (*Builder) TrySetValue

func (b *Builder) TrySetValue(attributeName string, value ldvalue.Value) bool

TrySetValue sets the value of any attribute for the Context.

This is the same as Builder.SetValue, except that it returns true for success, or false if the parameters violated one of the restrictions described for SetValue (for instance, attempting to set "key" to a value that was not a string).

type Context

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

Context is a collection of attributes that can be referenced in flag evaluations and analytics events.

To create a Context of a single kind, such as a user, you may use the New or NewWithKind constructors. Or, to specify other attributes, use NewBuilder. See the Builder type for more information about how to set attributes.

To create a multi-context, use NewMultiBuilder.

An uninitialized Context struct is not valid for use in any SDK operations. Also, a Context can be in an error state if it was built with invalid attributes. See Context.Err.

To learn more, read: https://docs.launchdarkly.com/home/contexts

func New

func New(key string) Context

New creates a Context with a Kind of DefaultKind and the specified key.

To specify additional properties, use NewBuilder. To create a multi-context, use NewMulti or NewMultiBuilder. To create a single Context of a different kind than DefaultKind, use NewWithKind; New is simply a shortcut for calling NewWithKind(DefaultKind, key).

func NewMulti

func NewMulti(contexts ...Context) Context

NewMulti creates a multi-context out of the specified Contexts.

To create a single Context, use New, NewWithKind, or NewBuilder.

For the returned Context to be valid, the contexts list must not be empty, and all of its elements must be valid Contexts. Otherwise, the returned Context will be invalid as reported by Context.Err.

If only one context parameter is given, NewMulti returns that same context.

If one of the nested contexts is a multi-context, this is exactly equivalent to adding each of the individual contexts from it separately. For instance, in the following example, "multi1" and "multi2" end up being exactly the same:

c1 := ldcontext.NewWithKind("kind1", "key1")
c2 := ldcontext.NewWithKind("kind2", "key2")
c3 := ldcontext.NewWithKind("kind3", "key3")

multi1 := ldcontext.NewMulti(c1, c2, c3)

c1plus2 := ldcontext.NewMulti(c1, c2)
multi2 := ldcontext.NewMulti(c1plus2, c3)

func NewWithKind

func NewWithKind(kind Kind, key string) Context

NewWithKind creates a Context with only the Kind and Key properties specified.

To specify additional properties, use NewBuilder. To create a multi-context, use NewMulti or NewMultiBuilder. As a shortcut if the Kind is DefaultKind, you can use New.

func (Context) Anonymous

func (c Context) Anonymous() bool

Anonymous returns true if this Context is only intended for flag evaluations and will not be indexed by LaunchDarkly.

For a single context, this value can be set by Builder.Anonymous, and is false if not specified.

For a multi-context, there is no single value, so Anonymous() always returns false; use Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts to get the Context for a particular kind and then call Anonymous() on it.

func (Context) Equal

func (c Context) Equal(other Context) bool

Equal tests whether two contexts are logically equal.

Two single contexts are logically equal if they have the same attribute names and values. Two multi-contexts are logically equal if they contain the same kinds (in any order) and the individual contexts are equal. A single context is never equal to a multi-context.

func (Context) Err

func (c Context) Err() error

Err returns nil for a valid Context, or a non-nil error value for an invalid Context.

A valid Context is one that can be used in SDK operations. An invalid Context is one that is missing necessary attributes or has invalid attributes, indicating an incorrect usage of the SDK API. For a complete list of the ways a Context can be invalid, see the lderrors package.

Since in normal usage it is easy for applications to be sure they are using context kinds correctly (so that having to constantly check error return values would be needlessly inconvenient), and because some states such as the empty value are impossible to prevent in the Go language, the SDK stores the error state in the Context itself and checks for such errors at the time the Context is used, such as in a flag evaluation. At that point, if the Context is invalid, the operation will fail in some well-defined way as described in the documentation for that method, and the SDK will generally log a warning as well. But in any situation where you are not sure if you have a valid Context, you can call Err() to check.

func (Context) FullyQualifiedKey

func (c Context) FullyQualifiedKey() string

FullyQualifiedKey returns a string that describes the entire Context based on Kind and Key values.

This value is used whenever LaunchDarkly needs a string identifier based on all of the Kind and Key values in the context; the SDK may use this for caching previously seen contexts, for instance.

func (Context) GetAllIndividualContexts

func (c Context) GetAllIndividualContexts(sliceIn []Context) []Context

GetAllIndividualContexts converts this context to a slice of individual contexts. If the method is called on a single context, then the resulting slice has exactly one element, which is the same context. If the method is called on a multi-context, then the resulting slice contains each individual context within.

If a non-nil slice is passed in, it will be reused to hold the return values if it has enough capacity. For instance, in the following example, no heap allocations will happen unless there are more than 10 individual contexts; if there are more than 10, the slice will be allocated on the stack:

preallocContexts := make([]ldcontext.Context, 0, 10)
contexts := c.GetAllIndividualContexts(preallocContexts)

func (Context) GetOptionalAttributeNames

func (c Context) GetOptionalAttributeNames(sliceIn []string) []string

GetOptionalAttributeNames returns a slice containing the names of all regular optional attributes defined on this Context. These do not include the mandatory Kind and Key, or the metadata attributes Secondary, Anonymous, and Private.

If a non-nil slice is passed in, it will be reused to hold the return values if it has enough capacity. For instance, in the following example, no heap allocations will happen unless there are more than 10 optional attribute names; if there are more than 10, the slice will be allocated on the stack:

preallocNames := make([]string, 0, 10)
names := c.GetOptionalAttributeNames(preallocNames)

func (Context) GetValue

func (c Context) GetValue(attrName string) ldvalue.Value

GetValue looks up the value of any attribute of the Context by name.

This includes only attributes that are addressable in evaluations, not metadata such as Context.PrivateAttributeByIndex.

For a single context, the attribute name can be any custom attribute that was set by methods like Builder.SetString. It can also be one of the built-in ones like "kind", "key", or "name"; in such cases, it is equivalent to calling Context.Kind, Context.Key, or Context.Name, except that the value is returned using the general-purpose ldvalue.Value type.

For a multi-context, the only supported attribute name is "kind". Use Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts to get the Context for a particular kind and then get its attributes.

This method does not support complex expressions for getting individual values out of JSON objects or arrays, such as "/address/street". Use Context.GetValueForRef for that purpose.

If the value is found, the return value is the attribute value, using the type ldvalue.Value to represent a value of any JSON type.

If there is no such attribute, the return value is ldvalue.Null(). An attribute that actually exists cannot have a null value.

func (Context) GetValueForRef

func (c Context) GetValueForRef(ref ldattr.Ref) ldvalue.Value

GetValueForRef looks up the value of any attribute of the Context, or a value contained within an attribute, based on an ldattr.Ref.

This includes only attributes that are addressable in evaluations, not metadata such as Context.PrivateAttributeByIndex.

This implements the same behavior that the SDK uses to resolve attribute references during a flag evaluation. In a single context, the ldattr.Ref can represent a simple attribute name-- either a built-in one like "name" or "key", or a custom attribute that was set by methods like Builder.SetString-- or, it can be a slash-delimited path using a JSON-Pointer-like syntax. See ldattr.Ref for more details.

For a multi-context, the only supported attribute name is "kind". Use Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts to get the Context for a particular kind and then get its attributes.

If the value is found, the return value is the attribute value, using the type ldvalue.Value to represent a value of any JSON type).

If there is no such attribute, or if the ldattr.Ref is invalid, the return value is ldvalue.Null(). An attribute that actually exists cannot have a null value.

func (Context) IndividualContextByIndex

func (c Context) IndividualContextByIndex(index int) Context

IndividualContextByIndex returns the single context corresponding to one of the Kinds in this context. If the method is called on a single context, then the only allowable value for index is zero, and the return value on success is the same context. If the method is called on a multi-context, then index must be >= zero and < the number of kinds, and the return value on success is one of the individual contexts within.

If the index is out of range, then the return value is an uninitialized Context{}. You can detect this condition because Context.IsDefined will return false.

In a multi-context, the ordering of the individual contexts is not guaranteed to be the same order that was passed into the builder or constructor.

func (Context) IndividualContextByKind

func (c Context) IndividualContextByKind(kind Kind) Context

IndividualContextByKind returns the single context, if any, whose Kind matches the specified value exactly. If the method is called on a single context, then the specified Kind must match the kind of that context. If the method is called on a multi-context, then the Kind can match any of the individual contexts within.

If the kind parameter is an empty string, DefaultKind is used instead.

If no matching Kind is found, then the return value is an uninitialized Context{}. You can detect this condition because Context.IsDefined will return false.

func (Context) IndividualContextCount

func (c Context) IndividualContextCount() int

IndividualContextCount returns the number of Kinds in the context.

For a single context, the return value is always 1. For a multi-context, it is the number of individual contexts within. For an invalid context, it is zero.

func (Context) IndividualContextKeyByKind

func (c Context) IndividualContextKeyByKind(kind Kind) string

IndividualContextKeyByKind returns the Key of the single context, if any, whose Kind matches the specified value exactly. If the method is called on a single context, then the specified Kind must match the Kind of that context. If the method is called on a multi-context, then the Kind can match any of the individual contexts within.

If the kind parameter is an empty string, DefaultKind is used instead.

If no matching Kind is found, the return value is an empty string.

This method is equivalent to calling Context.IndividualContextByKind and then Key, but is slightly more efficient (since it does not require copying an entire Context struct by value).

func (Context) IsDefined

func (c Context) IsDefined() bool

IsDefined returns true if this is a Context that was created with a constructor or builder (regardless of whether its properties are valid), or false if it is an empty uninitialized Context{}.

func (Context) JSONString

func (c Context) JSONString() string

JSONString returns the JSON representation of the Context.

This is equivalent to calling Context.MarshalJSON and converting the result to a string. An invalid Context cannot be represented in JSON and produces an empty string.

func (Context) Key

func (c Context) Key() string

Key returns the Context's key attribute.

For a single context, this value is set by the Context constructors or the Builder methods.

For a multi-context, there is no single value, so Key() returns an empty name; use Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts to get the Context for a particular kind and then call Key() on it.

func (Context) Kind

func (c Context) Kind() Kind

Kind returns the Context's kind attribute.

Every valid Context has a non-empty kind. For multi-contexts, this value is MultiKind and the kinds within the Context can be inspected with Context.IndividualContextCount, Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts.

For rules regarding the kind value, see Builder.Kind.

func (Context) MarshalJSON

func (c Context) MarshalJSON() ([]byte, error)

MarshalJSON provides JSON serialization for Context when using encoding/json.MarshalJSON.

LaunchDarkly's JSON schema for contexts is standardized across SDKs. There are two output formats, depending on whether it is a single context or a multi-context. Unlike the unmarshaler, the marshaler never uses the old-style user context schema from older SDKs.

If the Context is invalid (that is, it has a non-nil Context.Err) then marshaling fails with the same error.

func (Context) Multiple

func (c Context) Multiple() bool

Multiple returns true for a multi-context, or false for a single context.

If this value is true, then Context.Kind is guaranteed to return MultiKind, and you can inspect the individual Contexts for each kind by calling Context.IndividualContextCount, Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts.

If this value is false, then Context.Kind is guaranteed to return a value that is not MultiKind, and Context.IndividualContextCount is guaranteed to return 1.

func (Context) Name

func (c Context) Name() ldvalue.OptionalString

Name returns the Context's optional name attribute.

For a single context, this value is set by Builder.Name or Builder.OptName. If no value was specified, it returns the empty value ldvalue.OptionalString{}. The name attribute is treated differently from other user attributes in that its value, if specified, can only be a string, and it is used as the display name for the Context on the LaunchDarkly dashboard.

For a multi-context, there is no single value, so Name() returns an empty string; use Context.IndividualContextByIndex, Context.IndividualContextByKind, or Context.GetAllIndividualContexts to get the Context for a particular kind and then call Name() on it.

func (Context) PrivateAttributeByIndex

func (c Context) PrivateAttributeByIndex(index int) (ldattr.Ref, bool)

PrivateAttributeByIndex returns one of the attributes that were marked as private for thie Context with Builder.Private or Builder.PrivateRef.

func (Context) PrivateAttributeCount

func (c Context) PrivateAttributeCount() int

PrivateAttributeCount returns the number of attributes that were marked as private for this Context with Builder.Private or Builder.PrivateRef.

func (Context) Secondary deprecated

func (c Context) Secondary() ldvalue.OptionalString

Secondary returns the deprecated secondary key meta-attribute for the Context, if any.

This corresponds to the "secondary" attribute in the older LaunchDarkly user schema. This attribute is no longer supported for flag evaluations with the LaunchDarkly Go SDK, and cannot be set via the context builder. This method only exists to allow other LaunchDarkly code to detect the presence of the attribute in JSON data produced by older LaunchDarkly SDKs.

Deprecated: this method will be removed in the future and application code should not rely on it.

func (Context) String

func (c Context) String() string

String returns a string representation of the Context.

This is currently defined as being the same as the JSON representation, since that is the simplest way to represent all of the Context properties. However, Go's fmt.Stringer interface is deliberately nonspecific about what format a type may use for its string representation, and application code should not rely on String() always being the same as the JSON representation. If you specifically want the latter, use Context.JSONString or json.Marshal. However, if you do use String() for convenience in debugging or logging, you should assume that the output may contain any and all properties of the Context, so if there is anything you do not want to be visible, you should write your own formatting logic.

func (*Context) UnmarshalJSON

func (c *Context) UnmarshalJSON(data []byte) error

UnmarshalJSON provides JSON deserialization for Context when using encoding/json.UnmarshalJSON.

LaunchDarkly's JSON schema for contexts is standardized across SDKs. For unmarshaling, there are three supported formats:

  1. A single context, identified by a top-level "kind" property that is not "multi".
  2. A multi-context, identified by a top-level "kind" property of "multi".
  3. A user context in the format used by older LaunchDarkly SDKs. This has no top-level "kind"; its kind is assumed to be DefaultKind. It follows a different layout in which some predefined attribute names are top-level properties, while others are within a "custom" property. Also, unlike new Contexts, old-style users were allowed to have an empty string "" as a key.

Trying to unmarshal any non-struct value, including a JSON null, into a Context will return a json.UnmarshalTypeError. If you want to unmarshal optional context data that might be null, pass a **Context rather than a *Context to json.Unmarshal.

type ContextSerializationMethods

type ContextSerializationMethods struct{}

ContextSerializationMethods contains JSON marshaling and unmarshaling methods that are not normally used directly by applications. These methods are exported because they are used in LaunchDarkly service code and the Relay Proxy.

var ContextSerialization ContextSerializationMethods //nolint:gochecknoglobals

ContextSerialization is the global entry point for ContextSerializationMethods.

func (ContextSerializationMethods) MarshalToJSONWriter

func (s ContextSerializationMethods) MarshalToJSONWriter(w *jwriter.Writer, c *Context)

MarshalToJSONWriter marshals a Context with the jsonstream Writer API.

func (ContextSerializationMethods) MarshalToJSONWriterEventOutput

func (s ContextSerializationMethods) MarshalToJSONWriterEventOutput(w *jwriter.Writer, c *EventOutputContext)

MarshalToJSONWriterEventOutput marshals an EventOutputContext with the jsonstream Writer API.

func (ContextSerializationMethods) UnmarshalFromJSONReader

func (s ContextSerializationMethods) UnmarshalFromJSONReader(r *jreader.Reader, c *Context) error

UnmarshalFromJSONReader unmarshals a Context with the jsonstream Reader API.

In case of failure, the error is both returned from the method and stored as a failure state in the Reader.

func (ContextSerializationMethods) UnmarshalFromJSONReaderEventOutput

func (s ContextSerializationMethods) UnmarshalFromJSONReaderEventOutput(r *jreader.Reader, c *EventOutputContext)

UnmarshalFromJSONReaderEventOutput unmarshals an EventContext with the jsonstream Reader API.

In case of failure, the error is both returned from the method and stored as a failure state in the Reader.

func (ContextSerializationMethods) UnmarshalWithKindAndKeyOnly

func (s ContextSerializationMethods) UnmarshalWithKindAndKeyOnly(r *jreader.Reader, c *Context) error

UnmarshalWithKindAndKeyOnly is a special unmarshaling mode where all properties except kind and key are discarded. It works for both single and multi-contexts. This is more efficient than the regular unmarshaling logic in situations where contexts need to be indexed by Key or FullyQualifiedKey.

Because most properties are discarded immediately without checking their value, some error conditions (for instance, a "name" property whose value is not a string) will not be detected by this method. It will fail only if validation related to the kind or key fails.

type EventOutputContext

type EventOutputContext struct {
	Context
}

EventOutputContext is a specialization of Context that uses the LaunchDarkly event schema.

Applications will not normally need to read event data; this type is provided for use in LaunchDarkly service code and other tools. In JSON event data, contexts appear slightly differently. Marshaling or unmarshaling this type rather than Context causes this variant JSON schema to be used.

The wrapped Context can have all of the same properties as a regular Context, except that the meaning of "private attributes" is slightly different: in event data, these are the attributes that were redacted due to private attribute configuration, whereas in a regular Context they are the attributes that should be redacted.

type Kind

type Kind string

Kind is a string type set by the application to describe what kind of entity a Context represents. The meaning of this is completely up to the application. When no Kind is specified, the default is DefaultKind.

For a multi-context (see NewMultiBuilder), the Context.Kind is always MultiKind; there is a specific Kind for each of the individual Contexts within it.

const (
	// DefaultKind is a constant for the default Kind of "user".
	DefaultKind Kind = "user"

	// MultiKind is a constant for the Kind that all multi-contexts have.
	MultiKind Kind = "multi"
)

type MultiBuilder

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

MultiBuilder is a mutable object that uses the builder pattern to create a multi-context, as an alternative to NewMulti.

Use this type if you need to construct a Context that has multiple Kind values, each with its own nested Context. To define a single context, use Builder instead.

Obtain an instance of MultiBuilder by calling NewMultiBuilder; then, call MultiBuilder.Add to specify the nested Context for each Kind. Finally, call MultiBuilder.Build. MultiBuilder setters return a reference to the same builder, so they can be chained together:

context := ldcontext.NewMultiBuilder().
	Add(ldcontext.New("my-user-key")).
	Add(ldcontext.NewBuilder("my-org-key").Kind("organization").Name("Org1").Build()).
	Build()

A MultiBuilder should not be accessed by multiple goroutines at once. Once you have called MultiBuilder.Build, the resulting Context is immutable and safe to use from multiple goroutines.

func NewMultiBuilder

func NewMultiBuilder() *MultiBuilder

NewMultiBuilder creates a MultiBuilder for building a multi-context.

This method is for building a Context that has multiple Context.Kind values, each with its own nested Context. To define a single context, use NewBuilder instead.

func (*MultiBuilder) Add

func (m *MultiBuilder) Add(context Context) *MultiBuilder

Add adds a nested context for a specific Kind to a MultiBuilder.

It is invalid to add more than one context with the same Kind. This error is detected when you call MultiBuilder.Build or MultiBuilder.TryBuild.

If the parameter is a multi-context, this is exactly equivalent to adding each of the individual kinds from it separately. For instance, in the following example, "multi1" and "multi2" end up being exactly the same:

c1 := ldcontext.NewWithKind("kind1", "key1")
c2 := ldcontext.NewWithKind("kind2", "key2")
c3 := ldcontext.NewWithKind("kind3", "key3")

multi1 := ldcontext.NewMultiBuilder().Add(c1).Add(c2).Add(c3).Build()

c1plus2 := ldcontext.NewMultiBuilder().Add(c1).Add(c2).Build()
multi2 := ldcontext.NewMultiBuilder().Add(c1plus2).Add(c3).Build()

func (*MultiBuilder) Build

func (m *MultiBuilder) Build() Context

Build creates a Context from the current MultiBuilder properties.

The Context is immutable and will not be affected by any subsequent actions on the MultiBuilder.

It is possible for a MultiBuilder to represent an invalid state. Instead of returning two values (Context, error), the Builder always returns a Context and you can call Context.Err() to see if it has an error. See Context.Err for more information about invalid Context conditions. Using a single-return-value syntax is more convenient for application code, since in normal usage an application will never build an invalid Context.

If only one context was added to the builder, Build returns that same context, rather than a multi-context-- since there is no logical difference in LaunchDarkly between a single context and a multi-context that only contains one context.

func (*MultiBuilder) TryBuild

func (m *MultiBuilder) TryBuild() (Context, error)

TryBuild is an alternative to Build that returns any validation errors as a second value.

As described in MultiBuilder.Build, there are several ways the state of a Context could be invalid. Since in normal usage it is possible to be confident that these will not occur, the Build method is designed for convenient use within expressions by returning a single Context value, and any validation problems are contained within that value where they can be detected by calling the context's Context.Err method. But, if you prefer to use the two-value pattern that is common in Go, you can call TryBuild instead:

c, err := ldcontext.NewMultiBuilder().
	Add(context1).Add(context2).
	TryBuild()
if err != nil {
	// do whatever is appropriate if building the context failed
}

The two return values are the same as to 1. the Context that would be returned by Build(), and 2. the result of calling Context.Err on that Context. So, the above example is exactly equivalent to:

c := ldcontext.NewMultiBuilder().
	Add(context1).Add(context2).
	Build()
if c.Err() != nil {
	// do whatever is appropriate if building the context failed
}

Note that unlike some Go methods where the first return value is normally an uninitialized zero value if the error is non-nil, the Context returned by TryBuild in case of an error is not completely uninitialized: it does contain the error information as well, so that if it is mistakenly passed to an SDK method, the SDK can tell what the error was.

Jump to

Keyboard shortcuts

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