ffclient

package module
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2021 License: MIT Imports: 19 Imported by: 25

README ΒΆ

go-feature-flag logo

πŸŽ›οΈ go-feature-flag Tweet

Build Status Coverage Status Sonarcloud Status Build Status FOSSA Status
Release version GoDoc Go version License run on repl.it Mentioned in Awesome Go

Feature flags with no complex system to maintain!

Installation

go get github.com/thomaspoignant/go-feature-flag

What is go-feature-flag?

A simple and complete feature flag solution, without any complex backend system to install, you need only a file as your backend.
No server is needed, just add a file in a central system and all your services will react to the changes of this file.

go-feature-flags supports:

  • Storing your configuration flags file on various locations (HTTP, S3, GitHub, file).
  • Configuring your flags in various format (JSON, TOML and YAML).
  • Adding complex rules to target your users.
  • Run A/B test experimentations.
  • Getting notified when a flag has changed (webhook and slack).
  • Exporting your flags usage data (s3, log and file).

If you are not familiar with feature flags also called feature Toggles you can read this article of Martin Fowler that explains why this is a great pattern.
I've also wrote an article that explains why feature flags can help you to iterate quickly.

Quickstart

First, you need to initialize the ffclient with the location of your backend file.

err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    Retriever: &ffclient.HTTPRetriever{
        URL:    "http://example.com/flag-config.yaml",
    },
})
defer ffclient.Close()

This example will load a file from an HTTP endpoint and will refresh the flags every 3 seconds (if you omit the PollInterval, the default value is 60 seconds).

Now you can evaluate your flags anywhere in your code.

user := ffuser.NewUser("user-unique-key")
hasFlag, _ := ffclient.BoolVariation("test-flag", user, false)
if hasFlag {
    // flag "test-flag" is true for the user
} else {
    // flag "test-flag" is false for the user
}

You can find more example programs in the examples/ directory.

Configuration

The configuration is set with ffclient.Config{} and you can give it to ffclient.Init() the initialization function.

Example:

ffclient.Init(ffclient.Config{ 
    PollInterval:   3,
    Logger:         log.New(file, "/tmp/log", 0),
    Context:        context.Background(),
    Retriever:      &ffclient.FileRetriever{Path: "testdata/flag-config.yaml"},
    FileFormat:     "yaml",
    Notifiers: []ffclient.NotifierConfig{
        &ffclient.WebhookConfig{
            EndpointURL: " https://example.com/hook",
            Secret:     "Secret",
            Meta: map[string]string{
                "app.name": "my app",
            },
        },
    },
    DataExporter: ffclient.DataExporter{
        FlushInterval:   10 * time.Second,
        MaxEventInMemory: 1000,
        Exporter: &ffexporter.File{
            OutputDir: "/output-data/",
        },
    },
    StartWithRetrieverError: false,
})
Field Description
Retriever The configuration retriever you want to use to get your flag file
see Where do I store my flags file for the configuration details.
Context (optional) The context used by the retriever.
Default: context.Background()
DataExporter (optional) DataExporter defines how to export data on how your flags are used.
see export data section for more details.
FileFormat (optional) Format of your configuration file. Available formats are yaml, toml and json, if you omit the field it will try to unmarshal the file as a yaml file.
Default: YAML
Logger (optional) Logger used to log what go-feature-flag is doing.
If no logger is provided the module will not log anything.
Default: No log
Notifiers (optional) List of notifiers to call when your flag file has changed.
see notifiers section for more details.
PollInterval (optional) Number of seconds to wait before refreshing the flags.
Default: 60
StartWithRetrieverError (optional) If true, the SDK will start even if we did not get any flags from the retriever. It will serve only default values until the retriever returns the flags.
The init method will not return any error if the flag file is unreachable.
Default: false

Where do I store my flags file

go-feature-flags support different ways of retrieving the flag file.
We can have only one source for the file, if you set multiple sources in your configuration, only one will be take in consideration.

From Github
expand to see details
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    Retriever: &ffclient.GithubRetriever{
        RepositorySlug: "thomaspoignant/go-feature-flag",
        Branch: "main",
        FilePath: "testdata/flag-config.yaml",
        GithubToken: "XXXX",
        Timeout: 2 * time.Second,
    },
})
defer ffclient.Close()

To configure the access to your GitHub file:

  • RepositorySlug: your GitHub slug org/repo-name. MANDATORY
  • FilePath: the path of your file. MANDATORY
  • Branch: the branch where your file is (default is main).
  • GithubToken: Github token is used to access a private repository, you need the repo permission (how to create a GitHub token).
  • Timeout: Timeout for the HTTP call (default is 10 seconds).

⚠ GitHub has rate limits, so be sure to not reach them when setting your PollInterval.

From an HTTP endpoint
expand to see details
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    Retriever: &ffclient.HTTPRetriever{
        URL:    "http://example.com/flag-config.yaml",
        Timeout: 2 * time.Second,
    },
})
defer ffclient.Close()

To configure your HTTP endpoint:

  • URL: location of your file. MANDATORY
  • Method: the HTTP method you want to use (default is GET).
  • Body: If you need a body to get the flags.
  • Header: Header you should pass while calling the endpoint (useful for authorization).
  • Timeout: Timeout for the HTTP call (default is 10 seconds).
From a S3 Bucket
expand to see details
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    Retriever: &ffclient.S3Retriever{
        Bucket: "tpoi-test",
        Item:   "flag-config.yaml",
        AwsConfig: aws.Config{
            Region: aws.String("eu-west-1"),
        },
    },
})
defer ffclient.Close()

To configure your S3 file location:

  • Bucket: The name of your bucket. MANDATORY
  • Item: The location of your file in the bucket. MANDATORY
  • AwsConfig: An instance of aws.Config that configure your access to AWS (see this documentation for more info). MANDATORY
From a file
expand to see details
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    Retriever: &ffclient.FileRetriever{
        Path: "file-example.yaml",
    },
})
defer ffclient.Close()

To configure your File retriever:

  • Path: location of your file. MANDATORY

I will not recommend using a file to store your flags except if it is in a shared folder for all your services.

Flags file format

go-feature-flag is to avoid to have to host a backend to manage your feature flags and to keep them centralized by using a file a source.
Your file should be a YAML, JSON or TOML file with a list of flags (examples: YAML, JSON, TOML).

A flag configuration looks like:

test-flag:
  percentage: 100
  rule: key eq "random-key"
  true: true
  false: false
  default: false
  disable: false
  trackEvents: true
  experimentation:
    startDate: 2021-03-20T00:00:00.10-05:00
    endDate: 2021-03-21T00:00:00.10-05:00
FieldDescription
test-flag Name of the flag.
It should be unique.
true The value return by the flag if apply to the user (rule is evaluated to true) and user is in the active percentage.
false The value return by the flag if apply to the user (rule is evaluated to true) and user is not in the active percentage.
default The value return by the flag if not apply to the user (rule is evaluated to false).
percentage (optional) Percentage of the users affect by the flag.
Default value is 0
The percentage is done by doing a hash of the user key (100000 variations), it means that you can have 3 numbers after the comma.
rule (optional) This is the query use to select on which user the flag should apply.
Rule format is describe in the rule format section.
If no rule set, the flag apply to all users (percentage still apply).
disable (optional) True if the flag is disabled.
trackEvents (optional) False if you don't want to export the data in your data exporter.
Default value is true
experimentation (optional) experimentation is here to configure a flag that is available for only a determined time.
The structure is:
  experimentation:
    startDate: 2021-03-20T00:00:00.10-05:00
    endDate: 2021-03-21T00:00:00.10-05:00
The date is in the format supported natively by your flag file format.
Check this example to see how it works.

Rule format

The rule format is based on the nikunjy/rules library.

All the operations can be written capitalized or lowercase (ex: eq or EQ can be used).
Logical Operations supported are AND OR.

Compare Expression and their definitions (a|b means you can use either one of the two a or b):

eq|==: equals to 
ne|!=: not equals to
lt|<: less than 
gt|>: greater than
le|<=: less than equal to
ge|>=: greater than equal to 
co: contains 
sw: starts with 
ew: ends with
in: in a list
pr: present
not: not of a logical expression
Examples
  • Select a specific user: key eq "example@example.com"
  • Select all identified users: anonymous ne true
  • Select a user with a custom property: userId eq "12345"

Users

Feature flag targeting and rollouts are all determined by the user you pass to your Variation calls.
The SDK defines a User struct and a UserBuilder to make this easy.

Here's an example:

// User with only a key
user1 := ffuser.NewUser("user1-key")

// User with a key plus other attributes
user2 = ffuser.NewUserBuilder("user2-key").
 AddCustom("firstname", "John").
 AddCustom("lastname", "Doe").
 AddCustom("email", "john.doe@example.com").
 Build()

The most common attribute is the user's key. In this case we've used the strings "user1-key" and "user2-key".
The user key is the only mandatory user attribute. The key should also uniquely identify each user. You can use a primary key, an e-mail address, or a hash, as long as the same user always has the same key. We recommend using a hash if possible.

Custom attributes are one of the most powerful features. They let you have rules on these attributes and target users according to any data that you want.

Variation

The Variation methods determine whether a flag is enabled or not for a specific user. There is a Variation method for each type: BoolVariation, IntVariation, Float64Variation, StringVariation, JSONArrayVariation and JSONVariation.

result, _ := ffclient.BoolVariation("your.feature.key", user, false)

// result is now true or false depending on the setting of this boolean feature flag

Variation methods take the feature flag key, a User, and a default value.

The default value is return when an error is encountered (ffclient not initialized, variation with wrong type, flag does not exist ...).
In the example, if the flag your.feature.key does not exists, result will be false.
Not that you will always have a usable value in the result.

Notifiers

If you want to be informed when a flag has changed outside of your app, you can configure a notifier. go-feature-flag can handle more than one notifier at a time (see bellow the list of available notifiers and how to configure them).

Webhooks
expand to see details

⚠ In v0.9.0 we have changed how to configure webhooks, moving from the key Webhooks to Notifiers.
Webhooks is still supported for now but will be removed in a future version.

ffclient.Config{ 
    // ...
    Notifiers: []ffclient.NotifierConfig{
        &ffclient.WebhookConfig{
            EndpointURL: " https://example.com/hook",
            Secret:     "Secret",
            Meta: map[string]string{
                "app.name": "my app",
            },
        },
        // ...
    },
}
EndpointURL mandatory The complete URL of your API (we will send a POST request to this URL, see format)
Secret optional A secret key you can share with your webhook. We will use this key to sign the request (see signature section for more details).
Meta optional A list of key value that will be add in your request, this is super usefull if you to add information on the current running instance of your app.
By default the hostname is always added in the meta informations.
Format

If you have configured a webhook, a POST request will be sent to the EndpointURL with a body in this format:

{
    "meta": {
        "hostname": "server01",
        // ...
    },
    "flags": {
        "deleted": {}, // map of your deleted flags
        "added": {}, // map of your added flags
        "updated": {
            "flag-name": { // an object that contains old and new value
                "old_value": {},
                "new_value": {}
            }
        }
    }
}
Example
{
   "meta":{
       "hostname": "server01"
   },
   "flags":{
       "deleted": {
           "test-flag": {
               "rule": "key eq \"random-key\"",
               "percentage": 100,
               "true": true,
               "false": false,
               "default": false
           }
       },
       "added": {
           "test-flag3": {
               "percentage": 5,
               "true": "test",
               "false": "false",
               "default": "default"
           }
       },
       "updated": {
           "test-flag2": {
               "old_value": {
                   "rule": "key eq \"not-a-key\"",
                   "percentage": 100,
                   "true": true,
                   "false": false,
                   "default": false
               },
               "new_value": {
                   "disable": true,
                   "rule": "key eq \"not-a-key\"",
                   "percentage": 100,
                   "true": true,
                   "false": false,
                   "default": false
               }
           }
       }
   }
}
Signature

This header X-Hub-Signature-256 is sent if the webhook is configured with a secret. This is the HMAC hex digest of the request body, and is generated using the SHA-256 hash function and the secret as the HMAC key.

⚠ The recommendation is to always use the Secret and on your API/webook always verify the signature key to be sure that you don't have a man in the middle attack.

SLACK
expand to see details

The Slack notifier allows you to get notification on your favorite slack channel when an instance of go-feature-flag is detecting changes in the configuration file.

slack notification example

  • First, you need to create an incoming webhook on your slack instance (you can follow this documentation to see how to do it)
  • Copy your webhook URL. It should looks like https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX.
  • In your go-feature-flag init method add a slack notifier
ffclient.Config{ 
    // ...
    Notifiers: []ffclient.NotifierConfig{
        &ffclient.SlackNotifier{
            SlackWebhookURL: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
        },
        // ...
    },
}
SlackWebhookURL mandatory The complete URL of your incoming webhook configured in Slack.

Export data

If you want to export data about how your flag are used, you can use the DataExporter.
It collects all the variations events and can save these events on several locations:

  • File - create local files with the variation usages.
  • Log - use your logger to write the variation usages.
  • S3 - export your variation usages to S3.
  • Webhook - export your variation usages by calling a webhook.

Currently we are supporting only feature events. It represent individual flag evaluations and are considered "full fidelity" events.

An example feature event below:

{
    "kind": "feature",
    "contextKind": "anonymousUser",
    "userKey": "ABCD",
    "creationDate": 1618228297,
    "key": "test-flag",
    "variation": "Default",
    "value": false,
    "default": false
}
Field Description
kind The kind for a feature event is feature. A feature event will only be generated if the trackEvents attribute of the flag is set to true.
contextKind The kind of context which generated an event. This will only be "anonymousUser" for events generated on behalf of an anonymous user or the reserved word "user" for events generated on behalf of a non-anonymous user
userKey The key of the user object used in a feature flag evaluation.
creationDate When the feature flag was requested at Unix epoch time in milliseconds.
key The key of the feature flag requested.
variation The variation of the flag requested. Available values are:
True: if the flag was evaluated to True
False: if the flag was evaluated to False
Dafault: if the flag was evaluated to Default
SdkDefault: if something wrong happened and the SDK default value was used.
value The value of the feature flag returned by feature flag evaluation.
default (Optional) This value is set to true if feature flag evaluation failed, in which case the value returned was the default value passed to variation.

Events are collected and send in bulk to avoid to spam your exporter (see details in how to configure data export)

How to configure data export?

In your ffclient.Config add the DataExporter field and configure your export location.

To avoid to spam your location everytime you have a variation called, go-feature-flag is storing in memory all the events and send them in bulk to the exporter.
You can decide the threshold on when to send the data with the properties FlushInterval and MaxEventInMemory. The first threshold hit will export the data.

If there are some flags you don't want to export, you can user trackEvents fields on these specific flags to disable the data export (see flag file format).

Example:

ffclient.Config{ 
    // ...
   DataExporter: ffclient.DataExporter{
        FlushInterval:   10 * time.Second,
        MaxEventInMemory: 1000,
        Exporter: &ffexporter.File{
            OutputDir: "/output-data/",
        },
    },
    // ...
}
Field Description
FlushInterval optional Time to wait before exporting the data (default: 60 seconds).
MaxEventInMemory optional If MaxEventInMemory is reach before the FlushInterval a intermediary export will be done (default: 100000).
Exporter mandatory The configuration of the exporter you want to use. All the exporters are available in the ffexporter package.
File Exporter
expand to see details

The file exporter will collect the data and create a new file in a specific folder everytime we send the data.
This file should be in the local instance.

Check this complete example to see how to export the data in a file.

Configuration example:

ffclient.Config{ 
    // ...
   DataExporter: ffclient.DataExporter{
        // ...
        Exporter: &ffexporter.File{
            OutputDir: "/output-data/",
            Format: "csv",
            FileName: "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}",
            CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n"
        },
    },
    // ...
}
Field Description
OutputDir OutputDir is the location of the directory where to store the exported files. It should finish with a /.
Format Format is the output format you want in your exported file. Available format are JSON and CSV. (Default: JSON)
Filename Filename is the name of your output file. You can use a templated config to define the name of your exported files.
Available replacement are {{ .Hostname}}, {{ .Timestamp}} and {{ .Format}}
Default: flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}
CsvTemplate CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check internal/exporter/feature_event.go to see what are the fields available.
Default: {{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n

Check the godoc for full details.

Log Exporter
expand to see details

The log exporter is here mostly for backward compatibility (originaly every variations were logged, but it can be a lot of data for a default configuration).
It will use your logger ffclient.Config.Logger to log every variations changes.

You can configure your output log with the Format field.
It use a go template format.

Configuration example:

ffclient.Config{
    // ...
   DataExporter: ffclient.DataExporter{
        Exporter: &ffexporter.Log{
            Format: "[{{ .FormattedDate}}] user=\"{{ .UserKey}}\", flag=\"{{ .Key}}\", value=\"{{ .Value}}\"",
        },
    },
    // ...
}
Field Description
Format Format is the template configuration of the output format of your log.
You can use all the key from the exporter.FeatureEvent + a key called FormattedDate that represent the date with the RFC 3339 Format.

Default: [{{ .FormattedDate}}] user="{{ .UserKey}}", flag="{{ .Key}}", value="{{ .Value}}"

Check the godoc for full details.

S3 Exporter
expand to see details

The S3 exporter will collect the data and create a new file in a specific folder everytime we send the data.
Everytime the FlushInterval or MaxEventInMemory is reached a new file will be added to S3.
If for some reason the S3 upload failed, we will keep the data in memory and retry to add the next time we reach FlushInterval or MaxEventInMemory.

export in S3 screenshot

Check this complete example to see how to export the data in S3.

Configuration example:

ffclient.Config{ 
    // ...
   DataExporter: ffclient.DataExporter{
        // ...
        Exporter: &ffexporter.S3{
            Format: "csv",
            FileName: "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}",
            CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n",
            Bucket:    "my-bucket",
            S3Path:    "/go-feature-flag/variations/",
            Filename:  "flag-variation-{{ .Timestamp}}.{{ .Format}}",
            AwsConfig: &aws.Config{
               Region: aws.String("eu-west-1"),
           },
        },
    },
    // ...
}
Field Description
Bucket Name of your S3 Bucket.
AwsConfig An instance of aws.Config that configure your access to AWS (see this documentation for more info).
CsvTemplate (optional) CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check internal/exporter/feature_event.go to see what are the fields available.
Default: {{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n
Filename (optional) Filename is the name of your output file. You can use a templated config to define the name of your exported files.
Available replacement are {{ .Hostname}}, {{ .Timestamp}} and {{ .Format}}
Default: flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}
Format (optional) Format is the output format you want in your exported file. Available format are JSON and CSV. (Default: JSON)
S3Path (optional) The location of the directory in S3.

Check the godoc for full details.

Webhook Exporter
expand to see details

The Webhook exporter will collect the data and will send an HTTP POST request to the specified endpoint.
Everytime the FlushInterval or MaxEventInMemory is reached a new call is performed.
If for some reason the call failed, we will keep the data in memory and retry to add the next time we reach FlushInterval or MaxEventInMemory.

Configuration example:

ffclient.Config{ 
    // ...
   DataExporter: ffclient.DataExporter{
        // ...
        Exporter: &ffexporter.Webhook{
            EndpointURL: " https://webhook.url/",
            Secret:      "secret-for-signing",
            Meta:        map[string]string{
                "extraInfo": "info",
            },
        },
    },
    // ...
}
Field Description
EndpointURL EndpointURL of your webhook
Secret (optional) Secret used to sign your request body and fill the X-Hub-Signature-256 header.
Meta (optional) Add all the informations you want to see in your request.
Webhook format

If you have configured a webhook, a POST request will be sent to the EndpointURL with a body in this format:

{
    "meta": {
        "hostname": "server01",
        // ...
    },
    "events": [
        {
            "kind": "feature",
            "contextKind": "anonymousUser",
            "userKey": "14613538188334553206",
            "creationDate": 1618909178,
            "key": "test-flag",
            "variation": "Default",
            "value": false,
            "default": false
        },
        // ...
    ]
}
Signature

This header X-Hub-Signature-256 is sent if the webhook is configured with a secret. This is the HMAC hex digest of the request body, and is generated using the SHA-256 hash function and the secret as the HMAC key.

⚠ The recommendation is to always use the Secret and on your API/webook always verify the signature key to be sure that you don't have a man in the middle attack.

Multiple configuration flag files

go-feature-flag comes ready to use out of the box by calling the Init function and after that it will be available everywhere. Since most applications will want to use a single central flag configuration, the go-feature-flag package provides this. It is similar to a singleton.

In all of the examples above, they demonstrate using go-feature-flag in its singleton style approach.

Working with multiple go-feature-flag

You can also create many different go-feature-flag client for use in your application.
Each will have its own unique set of configurations and flags. Each can read from a different config file and from different places.
All of the functions that go-feature-flag package supports are mirrored as methods on a goFeatureFlag.

Example:
x, err := ffclient.New(Config{ Retriever: &ffclient.HTTPRetriever{{URL: "http://example.com/flag-config.yaml",}})
defer x.Close()

y, err := ffclient.New(Config{ Retriever: &ffclient.HTTPRetriever{{URL: "http://example.com/test2.yaml",}})
defer y.Close()

user := ffuser.NewUser("user-key")
x.BoolVariation("test-flag", user, false)
y.BoolVariation("test-flag", user, false)

// ...

When working with multiple go-feature-flag, it is up to the user to keep track of the different go-feature-flag instances.

How can I contribute?

This project is open for contribution, see the contributor's guide for some helpful tips.

Documentation ΒΆ

Overview ΒΆ

Package ffclient aids adding instrumentation to have feature flags in your app without any backend server.

Summary ΒΆ

This package and its subpackages contain bits of code to have an easy feature flag solution with no complex installation to do on your infrastructure and without using 3rd party vendor for this.

The ffclient package provides the entry point - initialization and the basic method to get your flags value.

Before using the module you need to initialized it this way:

func main() {
  err := ffclient.Init(ffclient.Config{
           PollInterval: 3,
           HTTPRetriever: &ffClient.HTTPRetriever{
             URL:    "http://example.com/flag-config.yaml",
           },
         })
  defer ffclient.Close()
  ...

This example will load a file from an HTTP endpoint and will refresh the flags every 3 seconds.

Now you can evalute your flags anywhere in your code.

func main() {
  ...
  user := ffuser.NewUser("user-unique-key")
  hasFlag, _ := ffclient.BoolVariation("test-flag", user, false)
  if hasFlag {
    //flag "test-flag" is true for the user
  } else {
    // flag "test-flag" is false for the user
  }
  ...

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

func BoolVariation ΒΆ

func BoolVariation(flagKey string, user ffuser.User, defaultValue bool) (bool, error)

BoolVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func Close ΒΆ

func Close()

Close the component by stopping the background refresh and clean the cache.

func Float64Variation ΒΆ

func Float64Variation(flagKey string, user ffuser.User, defaultValue float64) (float64, error)

Float64Variation return the value of the flag in float64. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func Init ΒΆ

func Init(config Config) error

Init the feature flag component with the configuration of ffclient.Config

func main() {
  err := ffclient.Init(ffclient.Config{
           PollInterval: 3,
           Retriever: &ffClient.HTTPRetriever{
             URL:    "http://example.com/flag-config.yaml",
           },
         })
  defer ffclient.Close()

func IntVariation ΒΆ

func IntVariation(flagKey string, user ffuser.User, defaultValue int) (int, error)

IntVariation return the value of the flag in int. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func JSONArrayVariation ΒΆ

func JSONArrayVariation(flagKey string, user ffuser.User, defaultValue []interface{}) ([]interface{}, error)

JSONArrayVariation return the value of the flag in []interface{}. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func JSONVariation ΒΆ

func JSONVariation(
	flagKey string, user ffuser.User, defaultValue map[string]interface{}) (map[string]interface{}, error)

JSONVariation return the value of the flag in map[string]interface{}. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func StringVariation ΒΆ

func StringVariation(flagKey string, user ffuser.User, defaultValue string) (string, error)

StringVariation return the value of the flag in string. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

Types ΒΆ

type Config ΒΆ

type Config struct {
	// PollInterval (optional) Poll every X seconds
	// Default: 60 seconds
	PollInterval int

	// Logger (optional) logger use by the library
	// Default: No log
	Logger *log.Logger

	// Context (optional) used to call other services (HTTP, S3 ...)
	// Default: context.Background()
	Context context.Context

	// Retriever is the component in charge to retrieve your flag file
	Retriever Retriever

	// Notifiers (optional) is the list of notifiers called when a flag change
	Notifiers []NotifierConfig

	// FileFormat (optional) is the format of the file to retrieve (available YAML, TOML and JSON)
	// Default: YAML
	FileFormat string

	// Deprecated: Use Notifiers instead, webhooks will be delete in a future version
	Webhooks []WebhookConfig // Webhooks we should call when a flag create/update/delete

	// DataExporter (optional) is the configuration where we store how we should output the flags variations results
	DataExporter DataExporter

	// StartWithRetrieverError (optional) If true, the SDK will start even if we did not get any flags from the retriever.
	// It will serve only default values until the retriever returns the flags.
	// The init method will not return any error if the flag file is unreachable.
	// Default: false
	StartWithRetrieverError bool
}

Config is the configuration of go-feature-flag. PollInterval is the interval in seconds where we gonna read the file to update the cache. You should also have a retriever to specify where to read the flags file.

func (*Config) GetRetriever ΒΆ

func (c *Config) GetRetriever() (retriever.FlagRetriever, error)

GetRetriever returns a retriever.FlagRetriever configure with the retriever available in the config.

type DataExporter ΒΆ added in v0.10.0

type DataExporter struct {
	// FlushInterval is the interval we are waiting to export the data.
	// example: if you set your FlushInterval to 1 minutes, we will send
	// the data every minute unless we reach the max event in cache before.
	FlushInterval time.Duration

	// MaxEventInMemory is the maximum number of event you keep in the cache
	// before sending the data to the Exporter.
	// We will send the data when the MaxEventInMemory is reach or if we have
	// waited the FlushInterval.
	MaxEventInMemory int64

	// Exporter is the configuration of your exporter.
	// You can see all available exporter in the ffexporter package.
	Exporter exporter.Exporter
}

DataExporter is the configuration of your export target.

type FileRetriever ΒΆ added in v0.5.0

type FileRetriever struct {
	Path string
}

FileRetriever is a configuration struct for a local flat file.

type GithubRetriever ΒΆ added in v0.4.0

type GithubRetriever struct {
	RepositorySlug string
	Branch         string // default is main
	FilePath       string
	GithubToken    string
	Timeout        time.Duration // default is 10 seconds
}

GithubRetriever is a configuration struct for a GitHub retriever.

type GoFeatureFlag ΒΆ added in v0.6.0

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

GoFeatureFlag is the main object of the library it contains the cache, the config and the update.

func New ΒΆ added in v0.6.0

func New(config Config) (*GoFeatureFlag, error)

New creates a new go-feature-flag instance that retrieve the config from a YAML file and return everything you need to manage your flags.

func (*GoFeatureFlag) BoolVariation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) BoolVariation(flagKey string, user ffuser.User, defaultValue bool) (bool, error)

BoolVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

func (*GoFeatureFlag) Close ΒΆ added in v0.6.0

func (g *GoFeatureFlag) Close()

Close wait until thread are done

func (*GoFeatureFlag) Float64Variation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) Float64Variation(flagKey string, user ffuser.User, defaultValue float64) (float64, error)

Float64Variation return the value of the flag in float64. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

func (*GoFeatureFlag) IntVariation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) IntVariation(flagKey string, user ffuser.User, defaultValue int) (int, error)

IntVariation return the value of the flag in int. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

func (*GoFeatureFlag) JSONArrayVariation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) JSONArrayVariation(
	flagKey string, user ffuser.User, defaultValue []interface{}) ([]interface{}, error)

JSONArrayVariation return the value of the flag in []interface{}. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

func (*GoFeatureFlag) JSONVariation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) JSONVariation(
	flagKey string, user ffuser.User, defaultValue map[string]interface{}) (map[string]interface{}, error)

JSONVariation return the value of the flag in map[string]interface{}. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

func (*GoFeatureFlag) StringVariation ΒΆ added in v0.6.0

func (g *GoFeatureFlag) StringVariation(flagKey string, user ffuser.User, defaultValue string) (string, error)

StringVariation return the value of the flag in string. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value. Note: Use this function only if you are using multiple go-feature-flag instances.

type HTTPRetriever ΒΆ

type HTTPRetriever struct {
	URL     string
	Method  string
	Body    string
	Header  http.Header
	Timeout time.Duration
}

HTTPRetriever is a configuration struct for an HTTP endpoint retriever.

type NotifierConfig ΒΆ added in v0.9.0

type NotifierConfig interface {
	GetNotifier(config Config) (notifier.Notifier, error)
}

NotifierConfig is the interface for your notifiers. You can use as notifier a WebhookConfig

Notifiers: []ffclient.NotifierConfig{
       &ffclient.WebhookConfig{
           EndpointURL: " https://example.com/hook",
           Secret:     "Secret",
           Meta: map[string]string{
               "app.name": "my app",
           },
       },
       // ...
   }

type Retriever ΒΆ added in v0.5.0

type Retriever interface {
	// contains filtered or unexported methods
}

type S3Retriever ΒΆ

type S3Retriever struct {
	// Bucket is the name of your S3 Bucket.
	Bucket string

	// Item is the path to your flag file in your bucket.
	Item string

	// AwsConfig is the AWS SDK configuration object we will use to
	// download your feature flag configuration file.
	AwsConfig aws.Config
}

S3Retriever is a configuration struct for a S3 retriever.

type SlackNotifier ΒΆ added in v0.9.0

type SlackNotifier struct {
	SlackWebhookURL string
}

func (*SlackNotifier) GetNotifier ΒΆ added in v0.9.0

func (w *SlackNotifier) GetNotifier(config Config) (notifier.Notifier, error)

GetNotifier convert the configuration in a Notifier struct

type WebhookConfig ΒΆ added in v0.7.0

type WebhookConfig struct {
	// Deprecated: use EndpointURL instead
	PayloadURL string

	// EndpointURL is the URL where we gonna do the POST Request.
	EndpointURL string
	Secret      string            // Secret used to sign your request body.
	Meta        map[string]string // Meta information that you want to send to your webhook (not mandatory)
}

WebhookConfig is the configuration of your webhook. we will call this URL with a POST request with the following format

 {
  "meta":{
      "hostname": "server01"
  },
  "flags":{
      "deleted": {
          "test-flag": {
              "rule": "key eq \"random-key\"",
              "percentage": 100,
              "true": true,
              "false": false,
              "default": false
          }
      },
      "added": {
          "test-flag3": {
              "percentage": 5,
              "true": "test",
              "false": "false",
              "default": "default"
          }
      },
      "updated": {
          "test-flag2": {
              "old_value": {
                  "rule": "key eq \"not-a-key\"",
                  "percentage": 100,
                  "true": true,
                  "false": false,
                  "default": false
              },
              "new_value": {
                  "disable": true,
                  "rule": "key eq \"not-a-key\"",
                  "percentage": 100,
                  "true": true,
                  "false": false,
                  "default": false
              }
          }
      }
  }
}

func (*WebhookConfig) GetNotifier ΒΆ added in v0.9.0

func (w *WebhookConfig) GetNotifier(config Config) (notifier.Notifier, error)

GetNotifier convert the configuration in a Notifier struct

Directories ΒΆ

Path Synopsis
examples
Package ffexporter defines the data exporter of go-feature-flag Theses exporters are usable in your init configuration.
Package ffexporter defines the data exporter of go-feature-flag Theses exporters are usable in your init configuration.
Package ffuser defines the go-feature-flag model for user properties.
Package ffuser defines the go-feature-flag model for user properties.

Jump to

Keyboard shortcuts

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