diff --git a/config/config.go b/config/config.go new file mode 100644 index 00000000..e3fef11c --- /dev/null +++ b/config/config.go @@ -0,0 +1,82 @@ +// Copyright 2018 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "io/ioutil" + "os" + + "github.com/prometheus/common/log" + "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/yaml.v2" +) + +type getFlagger interface { + GetFlag(name string) *kingpin.FlagClause +} + +// Resolver represents a configuration file resolver for kingpin. +type Resolver struct { + flags map[string]string +} + +// NewResolver returns a Resolver structure. +func NewResolver(file string) (*Resolver, error) { + flags := map[string]string{} + log.Infof("Loading configuration file: %v", file) + if _, err := os.Stat(file); err != nil { + return nil, err + } + b, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + var m map[string]string + err = yaml.Unmarshal(b, &m) + if err != nil { + return nil, err + } + for k, v := range m { + if _, ok := flags[k]; !ok { + flags[k] = v + } + } + return &Resolver{flags: flags}, nil +} + +func (c *Resolver) setDefault(v getFlagger) { + for name, value := range c.flags { + f := v.GetFlag(name) + if f != nil { + f.Default(value) + } + } +} + +// Bind sets active flags with their default values from the configuration file(s). +func (c *Resolver) Bind(app *kingpin.Application, args []string) error { + // Parse the command line arguments to get the selected command. + pc, err := app.ParseContext(args) + if err != nil { + return err + } + + c.setDefault(app) + if pc.SelectedCommand != nil { + c.setDefault(pc.SelectedCommand) + } + + return nil +} diff --git a/exporter.go b/exporter.go index a776c605..0afcb651 100644 --- a/exporter.go +++ b/exporter.go @@ -18,6 +18,7 @@ import ( "github.com/StackExchange/wmi" "github.com/prometheus-community/windows_exporter/collector" + "github.com/prometheus-community/windows_exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/log" @@ -269,7 +270,11 @@ func initWbem() { func main() { var ( - app = kingpin.New("windows_exporter", "") + app = kingpin.New("windows_exporter", "") + configFile = app.Flag( + "config.file", + "YAML configuration file to use. Values set in this file will override flags.", + ).Default(os.ExpandEnv("$ProgramFiles\\windows_exporter\\config.yml")).String() listenAddress = app.Flag( "telemetry.addr", "host:port for exporter.", @@ -299,7 +304,26 @@ func main() { log.AddFlags(app) app.Version(version.Print("windows_exporter")) app.HelpFlag.Short('h') - app.Parse(os.Args[1:]) + + // Load values from configuration file(s). Executable flags must first be parsed, in order + // to load the specified file(s). + _, err := app.Parse(os.Args[1:]) + if err != nil { + log.Fatalf("%v\n", err) + } + resolver, err := config.NewResolver(*configFile) + if err != nil { + log.Fatalf("could not load config file: %v\n", err) + } + err = resolver.Bind(app, os.Args[1:]) + if err != nil { + log.Fatalf("%v\n", err) + } + // Parse flags once more to include those discovered in configuration file(s). + _, err = app.Parse(os.Args[1:]) + if err != nil { + log.Fatalf("%v\n", err) + } if *printCollectors { collectors := collector.Available() diff --git a/go.mod b/go.mod index 67e22961..9e6d9014 100644 --- a/go.mod +++ b/go.mod @@ -14,4 +14,5 @@ require ( github.com/prometheus/common v0.2.0 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b gopkg.in/alecthomas/kingpin.v2 v2.2.6 + gopkg.in/yaml.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index a53881ee..5679dbb9 100644 --- a/go.sum +++ b/go.sum @@ -69,4 +69,5 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=