envconfig: github.com/vrischmann/envconfig Index | Examples | Files

package envconfig

import "github.com/vrischmann/envconfig"

Package envconfig implements a configuration reader which reads each value from an environment variable.

The basic idea is that you define a configuration struct, like this:

var conf struct {
    Addr string
    Port int
    Auth struct {
        Key      string
        Endpoint string
    }
    Partitions []int
    Shards     []struct {
        Name string
        Id   int
    }
}

Once you have that, you need to initialize the configuration:

if err := envconfig.Init(&conf); err != nil {
    log.Fatalln(err)
}

Then it's just a matter of setting the environment variables when calling your binary:

ADDR=localhost PORT=6379 AUTH_KEY=foobar ./mybinary

Layout of the conf struct

Your conf struct must follow the following rules:

- no unexported fields by default (can turn off with Options.AllowUnexported)
- only supported types (no map fields for example)

Naming of the keys

By default, envconfig generates all possible keys based on the field chain according to a flexible naming scheme.

The field chain is how you access your field in the configuration struct. For example:

var conf struct {
    Shard struct {
        Name string
    }
}

With that struct, you access the name field via the chain *Shard.Name*

The default naming scheme takes that and transforms it into the following:

- SHARD_NAME
- shard_name

It can handles more complicated cases, with multiple words in one field name. It needs to be in the correct case though, for example:

var conf struct {
    Cassandra struct {
        SSLCert string
        SslKey  string
    }
}

With that struct, you access the name field via the chain *Cassandra.SSLCert* or *Cassandra.SslKey*

The default naming scheme takes that and transforms it into the following:

- CASSANDRA_SSL_CERT, cassandra_ssl_cert, CASSANDRA_SSLCERT, cassandra_sslcert
- CASSANDRA_SSL_KEY, cassandra_ssl_key, CASSANDRA_SSLKEY, cassandra_sslkey

And, if that is not good enough for you, you always have the option to use a custom key:

var conf struct {
    Cassandra struct {
        Name string `envconfig:"cassandraMyName"`
    }
}

Now envconfig will only ever checks the environment variable _cassandraMyName_.

Content of the variables

There are three types of content for a single variable:

- for simple types, a single string representing the value, and parseable into the type.
- for slices or arrays, a comma-separated list of strings. Each string must be parseable into the element type of the slice or array.
- for structs, a comma-separated list of specially formatted strings representing structs.

Example of a valid slice value:

foo,bar,baz

The format for a struct is as follow:

- prefixed with {
- suffixed with }
- contains a comma-separated list of field values, in the order in which they are defined in the struct

Example of a valid struct value:

type MyStruct struct {
    Name    string
    Id      int
    Timeout time.Duration
}

{foobar,10,120s}

Example of a valid slice of struct values:

{foobar,10,120s},{barbaz,20,50s}

Special case for bytes slices

For bytes slices, you generally don't want to type out a comma-separated list of byte values.

For this use case, we support base64 encoded values.

Here's an example:

var conf struct {
    Data []byte
}

os.Setenv("DATA", "Rk9PQkFS")

This will decode DATA to FOOBAR and put that into conf.Data.

Optional values

Sometimes you don't absolutely need a value. Here's how we tell envconfig a value is optional:

var conf struct {
    Name string `envconfig:"optional"`
}

Skipped fields

Sometimes you want a field to be skipped entirely.

    var conf struct {
	Internal string `envconfig:"-"`
    }

Default values

Often times you have configuration keys which almost never changes, but you still want to be able to change them.

In such cases, you might want to provide a default value.

Here's to do this with envconfig:

var conf struct {
    Timeout time.Duration `envconfig:"default=1m"`
}

Combining options

You can of course combine multiple options. The syntax is simple enough, separate each option with a comma.

For example:

var conf struct {
    Timeout time.Duration `envconfig:"default=1m,myTimeout"`
}

This would give you the default timeout of 1 minute, and lookup the myTimeout environment variable.

Supported types

envconfig supports the following list of types:

- bool
- string
- intX
- uintX
- floatX
- time.Duration
- pointers to all of the above types

Notably, we don't (yet) support complex types simply because I had no use for it yet.

Custom unmarshaler

When the standard types are not enough, you will want to use a custom unmarshaler for your types.

You do this by implementing Unmarshaler on your type. Here's an example:

type connectionType uint

const (
    tlsConnection connectionType = iota
    insecureConnection
)

func (t *connectionType) Unmarshal(s string) error {
    switch s {
        case "tls":
            *t = tlsConnection
        case "insecure":
            *t = insecureConnection
        default:
            return fmt.Errorf("unable to unmarshal %s to a connection type", s)
    }

    return nil
}

Index

Examples

Package Files

doc.go envconfig.go slice.go

Variables

var (
    // ErrUnexportedField is the error returned by the Init* functions when a field of the config struct is not exported and the option AllowUnexported is not used.
    ErrUnexportedField = errors.New("envconfig: unexported field")
    // ErrNotAPointer is the error returned by the Init* functions when the configuration object is not a pointer.
    ErrNotAPointer = errors.New("envconfig: value is not a pointer")
    // ErrInvalidValueKind is the error returned by the Init* functions when the configuration object is not a struct.
    ErrInvalidValueKind = errors.New("envconfig: invalid value kind, only works on structs")
)

func Init Uses

func Init(conf interface{}) error

Init reads the configuration from environment variables and populates the conf object. conf must be a pointer

Code:

var conf struct {
    MySQL struct {
        Host     string
        Port     int
        Database struct {
            User     string
            Password string
            Name     string
        }
        Params struct {
            Charset string `envconfig:"-"`
        }
    }
    Log struct {
        Path   string `envconfig:"default=/var/log/mylog.log"`
        Rotate bool   `envconfig:"logRotate"`
    }
    NbWorkers int
    Timeout   time.Duration
    Cassandra struct {
        SSLCert string
        SSLKey  string
    }
}

os.Setenv("MYSQL_HOST", "localhost")
os.Setenv("MYSQL_PORT", "3306")
os.Setenv("MYSQL_DATABASE_USER", "root")
os.Setenv("MYSQL_DATABASE_PASSWORD", "foobar")
os.Setenv("MYSQL_DATABASE_NAME", "default")
os.Setenv("logRotate", "true")
os.Setenv("NBWORKERS", "10")
os.Setenv("TIMEOUT", "120s")
os.Setenv("CASSANDRA_SSL_CERT", "/etc/cassandra/ssl.crt")
os.Setenv("CASSANDRA_SSL_KEY", "/etc/cassandra/ssl.key")

if err := envconfig.Init(&conf); err != nil {
    fmt.Printf("err=%s\n", err)
}

fmt.Println(conf.MySQL.Database.User)
fmt.Println(conf.Log.Rotate)
fmt.Println(conf.Timeout)
fmt.Println(conf.Log.Path)
fmt.Println(conf.Cassandra.SSLCert)
fmt.Println(conf.Cassandra.SSLKey)

Output:

root
true
2m0s
/var/log/mylog.log
/etc/cassandra/ssl.crt
/etc/cassandra/ssl.key

func InitWithOptions Uses

func InitWithOptions(conf interface{}, opts Options) error

InitWithOptions reads the configuration from environment variables and populates the conf object. conf must be a pointer.

func InitWithPrefix Uses

func InitWithPrefix(conf interface{}, prefix string) error

InitWithPrefix reads the configuration from environment variables and populates the conf object. conf must be a pointer. Each key read will be prefixed with the prefix string.

Code:

var conf struct {
    Name string
}

os.Setenv("NAME", "")
os.Setenv("FOO_NAME", "")

os.Setenv("NAME", "foobar")

err := envconfig.InitWithPrefix(&conf, "FOO")
fmt.Println(err)

os.Setenv("FOO_NAME", "foobar")
err = envconfig.InitWithPrefix(&conf, "FOO")
fmt.Println(err)

fmt.Println(conf.Name)

Output:

envconfig: keys FOO_NAME, foo_name not found
<nil>
foobar

type Options Uses

type Options struct {
    // Prefix allows specifying a prefix for each key.
    Prefix string

    // AllOptional determines whether to not throw errors by default for any key
    // that is not found. AllOptional=true means errors will not be thrown.
    AllOptional bool

    // LeaveNil specifies whether to not create new pointers for any pointer fields
    // found within the passed config. Rather, it behaves such that if and only if
    // there is a) a non-empty field in the value or b) a non-empty value that
    // the pointer is pointing to will a new pointer be created. By default,
    // LeaveNil=false will create all pointers in all structs if they are nil.
    //
    //	var X struct {
    //		A *struct{
    //			B string
    //		}
    //	}
    //	envconfig.InitWithOptions(&X, Options{LeaveNil: true})
    //
    // $ ./program
    //
    // X.A == nil
    //
    // $ A_B="string" ./program
    //
    // X.A.B="string" // A will not be nil
    LeaveNil bool

    // AllowUnexported allows unexported fields to be present in the passed config.
    AllowUnexported bool
}

Options is used to customize the behavior of envconfig. Use it with InitWithOptions.

type Unmarshaler Uses

type Unmarshaler interface {
    Unmarshal(s string) error
}

Unmarshaler is the interface implemented by objects that can unmarshal a environment variable string of themselves.

Package envconfig imports 13 packages (graph) and is imported by 24 packages. Updated 2019-06-13. Refresh now. Tools for package owners.