Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing Go code style issues #33

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![tests](https://github.com/statsig-io/go-sdk/actions/workflows/test.yml/badge.svg)](https://github.com/statsig-io/go-sdk/actions/workflows/test.yml)

The Statsig Go SDK for multi-user, server side environments. If you need a SDK for another language or single user client environment, check out our [other SDKs](https://docs.statsig.com/#sdks).
The Statsig Go SDK for multi-user, server side environments. If you need an SDK for another language or single user client environment, check out our [other SDKs](https://docs.statsig.com/#sdks).

Statsig helps you move faster with Feature Gates (Feature Flags) and Dynamic Configs. It also allows you to run A/B tests to validate your new features and understand their impact on your KPIs. If you're new to Statsig, create an account at [statsig.com](https://www.statsig.com).

Expand All @@ -12,10 +12,10 @@ Check out our [SDK docs](https://docs.statsig.com/server/golangSDK) to get start

## Testing

Each server SDK is tested at multiple levels - from unit to integration and e2e tests. Our internal e2e test harness runs daily against each server SDK, while unit and integration tests can be seen in the respective github repos of each SDK. The `statsig_test.go` runs a validation test on local rule/condition evaluation for this SDK against the results in the statsig backend.
Each server SDK is tested at multiple levels - from unit to integration and e2e tests. Our internal e2e test harness runs daily against each server SDK, while unit and integration tests can be seen in the respective GitHub repos of each SDK. The `statsig_test.go` runs a validation test on local rule/condition evaluation for this SDK against the results in the statsig backend.

## Guidelines

- Pull requests are welcome!
- Pull requests are welcome!
- If you encounter bugs, feel free to [file an issue](https://github.com/statsig-io/go-sdk/issues).
- For integration questions/help, [join our slack community](https://join.slack.com/t/statsigcommunity/shared_invite/zt-pbp005hg-VFQOutZhMw5Vu9eWvCro9g).
56 changes: 30 additions & 26 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
)

// An instance of a StatsigClient for interfacing with Statsig Feature Gates, Dynamic Configs, Experiments, and Event Logging
// Client is an instance of a StatsigClient for interfacing with Statsig Feature Gates, Dynamic Configs, Experiments, and Event Logging
type Client struct {
sdkKey string
evaluator *evaluator
Expand All @@ -18,12 +18,12 @@ type Client struct {
diagnostics *diagnostics
}

// Initializes a Statsig Client with the given sdkKey
// NewClient initializes a Statsig Client with the given sdkKey
func NewClient(sdkKey string) *Client {
return NewClientWithOptions(sdkKey, &Options{})
}

// Initializes a Statsig Client with the given sdkKey and options
// NewClientWithOptions initializes a Statsig Client with the given sdkKey and options
func NewClientWithOptions(sdkKey string, options *Options) *Client {
diagnostics := newDiagnostics(options)
diagnostics.initialize().overall().start().mark()
Expand All @@ -50,31 +50,31 @@ func NewClientWithOptions(sdkKey string, options *Options) *Client {
}
}

// Checks the value of a Feature Gate for the given user
// CheckGate checks the value of a Feature Gate for the given user
func (c *Client) CheckGate(user User, gate string) bool {
options := checkGateOptions{disableLogExposures: false}
return c.checkGateImpl(user, gate, options).Value
}

// Checks the value of a Feature Gate for the given user without logging an exposure event
// CheckGateWithExposureLoggingDisabled checks the value of a Feature Gate for the given user without logging an exposure event
func (c *Client) CheckGateWithExposureLoggingDisabled(user User, gate string) bool {
options := checkGateOptions{disableLogExposures: true}
return c.checkGateImpl(user, gate, options).Value
}

// Get the Feature Gate for the given user
// GetGate gets the Feature Gate for the given user
func (c *Client) GetGate(user User, gate string) FeatureGate {
options := checkGateOptions{disableLogExposures: false}
return c.checkGateImpl(user, gate, options)
}

// Checks the value of a Feature Gate for the given user without logging an exposure event
// GetGateWithExposureLoggingDisabled checks the value of a Feature Gate for the given user without logging an exposure event
func (c *Client) GetGateWithExposureLoggingDisabled(user User, gate string) FeatureGate {
options := checkGateOptions{disableLogExposures: true}
return c.checkGateImpl(user, gate, options)
}

// Logs an exposure event for the dynamic config
// ManuallyLogGateExposure logs an exposure event for the dynamic config
func (c *Client) ManuallyLogGateExposure(user User, gate string) {
c.errorBoundary.captureVoid(func() {
if !c.verifyUser(user) {
Expand All @@ -87,21 +87,21 @@ func (c *Client) ManuallyLogGateExposure(user User, gate string) {
})
}

// Gets the DynamicConfig value for the given user
// GetConfig gets the DynamicConfig value for the given user
func (c *Client) GetConfig(user User, config string) DynamicConfig {
options := &getConfigOptions{disableLogExposures: false}
context := getConfigImplContext{configOptions: options}
return c.getConfigImpl(user, config, context)
}

// Gets the DynamicConfig value for the given user without logging an exposure event
// GetConfigWithExposureLoggingDisabled gets the DynamicConfig value for the given user without logging an exposure event
func (c *Client) GetConfigWithExposureLoggingDisabled(user User, config string) DynamicConfig {
options := &getConfigOptions{disableLogExposures: true}
context := getConfigImplContext{configOptions: options}
return c.getConfigImpl(user, config, context)
}

// Logs an exposure event for the config
// ManuallyLogConfigExposure logs an exposure event for the config
func (c *Client) ManuallyLogConfigExposure(user User, config string) {
c.errorBoundary.captureVoid(func() {
if !c.verifyUser(user) {
Expand All @@ -114,7 +114,7 @@ func (c *Client) ManuallyLogConfigExposure(user User, config string) {
})
}

// Gets the DynamicConfig value of an Experiment for the given user
// GetExperiment gets the DynamicConfig value of an Experiment for the given user
func (c *Client) GetExperiment(user User, experiment string) DynamicConfig {
if !c.verifyUser(user) {
return *NewConfig(experiment, nil, "", "", nil)
Expand All @@ -124,7 +124,7 @@ func (c *Client) GetExperiment(user User, experiment string) DynamicConfig {
return c.getConfigImpl(user, experiment, context)
}

// Gets the DynamicConfig value of an Experiment for the given user without logging an exposure event
// GetExperimentWithExposureLoggingDisabled gets the DynamicConfig value of an Experiment for the given user without logging an exposure event
func (c *Client) GetExperimentWithExposureLoggingDisabled(user User, experiment string) DynamicConfig {
if !c.verifyUser(user) {
return *NewConfig(experiment, nil, "", "", nil)
Expand All @@ -134,7 +134,7 @@ func (c *Client) GetExperimentWithExposureLoggingDisabled(user User, experiment
return c.getConfigImpl(user, experiment, context)
}

// Gets the DynamicConfig value of an Experiment for the given user with configurable options
// GetExperimentWithOptions gets the DynamicConfig value of an Experiment for the given user with configurable options
func (c *Client) GetExperimentWithOptions(user User, experiment string, options *GetExperimentOptions) DynamicConfig {
if !c.verifyUser(user) {
return *NewConfig(experiment, nil, "", "", nil)
Expand All @@ -143,11 +143,12 @@ func (c *Client) GetExperimentWithOptions(user User, experiment string, options
return c.getConfigImpl(user, experiment, context)
}

// Logs an exposure event for the experiment
// ManuallyLogExperimentExposure logs an exposure event for the experiment
func (c *Client) ManuallyLogExperimentExposure(user User, experiment string) {
c.ManuallyLogConfigExposure(user, experiment)
}

// GetUserPersistedValues gets the persisted values for the given user
func (c *Client) GetUserPersistedValues(user User, idType string) UserPersistedValues {
return c.errorBoundary.captureGetUserPersistedValues(func() UserPersistedValues {
persistedValues := c.evaluator.persistentStorageUtils.getUserPersistedValues(user, idType)
Expand All @@ -159,19 +160,19 @@ func (c *Client) GetUserPersistedValues(user User, idType string) UserPersistedV
})
}

// Gets the Layer object for the given user
// GetLayer gets the Layer object for the given user
func (c *Client) GetLayer(user User, layer string) Layer {
options := getLayerOptions{disableLogExposures: false}
return c.getLayerImpl(user, layer, options)
}

// Gets the Layer object for the given user without logging an exposure event
// GetLayerWithExposureLoggingDisabled gets the Layer object for the given user without logging an exposure event
func (c *Client) GetLayerWithExposureLoggingDisabled(user User, layer string) Layer {
options := getLayerOptions{disableLogExposures: true}
return c.getLayerImpl(user, layer, options)
}

// Logs an exposure event for the parameter in the given layer
// ManuallyLogLayerParameterExposure logs an exposure event for the parameter in the given layer
func (c *Client) ManuallyLogLayerParameterExposure(user User, layer string, parameter string) {
c.errorBoundary.captureVoid(func() {
if !c.verifyUser(user) {
Expand All @@ -185,7 +186,7 @@ func (c *Client) ManuallyLogLayerParameterExposure(user User, layer string, para
})
}

// Logs an event to Statsig for analysis in the Statsig Console
// LogEvent logs an event to Statsig for analysis in the Statsig Console
func (c *Client) LogEvent(event Event) {
c.errorBoundary.captureVoid(func() {
event.User = normalizeUser(event.User, *c.options)
Expand All @@ -196,38 +197,40 @@ func (c *Client) LogEvent(event Event) {
})
}

// Override the value of a Feature Gate for the given user
// OverrideGate overrides the value of a Feature Gate for the given user
func (c *Client) OverrideGate(gate string, val bool) {
c.errorBoundary.captureVoid(func() { c.evaluator.OverrideGate(gate, val) })
}

// Override the DynamicConfig value for the given user
// OverrideConfig overrides the DynamicConfig value for the given user
func (c *Client) OverrideConfig(config string, val map[string]interface{}) {
c.errorBoundary.captureVoid(func() { c.evaluator.OverrideConfig(config, val) })
}

// Override the Layer value for the given user
// OverrideLayer overrides the Layer value for the given user
func (c *Client) OverrideLayer(layer string, val map[string]interface{}) {
c.errorBoundary.captureVoid(func() { c.evaluator.OverrideLayer(layer, val) })
}

// LogImmediate logs a batch of events to Statsig for analysis in the Statsig Console
func (c *Client) LogImmediate(events []Event) (*http.Response, error) {
if len(events) > 500 {
err := errors.New(EventBatchSizeError)
return nil, fmt.Errorf(err.Error())
}
events_processed := make([]interface{}, 0)
eventsProcessed := make([]interface{}, 0)
for _, event := range events {
event.User = normalizeUser(event.User, *c.options)
events_processed = append(events_processed, event)
eventsProcessed = append(eventsProcessed, event)
}
input := logEventInput{
Events: events_processed,
Events: eventsProcessed,
StatsigMetadata: c.transport.metadata,
}
return c.transport.post("/log_event", input, nil, RequestOptions{})
}

// GetClientInitializeResponse gets the ClientInitializeResponse for the given user
func (c *Client) GetClientInitializeResponse(user User, clientKey string) ClientInitializeResponse {
return c.errorBoundary.captureGetClientInitializeResponse(func() ClientInitializeResponse {
if !c.verifyUser(user) {
Expand All @@ -247,7 +250,7 @@ func (c *Client) verifyUser(user User) bool {
return true
}

// Cleans up Statsig, persisting any Event Logs and cleanup processes
// Shutdown cleans up Statsig, persisting any Event Logs and cleanup processes
// Using any method is undefined after Shutdown() has been called
func (c *Client) Shutdown() {
c.errorBoundary.captureVoid(func() {
Expand All @@ -264,6 +267,7 @@ type getConfigOptions struct {
disableLogExposures bool
}

// GetExperimentOptions is a set of options for fetching an experiment
type GetExperimentOptions struct {
DisableLogExposures bool
PersistedValues UserPersistedValues
Expand Down
2 changes: 1 addition & 1 deletion client_initialize_response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestInitializeResponseConsistency(t *testing.T) {
InitializeWithOptions(secret, &Options{
API: api,
OutputLoggerOptions: getOutputLoggerOptionsForTest(t),
StatsigLoggerOptions: getStatsigLoggerOptionsForTest(t),
StatsigLoggerOptions: getStatsigLoggerOptionsForTest(),
})
defer ShutdownAndDangerouslyClearInstance()

Expand Down
2 changes: 1 addition & 1 deletion concurrency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestCallingAPIsConcurrently(t *testing.T) {
Tier: "awesome_land",
},
OutputLoggerOptions: getOutputLoggerOptionsForTest(t),
StatsigLoggerOptions: getStatsigLoggerOptionsForTest(t),
StatsigLoggerOptions: getStatsigLoggerOptionsForTest(),
}

InitializeWithOptions("secret-key", options)
Expand Down
10 changes: 5 additions & 5 deletions data_adapter_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,25 @@ func (d *dataAdapterExample) Initialize() {}

func (d *dataAdapterExample) Shutdown() {}

func (d *dataAdapterExample) ShouldBeUsedForQueryingUpdates(key string) bool {
func (d *dataAdapterExample) ShouldBeUsedForQueryingUpdates(string) bool {
return false
}

type brokenDataAdapterExample struct{}

func (d brokenDataAdapterExample) Get(key string) string {
func (d brokenDataAdapterExample) Get(string) string {
panic(errors.New("invalid get function"))
}

func (d brokenDataAdapterExample) Set(key string, value string) {
func (d brokenDataAdapterExample) Set(string, string) {
panic(errors.New("invalid set function"))
}

func (d brokenDataAdapterExample) Initialize() {}

func (d brokenDataAdapterExample) Shutdown() {}

func (d brokenDataAdapterExample) ShouldBeUsedForQueryingUpdates(key string) bool {
func (d brokenDataAdapterExample) ShouldBeUsedForQueryingUpdates(string) bool {
return false
}

Expand All @@ -69,7 +69,7 @@ func (d *dataAdapterWithPollingExample) Initialize() {}

func (d *dataAdapterWithPollingExample) Shutdown() {}

func (d *dataAdapterWithPollingExample) ShouldBeUsedForQueryingUpdates(key string) bool {
func (d *dataAdapterWithPollingExample) ShouldBeUsedForQueryingUpdates(string) bool {
return true
}
func (d *dataAdapterWithPollingExample) clearStore(key string) {
Expand Down
36 changes: 13 additions & 23 deletions data_adapter_interface.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
package statsig

const CONFIG_SPECS_KEY = "statsig.cache"
const ID_LISTS_KEY = "statsig.id_lists"
const (
configSpecsKey = "statsig.cache"
idListsKey = "statsig.id_lists"
)

/**
* An adapter for implementing custom storage of config specs.
* Can be used to bootstrap Statsig (priority over bootstrapValues if both provided)
* Also useful for backing up cached data
*/
// IDataAdapter is an adapter for implementing custom storage of config specs.
// Can be used to bootstrap Statsig (priority over bootstrapValues if both provided)
// Also useful for backing up cached data
type IDataAdapter interface {
/**
* Returns the data stored for a specific key
*/
// Get returns the data stored for a specific key
Get(key string) string

/**
* Updates data stored for each key
*/
// Set updates data stored for each key
Set(key string, value string)

/**
* Startup tasks to run before any get/set calls can be made
*/
// Initialize starts up tasks to run before any get/set calls can be made
Initialize()

/**
* Cleanup tasks to run when statsig is shutdown
*/
// Shutdown cleans up tasks to run when statsig is shutdown
Shutdown()

/**
* Determines whether the SDK should poll for updates from
* the data adapter (instead of Statsig network) for the given key
*/
// ShouldBeUsedForQueryingUpdates determines whether the SDK should poll for updates
// from the data adapter (instead of Statsig network) for the given key
ShouldBeUsedForQueryingUpdates(key string) bool
}
Loading