allow dynamic controller scrapes
This commit is contained in:
parent
1dd5b4761c
commit
17e7c8edb3
|
|
@ -46,11 +46,12 @@
|
||||||
version = "v1.6.0"
|
version = "v1.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7097829edd12fd7211fca0d29496b44f94ef9e6d72f88fb64f3d7b06315818ad"
|
digest = "1:eb04f69c8991e52eff33c428bd729e04208bf03235be88e4df0d88497c6861b9"
|
||||||
name = "github.com/prometheus/client_golang"
|
name = "github.com/prometheus/client_golang"
|
||||||
packages = [
|
packages = [
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"prometheus/internal",
|
"prometheus/internal",
|
||||||
|
"prometheus/promhttp",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "170205fb58decfd011f1550d4cfb737230d7ae4f"
|
revision = "170205fb58decfd011f1550d4cfb737230d7ae4f"
|
||||||
|
|
@ -99,11 +100,11 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:68fe4216878f16dd6ef33413365fbbe8d2eb781177c7adab874cfc752ce96a7e"
|
digest = "1:07f0cb66f649e51f9ef23441f8dfc34a73e7d9bf0832417abcbad578f1d8c8d6"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["windows"]
|
packages = ["windows"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "4a24b406529242041050cb1dec3e0e4c46a5f1b6"
|
revision = "af0d71d358abe0ba3594483a5d519f429dbae3e9"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:54742bef5cb29f706614c9edcfdeb29fb5992f26090f26ca955f575dddf54f9e"
|
digest = "1:54742bef5cb29f706614c9edcfdeb29fb5992f26090f26ca955f575dddf54f9e"
|
||||||
|
|
@ -113,14 +114,6 @@
|
||||||
revision = "961061d377655468e9da4a9333e71b9b77402470"
|
revision = "961061d377655468e9da4a9333e71b9b77402470"
|
||||||
version = "v0.0.1"
|
version = "v0.0.1"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:54742bef5cb29f706614c9edcfdeb29fb5992f26090f26ca955f575dddf54f9e"
|
|
||||||
name = "golift.io/config"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "961061d377655468e9da4a9333e71b9b77402470"
|
|
||||||
version = "v0.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:2883cea734f2766f41ff9c9d4aefccccc53e3d44f5c8b08893b9c218cf666722"
|
digest = "1:2883cea734f2766f41ff9c9d4aefccccc53e3d44f5c8b08893b9c218cf666722"
|
||||||
name = "golift.io/unifi"
|
name = "golift.io/unifi"
|
||||||
|
|
@ -143,10 +136,10 @@
|
||||||
input-imports = [
|
input-imports = [
|
||||||
"github.com/influxdata/influxdb1-client/v2",
|
"github.com/influxdata/influxdb1-client/v2",
|
||||||
"github.com/prometheus/client_golang/prometheus",
|
"github.com/prometheus/client_golang/prometheus",
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp",
|
||||||
"github.com/prometheus/common/version",
|
"github.com/prometheus/common/version",
|
||||||
"github.com/spf13/pflag",
|
"github.com/spf13/pflag",
|
||||||
"golift.io/cnfg",
|
"golift.io/cnfg",
|
||||||
"golift.io/config",
|
|
||||||
"golift.io/unifi",
|
"golift.io/unifi",
|
||||||
]
|
]
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
influx "github.com/influxdata/influxdb1-client/v2"
|
influx "github.com/influxdata/influxdb1-client/v2"
|
||||||
"golift.io/config"
|
"golift.io/cnfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -23,13 +23,13 @@ const (
|
||||||
|
|
||||||
// Config defines the data needed to store metrics in InfluxDB
|
// Config defines the data needed to store metrics in InfluxDB
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Interval config.Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval" yaml:"interval"`
|
Interval cnfg.Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval" yaml:"interval"`
|
||||||
Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"`
|
Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"`
|
||||||
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
||||||
URL string `json:"url,omitempty" toml:"url,omitempty" xml:"url" yaml:"url"`
|
URL string `json:"url,omitempty" toml:"url,omitempty" xml:"url" yaml:"url"`
|
||||||
User string `json:"user,omitempty" toml:"user,omitempty" xml:"user" yaml:"user"`
|
User string `json:"user,omitempty" toml:"user,omitempty" xml:"user" yaml:"user"`
|
||||||
Pass string `json:"pass,omitempty" toml:"pass,omitempty" xml:"pass" yaml:"pass"`
|
Pass string `json:"pass,omitempty" toml:"pass,omitempty" xml:"pass" yaml:"pass"`
|
||||||
DB string `json:"db,omitempty" toml:"db,omitempty" xml:"db" yaml:"db"`
|
DB string `json:"db,omitempty" toml:"db,omitempty" xml:"db" yaml:"db"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InfluxDB allows the data to be nested in the config file.
|
// InfluxDB allows the data to be nested in the config file.
|
||||||
|
|
@ -133,12 +133,12 @@ func (u *InfluxUnifi) setConfigDefaults() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.Config.Interval.Duration == 0 {
|
if u.Config.Interval.Duration == 0 {
|
||||||
u.Config.Interval = config.Duration{Duration: defaultInterval}
|
u.Config.Interval = cnfg.Duration{Duration: defaultInterval}
|
||||||
} else if u.Config.Interval.Duration < minimumInterval {
|
} else if u.Config.Interval.Duration < minimumInterval {
|
||||||
u.Config.Interval = config.Duration{Duration: minimumInterval}
|
u.Config.Interval = cnfg.Duration{Duration: minimumInterval}
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Config.Interval = config.Duration{Duration: u.Config.Interval.Duration.Round(time.Second)}
|
u.Config.Interval = cnfg.Duration{Duration: u.Config.Interval.Duration.Round(time.Second)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportMetrics batches all device and client data into influxdb data points.
|
// ReportMetrics batches all device and client data into influxdb data points.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,49 @@ func (u *InputUnifi) isNill(c *Controller) bool {
|
||||||
return c.Unifi == nil
|
return c.Unifi == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *InputUnifi) dynamicController(url string) (*poller.Metrics, bool, error) {
|
||||||
|
c := u.Config.Default // copy defaults into new controller
|
||||||
|
c.Name = url
|
||||||
|
c.URL = url
|
||||||
|
|
||||||
|
u.Logf("Authenticating to Dynamic UniFi Controller: %s", url)
|
||||||
|
|
||||||
|
if err := u.getUnifi(&c); err != nil {
|
||||||
|
return nil, false, fmt.Errorf("authenticating to %s: %v", url, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics := &poller.Metrics{}
|
||||||
|
ok, err := u.appendController(&c, metrics)
|
||||||
|
|
||||||
|
return metrics, ok, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *InputUnifi) appendController(c *Controller, metrics *poller.Metrics) (bool, error) {
|
||||||
|
m, err := u.collectController(c)
|
||||||
|
if err != nil || m == nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.Sites = append(metrics.Sites, m.Sites...)
|
||||||
|
metrics.Clients = append(metrics.Clients, m.Clients...)
|
||||||
|
metrics.IDSList = append(metrics.IDSList, m.IDSList...)
|
||||||
|
|
||||||
|
if m.Devices == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if metrics.Devices == nil {
|
||||||
|
metrics.Devices = &unifi.Devices{}
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.UAPs = append(metrics.UAPs, m.UAPs...)
|
||||||
|
metrics.USGs = append(metrics.USGs, m.USGs...)
|
||||||
|
metrics.USWs = append(metrics.USWs, m.USWs...)
|
||||||
|
metrics.UDMs = append(metrics.UDMs, m.UDMs...)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *InputUnifi) collectController(c *Controller) (*poller.Metrics, error) {
|
func (u *InputUnifi) collectController(c *Controller) (*poller.Metrics, error) {
|
||||||
if u.isNill(c) {
|
if u.isNill(c) {
|
||||||
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,13 @@ import (
|
||||||
"golift.io/unifi"
|
"golift.io/unifi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultURL = "https://127.0.0.1:8443"
|
||||||
|
defaultUser = "unifipoller"
|
||||||
|
defaultPass = "unifipollerp4$$w0rd"
|
||||||
|
defaultSite = "all"
|
||||||
|
)
|
||||||
|
|
||||||
// InputUnifi contains the running data.
|
// InputUnifi contains the running data.
|
||||||
type InputUnifi struct {
|
type InputUnifi struct {
|
||||||
Config *Config `json:"unifi" toml:"unifi" xml:"unifi" yaml:"unifi"`
|
Config *Config `json:"unifi" toml:"unifi" xml:"unifi" yaml:"unifi"`
|
||||||
|
|
@ -36,7 +43,9 @@ type Controller struct {
|
||||||
// Config contains our configuration data
|
// Config contains our configuration data
|
||||||
type Config struct {
|
type Config struct {
|
||||||
sync.RWMutex // locks the Unifi struct member when re-authing to unifi.
|
sync.RWMutex // locks the Unifi struct member when re-authing to unifi.
|
||||||
|
Default Controller `json:"defaults" toml:"defaults" xml:"default" yaml:"defaults"`
|
||||||
Disable bool `json:"disable" toml:"disable" xml:"disable" yaml:"disable"`
|
Disable bool `json:"disable" toml:"disable" xml:"disable" yaml:"disable"`
|
||||||
|
Dynamic bool `json:"dynamic" toml:"dynamic" xml:"dynamic" yaml:"dynamic"`
|
||||||
Controllers []*Controller `json:"controllers" toml:"controller" xml:"controller" yaml:"controllers"`
|
Controllers []*Controller `json:"controllers" toml:"controller" xml:"controller" yaml:"controllers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,6 +156,28 @@ func (u *InputUnifi) dumpSitesJSON(c *Controller, path, name string, sites unifi
|
||||||
return allJSON, nil
|
return allJSON, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *InputUnifi) setDefaults(c *Controller) {
|
||||||
|
if c.URL == "" {
|
||||||
|
c.URL = defaultURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Name == "" {
|
||||||
|
c.Name = c.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Pass == "" {
|
||||||
|
c.Pass = defaultPass
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.User == "" {
|
||||||
|
c.User = defaultUser
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Sites) < 1 {
|
||||||
|
c.Sites = []string{defaultSite}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StringInSlice returns true if a string is in a slice.
|
// StringInSlice returns true if a string is in a slice.
|
||||||
func StringInSlice(str string, slice []string) bool {
|
func StringInSlice(str string, slice []string) bool {
|
||||||
for _, s := range slice {
|
for _, s := range slice {
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,15 @@ func (u *InputUnifi) Initialize(l poller.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(u.Config.Controllers) < 1 {
|
if u.setDefaults(&u.Config.Default); len(u.Config.Controllers) < 1 {
|
||||||
return fmt.Errorf("no unifi controllers defined for unifi input")
|
new := u.Config.Default // copy defaults.
|
||||||
|
u.Config.Controllers = []*Controller{&new}
|
||||||
}
|
}
|
||||||
|
|
||||||
u.Logger = l
|
u.Logger = l
|
||||||
|
|
||||||
for i, c := range u.Config.Controllers {
|
for _, c := range u.Config.Controllers {
|
||||||
if c.Name == "" {
|
u.setDefaults(c)
|
||||||
u.Config.Controllers[i].Name = c.URL
|
|
||||||
}
|
|
||||||
|
|
||||||
switch err := u.getUnifi(c); err {
|
switch err := u.getUnifi(c); err {
|
||||||
case nil:
|
case nil:
|
||||||
|
|
@ -48,12 +47,12 @@ func (u *InputUnifi) Initialize(l poller.Logger) error {
|
||||||
|
|
||||||
// Metrics grabs all the measurements from a UniFi controller and returns them.
|
// Metrics grabs all the measurements from a UniFi controller and returns them.
|
||||||
func (u *InputUnifi) Metrics() (*poller.Metrics, bool, error) {
|
func (u *InputUnifi) Metrics() (*poller.Metrics, bool, error) {
|
||||||
return u.MetricsFrom(poller.Filter{})
|
return u.MetricsFrom(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsFrom grabs all the measurements from a UniFi controller and returns them.
|
// MetricsFrom grabs all the measurements from a UniFi controller and returns them.
|
||||||
func (u *InputUnifi) MetricsFrom(filter poller.Filter) (*poller.Metrics, bool, error) {
|
func (u *InputUnifi) MetricsFrom(filter *poller.Filter) (*poller.Metrics, bool, error) {
|
||||||
if u.Config.Disable {
|
if u.Config.Disable || filter == nil || filter.Term == "" {
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,49 +60,36 @@ func (u *InputUnifi) MetricsFrom(filter poller.Filter) (*poller.Metrics, bool, e
|
||||||
metrics := &poller.Metrics{}
|
metrics := &poller.Metrics{}
|
||||||
ok := false
|
ok := false
|
||||||
|
|
||||||
|
// Check if the request is for an existing, configured controller.
|
||||||
for _, c := range u.Config.Controllers {
|
for _, c := range u.Config.Controllers {
|
||||||
if filter.Term != "" && c.Name != filter.Term {
|
if !strings.EqualFold(c.Name, filter.Term) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := u.collectController(c)
|
exists, err := u.appendController(c, metrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if m == nil {
|
if exists {
|
||||||
continue
|
ok = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = true
|
|
||||||
|
|
||||||
metrics.Sites = append(metrics.Sites, m.Sites...)
|
|
||||||
metrics.Clients = append(metrics.Clients, m.Clients...)
|
|
||||||
metrics.IDSList = append(metrics.IDSList, m.IDSList...)
|
|
||||||
|
|
||||||
if m.Devices == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if metrics.Devices == nil {
|
|
||||||
metrics.Devices = &unifi.Devices{}
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics.UAPs = append(metrics.UAPs, m.UAPs...)
|
|
||||||
metrics.USGs = append(metrics.USGs, m.USGs...)
|
|
||||||
metrics.USWs = append(metrics.USWs, m.USWs...)
|
|
||||||
metrics.UDMs = append(metrics.UDMs, m.UDMs...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return metrics, ok, fmt.Errorf(strings.Join(errs, ", "))
|
return metrics, ok, fmt.Errorf(strings.Join(errs, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.Config.Dynamic && !ok && strings.HasPrefix(filter.Term, "http") {
|
||||||
|
// Attempt to a dynamic metrics fetch from an unconfigured controller.
|
||||||
|
return u.dynamicController(filter.Term)
|
||||||
|
}
|
||||||
|
|
||||||
return metrics, ok, nil
|
return metrics, ok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawMetrics returns API output from the first configured unifi controller.
|
// RawMetrics returns API output from the first configured unifi controller.
|
||||||
func (u *InputUnifi) RawMetrics(filter poller.Filter) ([]byte, error) {
|
func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) {
|
||||||
c := u.Config.Controllers[0] // We could pull the controller number from the filter.
|
c := u.Config.Controllers[0] // We could pull the controller number from the filter.
|
||||||
if u.isNill(c) {
|
if u.isNill(c) {
|
||||||
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
u.Logf("Re-authenticating to UniFi Controller: %s", c.URL)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ func (u *UnifiPoller) DumpJSONPayload() (err error) {
|
||||||
u.Config.Quiet = true
|
u.Config.Quiet = true
|
||||||
|
|
||||||
split := strings.SplitN(u.Flags.DumpJSON, " ", 2)
|
split := strings.SplitN(u.Flags.DumpJSON, " ", 2)
|
||||||
filter := Filter{Type: split[0]}
|
filter := &Filter{Type: split[0]}
|
||||||
|
|
||||||
if len(split) > 1 {
|
if len(split) > 1 {
|
||||||
filter.Term = split[1]
|
filter.Term = split[1]
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ var (
|
||||||
|
|
||||||
// Input plugins must implement this interface.
|
// Input plugins must implement this interface.
|
||||||
type Input interface {
|
type Input interface {
|
||||||
Initialize(Logger) error // Called once on startup to initialize the plugin.
|
Initialize(Logger) error // Called once on startup to initialize the plugin.
|
||||||
Metrics() (*Metrics, bool, error) // Called every time new metrics are requested.
|
Metrics() (*Metrics, bool, error) // Called every time new metrics are requested.
|
||||||
MetricsFrom(Filter) (*Metrics, bool, error) // Called every time new metrics are requested.
|
MetricsFrom(*Filter) (*Metrics, bool, error) // Called every time new metrics are requested.
|
||||||
RawMetrics(Filter) ([]byte, error)
|
RawMetrics(*Filter) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputPlugin describes an input plugin's consumable interface.
|
// InputPlugin describes an input plugin's consumable interface.
|
||||||
|
|
@ -108,7 +108,7 @@ func (u *UnifiPoller) Metrics() (*Metrics, bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MetricsFrom aggregates all the measurements from all configured inputs and returns them.
|
// MetricsFrom aggregates all the measurements from all configured inputs and returns them.
|
||||||
func (u *UnifiPoller) MetricsFrom(filter Filter) (*Metrics, bool, error) {
|
func (u *UnifiPoller) MetricsFrom(filter *Filter) (*Metrics, bool, error) {
|
||||||
errs := []string{}
|
errs := []string{}
|
||||||
metrics := &Metrics{}
|
metrics := &Metrics{}
|
||||||
ok := false
|
ok := false
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ var (
|
||||||
// Output packages must implement this interface.
|
// Output packages must implement this interface.
|
||||||
type Collect interface {
|
type Collect interface {
|
||||||
Metrics() (*Metrics, bool, error)
|
Metrics() (*Metrics, bool, error)
|
||||||
MetricsFrom(Filter) (*Metrics, bool, error)
|
MetricsFrom(*Filter) (*Metrics, bool, error)
|
||||||
Logger
|
Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/prometheus/common/version"
|
"github.com/prometheus/common/version"
|
||||||
"golift.io/unifi"
|
"golift.io/unifi"
|
||||||
)
|
)
|
||||||
|
|
@ -77,6 +78,11 @@ type Report struct {
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type target struct {
|
||||||
|
*poller.Filter
|
||||||
|
*promUnifi
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
u := &promUnifi{Prometheus: &Prometheus{}}
|
u := &promUnifi{Prometheus: &Prometheus{}}
|
||||||
|
|
||||||
|
|
@ -103,6 +109,8 @@ func (u *promUnifi) Run(c poller.Collect) error {
|
||||||
u.Config.HTTPListen = defaultHTTPListen
|
u.Config.HTTPListen = defaultHTTPListen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
prometheus.MustRegister(version.NewCollector(u.Config.Namespace))
|
prometheus.MustRegister(version.NewCollector(u.Config.Namespace))
|
||||||
prometheus.MustRegister(&promUnifi{
|
prometheus.MustRegister(&promUnifi{
|
||||||
Collector: c,
|
Collector: c,
|
||||||
|
|
@ -115,8 +123,43 @@ func (u *promUnifi) Run(c poller.Collect) error {
|
||||||
})
|
})
|
||||||
c.Logf("Exporting Measurements for Prometheus at https://%s/metrics, namespace: %s",
|
c.Logf("Exporting Measurements for Prometheus at https://%s/metrics, namespace: %s",
|
||||||
u.Config.HTTPListen, u.Config.Namespace)
|
u.Config.HTTPListen, u.Config.Namespace)
|
||||||
|
mux.Handle("/metrics", promhttp.HandlerFor(
|
||||||
|
prometheus.DefaultGatherer, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError},
|
||||||
|
))
|
||||||
|
mux.HandleFunc("/scrape", u.ScrapeHandler)
|
||||||
|
|
||||||
return http.ListenAndServe(u.Config.HTTPListen, nil)
|
return http.ListenAndServe(u.Config.HTTPListen, mux)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScrapeHandler allows prometheus to scrape a single source, instead of all sources.
|
||||||
|
func (u *promUnifi) ScrapeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
t := &target{promUnifi: u, Filter: &poller.Filter{}}
|
||||||
|
if t.Filter.Type = r.URL.Query().Get("input"); t.Filter.Type == "" {
|
||||||
|
http.Error(w, `'input' parameter must be specified (try "unifi")`, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Filter.Term = r.URL.Query().Get("target"); t.Filter.Term == "" {
|
||||||
|
http.Error(w, "'target' parameter must be specified, configured name, or unconfigured url", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registry := prometheus.NewRegistry()
|
||||||
|
|
||||||
|
registry.MustRegister(t)
|
||||||
|
promhttp.HandlerFor(
|
||||||
|
registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError},
|
||||||
|
).ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe satisfies the prometheus Collector. This returns all of the
|
||||||
|
// metric descriptions that this packages produces.
|
||||||
|
func (t *target) Describe(ch chan<- *prometheus.Desc) {
|
||||||
|
t.promUnifi.Describe(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *target) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
t.promUnifi.collect(ch, t.Filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe satisfies the prometheus Collector. This returns all of the
|
// Describe satisfies the prometheus Collector. This returns all of the
|
||||||
|
|
@ -138,6 +181,10 @@ func (u *promUnifi) Describe(ch chan<- *prometheus.Desc) {
|
||||||
// Collect satisfies the prometheus Collector. This runs the input method to get
|
// Collect satisfies the prometheus Collector. This runs the input method to get
|
||||||
// the current metrics (from another package) then exports them for prometheus.
|
// the current metrics (from another package) then exports them for prometheus.
|
||||||
func (u *promUnifi) Collect(ch chan<- prometheus.Metric) {
|
func (u *promUnifi) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
u.collect(ch, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *promUnifi) collect(ch chan<- prometheus.Metric, filter *poller.Filter) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ok := false
|
ok := false
|
||||||
|
|
@ -145,7 +192,13 @@ func (u *promUnifi) Collect(ch chan<- prometheus.Metric) {
|
||||||
r := &Report{Config: u.Config, ch: make(chan []*metric, buffer), Start: time.Now()}
|
r := &Report{Config: u.Config, ch: make(chan []*metric, buffer), Start: time.Now()}
|
||||||
defer r.close()
|
defer r.close()
|
||||||
|
|
||||||
if r.Metrics, ok, err = u.Collector.Metrics(); err != nil {
|
if filter == nil {
|
||||||
|
r.Metrics, ok, err = u.Collector.Metrics()
|
||||||
|
} else {
|
||||||
|
r.Metrics, ok, err = u.Collector.MetricsFrom(filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
r.error(ch, prometheus.NewInvalidDesc(fmt.Errorf("metric fetch failed")), err)
|
r.error(ch, prometheus.NewInvalidDesc(fmt.Errorf("metric fetch failed")), err)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
"github.com/davidnewhall/unifi-poller/pkg/poller"
|
||||||
"golift.io/config"
|
"golift.io/cnfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// mysqlConfig represents the data that is unmarshalled from the up.conf config file for this plugins.
|
// mysqlConfig represents the data that is unmarshalled from the up.conf config file for this plugins.
|
||||||
type mysqlConfig struct {
|
type mysqlConfig struct {
|
||||||
Interval config.Duration `json:"interval" toml:"interval" xml:"interval" yaml:"interval"`
|
Interval cnfg.Duration `json:"interval" toml:"interval" xml:"interval" yaml:"interval"`
|
||||||
Host string `json:"host" toml:"host" xml:"host" yaml:"host"`
|
Host string `json:"host" toml:"host" xml:"host" yaml:"host"`
|
||||||
User string `json:"user" toml:"user" xml:"user" yaml:"user"`
|
User string `json:"user" toml:"user" xml:"user" yaml:"user"`
|
||||||
Pass string `json:"pass" toml:"pass" xml:"pass" yaml:"pass"`
|
Pass string `json:"pass" toml:"pass" xml:"pass" yaml:"pass"`
|
||||||
DB string `json:"db" toml:"db" xml:"db" yaml:"db"`
|
DB string `json:"db" toml:"db" xml:"db" yaml:"db"`
|
||||||
Table string `json:"table" toml:"table" xml:"table" yaml:"table"`
|
Table string `json:"table" toml:"table" xml:"table" yaml:"table"`
|
||||||
// Maps do not work with ENV VARIABLES yet, but may in the future.
|
// Maps do not work with ENV VARIABLES yet, but may in the future.
|
||||||
Fields []string `json:"fields" toml:"fields" xml:"field" yaml:"fields"`
|
Fields []string `json:"fields" toml:"fields" xml:"field" yaml:"fields"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue