Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mwitkow/go-flagz
Dynamic flag management for Go.
https://github.com/mwitkow/go-flagz
configuration dynamic-flags etcd flags golang kubernetes
Last synced: 7 days ago
JSON representation
Dynamic flag management for Go.
- Host: GitHub
- URL: https://github.com/mwitkow/go-flagz
- Owner: mwitkow
- License: apache-2.0
- Created: 2015-07-19T14:50:49.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2021-04-12T11:42:48.000Z (over 3 years ago)
- Last Synced: 2024-06-19T20:51:36.679Z (5 months ago)
- Topics: configuration, dynamic-flags, etcd, flags, golang, kubernetes
- Language: Go
- Size: 389 KB
- Stars: 205
- Watchers: 7
- Forks: 24
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Go FlagZ
[![Travis Build](https://travis-ci.org/mwitkow/go-flagz.svg)](https://travis-ci.org/mwitkow/go-flagz)
[![Go Report Card](https://goreportcard.com/badge/github.com/mwitkow/go-flagz)](http://goreportcard.com/report/mwitkow/go-flagz)
[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/mwitkow/go-flagz)
[![SourceGraph](https://sourcegraph.com/github.com/mwitkow/go-flagz/-/badge.svg)](https://sourcegraph.com/github.com/mwitkow/go-flagz/?badge)
[![codecov](https://codecov.io/gh/mwitkow/go-flagz/branch/master/graph/badge.svg)](https://codecov.io/gh/mwitkow/go-flagz)
[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)Dynamic, thread-safe `flag` variables that can be modified at runtime through [etcd](https://github.com/coreos/etcd)
or [Kubernetes](http://kubernetes.io).For a similar project for JVM languages (Java, scala) see [java-flagz](https://github.com/mwitkow/java-flagz)
## This sounds crazy. Why?File-based or command-line configuration can only be changed when a service restarts. Dynamic flags provide
flexibility in normal operations and emergencies. Two examples:
* A new feature launches that you want to A/B test. You want to gradually enable it for a certain fraction of user
requests (1%, 5%, 20%, 50%, 100%) without the need to restart servers.
* Your service is getting overloaded and you want to disable certain costly features. You can't afford
restarting because you'd lose important capacity.
All of this can be done simultaneously across a whole shard of your services.## Features
* compatible with popular `flag` replacement [`spf13/pflag`](https://github.com/spf13/pflag) (e.g. ones using [`spf13/cobra`](https://github.com/spf13/cobra))
* dynamic `flag` that are thread-safe and efficient:
- `DynInt64`
- `DynFloat64`
- `DynString`
- `DynDuration`
- `DynStringSlice`
- `DynJSON` - a `flag` that takes an arbitrary JSON struct
- `DynProto3` - a `flag` that takes a `proto3` struct in JSONpb or binary form
* `validator` functions for each `flag`, allows the user to provide checks for newly set values
* `notifier` functions allow user code to be subscribed to `flag` changes
* Kubernetes `ConfigMap` watcher, see [configmap/README.md](configmap/README.md).
* `etcd` based watcher that syncs values from a distributed Key-Value store into the program's memory
* Prometheus metric for checksums of the current flag configuration
* a `/debug/flagz` HandlerFunc endpoint that allows for easy inspection of the service's runtime configurationHere's a teaser of the debug endpoint:
![Status Endpoint](https://raw.githubusercontent.com/mwitkow/go-flagz/screenshots/screenshot_endpoint.png)
## Examples
Declare a single `pflag.FlagSet` in some public package (e.g. `common.SharedFlagSet`) that you'll use throughout your server.
### Dynamic JSON flag with a validator and notifier
```go
var (
limitsConfigFlag = flagz.DynJSON(
common.SharedFlagSet,
"rate_limiting_config",
&rateLimitConfig{ DefaultRate: 10, Policy: "allow"},
"Config for service's rate limit",
).WithValidator(rateLimitConfigValidator).WithNotifier(onRateLimitChange)
)
```This declares a JSON flag of type `rateLimitConfig` with a default value. Whenever the config changes (statically or dynamically) the `rateLimitConfigValidator` will be called. If it returns no errors, the flag will be updated and `onRateLimitChange` will be called with both old and new, allowing the rate-limit mechanism to re-tune.
## Dynamic feature flags
```go
var (
featuresFlag = flagz.DynStringSlice(common.SharedFlagSet, "enabled_features", []string{"fast_index"}, "list of enabled feature markers")
)
...
func MyHandler(resp http.ResponseWriter, req *http.Request) {
...
if existsInStringSlice("fast_index", featuresFlag.Get()) {
doFastIndex(req)
}
...
}
```All access to `featuresFlag`, which is a `[]string` flag, is synchronised across go-routines using `atomic` pointer swaps.
## Watching for changes from etcd
```go
// First parse the flags from the command line, as normal.
common.SharedFlagSet.Parse(os.Args[1:])
w, err := watcher.New(common.SharedFlagSet, etcdClient, "/my_service/flagz", logger)
if err != nil {
logger.Fatalf("failed setting up %v", err)
}
// Read flagz from etcd and update their values in common.SharedFlagSet
if err := w.Initialize(); err != nil {
log.Fatalf("failed setting up %v", err)
}
// Start listening of dynamic flags from etcd.
w.Start()
```The `watcher`'s go-routine will watch for `etcd` value changes and synchronise them with values in memory. In case a value fails parsing or the user-specified `validator`, the key in `etcd` will be atomically rolled back.
## More examples:
* [simple http server](examples/server)
* [printing CLI command](examples/cli)# Status
This code is *production* quality. It's been running happily in production at Improbable for a few months.
Features planned:
* [x] - [#11](https://github.com/mwitkow/go-flagz/issues/11) monitoring of `FlagSet` checksus using a Prometheus handler
* [ ] - [#12](https://github.com/mwitkow/go-flagz/issues/12) support for standard `flag` (requires changes in `spf13/pflag` interfaces)### License
`go-flagz` is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.