From c220fc4babc89736e8f1498f3998056ba6495359 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 1 Oct 2020 09:20:42 -0500 Subject: [PATCH 01/25] Initial commit --- integrations/datadogunifi/.gitignore | 15 +++++++++++++++ integrations/datadogunifi/LICENSE | 21 +++++++++++++++++++++ integrations/datadogunifi/README.md | 2 ++ 3 files changed, 38 insertions(+) create mode 100644 integrations/datadogunifi/.gitignore create mode 100644 integrations/datadogunifi/LICENSE create mode 100644 integrations/datadogunifi/README.md diff --git a/integrations/datadogunifi/.gitignore b/integrations/datadogunifi/.gitignore new file mode 100644 index 00000000..66fd13c9 --- /dev/null +++ b/integrations/datadogunifi/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/integrations/datadogunifi/LICENSE b/integrations/datadogunifi/LICENSE new file mode 100644 index 00000000..f452416f --- /dev/null +++ b/integrations/datadogunifi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Cody Lee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/integrations/datadogunifi/README.md b/integrations/datadogunifi/README.md new file mode 100644 index 00000000..3cd5b7fa --- /dev/null +++ b/integrations/datadogunifi/README.md @@ -0,0 +1,2 @@ +# datadogunifi +UniFi Poller Output Plugin for DataDog From 575473d9f88f1995ffedbfcfad7987df0b11cc65 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 1 Oct 2020 09:22:13 -0500 Subject: [PATCH 02/25] add travis.yml and add go.mod --- integrations/datadogunifi/.travis.yml | 10 ++++++++++ integrations/datadogunifi/go.mod | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 integrations/datadogunifi/.travis.yml create mode 100644 integrations/datadogunifi/go.mod diff --git a/integrations/datadogunifi/.travis.yml b/integrations/datadogunifi/.travis.yml new file mode 100644 index 00000000..909e2741 --- /dev/null +++ b/integrations/datadogunifi/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: +- 1.14.x +- 1.15.x +before_install: + # download super-linter: golangci-lint +- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest +script: +- go test ./... +- golangci-lint run --enable-all diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod new file mode 100644 index 00000000..c25bf515 --- /dev/null +++ b/integrations/datadogunifi/go.mod @@ -0,0 +1,3 @@ +module github.com/platinummonkey/datadogunifi + +go 1.15 From ceeb63870e4d7993631e0933d332611d052fd6aa Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 1 Oct 2020 20:15:01 -0500 Subject: [PATCH 03/25] initial commit --- integrations/datadogunifi/.gitignore | 2 + integrations/datadogunifi/README.md | 1 + integrations/datadogunifi/clients.go | 6 + integrations/datadogunifi/datadog.go | 286 +++++++++++++++++++++++++++ integrations/datadogunifi/go.mod | 8 + integrations/datadogunifi/go.sum | 180 +++++++++++++++++ integrations/datadogunifi/site.go | 8 + 7 files changed, 491 insertions(+) create mode 100644 integrations/datadogunifi/clients.go create mode 100644 integrations/datadogunifi/datadog.go create mode 100644 integrations/datadogunifi/go.sum create mode 100644 integrations/datadogunifi/site.go diff --git a/integrations/datadogunifi/.gitignore b/integrations/datadogunifi/.gitignore index 66fd13c9..0ce503cb 100644 --- a/integrations/datadogunifi/.gitignore +++ b/integrations/datadogunifi/.gitignore @@ -11,5 +11,7 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +.vscode/ + # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/integrations/datadogunifi/README.md b/integrations/datadogunifi/README.md index 3cd5b7fa..4b3cf5ca 100644 --- a/integrations/datadogunifi/README.md +++ b/integrations/datadogunifi/README.md @@ -1,2 +1,3 @@ # datadogunifi + UniFi Poller Output Plugin for DataDog diff --git a/integrations/datadogunifi/clients.go b/integrations/datadogunifi/clients.go new file mode 100644 index 00000000..80fc027a --- /dev/null +++ b/integrations/datadogunifi/clients.go @@ -0,0 +1,6 @@ +package datadogunifi + +import ( + "github.com/unifi-poller/unifi" +) + diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go new file mode 100644 index 00000000..19fc981c --- /dev/null +++ b/integrations/datadogunifi/datadog.go @@ -0,0 +1,286 @@ +// Package datadogunifi provides the methods to turn UniFi measurements into Datadog +// data points with appropriate tags and fields. +package datadogunifi + +import ( + "crypto/tls" + "fmt" + "io/ioutil" + "log" + "strings" + "time" + + "github.com/DataDog/datadog-go/statsd" + "github.com/pkg/errors" + "github.com/unifi-poller/poller" + "github.com/unifi-poller/unifi" + "golift.io/cnfg" +) + +const ( + +) + +// Config defines the data needed to store metrics in Datadog. +type Config struct { + // Required Config + + // Disable when true disables this output plugin + Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"` + // Address determines how to talk to the Datadog agent + Address string `json:"address" toml:"address" xml:"address,attr" yaml:"address"` + + // Optional Statsd Options - mirrored from statsd.Options + + // Namespace to prepend to all metrics, events and service checks name. + Namespace *string `json:"namespace" toml:"namespace" xml:"namespace,attr" yaml:"namespace"` + // Tags are global tags to be applied to every metrics, events and service checks. + Tags []string `json:"tags" toml:"tags" xml:"tags,attr" yaml:"tags"` + // MaxBytesPerPayload is the maximum number of bytes a single payload will contain. + // The magic value 0 will set the option to the optimal size for the transport + // protocol used when creating the client: 1432 for UDP and 8192 for UDS. + MaxBytesPerPayload *int `json:"max_bytes_per_payload" toml:"max_bytes_per_payload" xml:"max_bytes_per_payload,attr" yaml:"max_bytes_per_payload"` + // MaxMessagesPerPayload is the maximum number of metrics, events and/or service checks a single payload will contain. + // This option can be set to `1` to create an unbuffered client. + MaxMessagesPerPayload *int `json:"max_messages_per_payload" toml:"max_messages_per_payload" xml:"max_messages_per_payload,attr" yaml:"max_messages_per_payload"` + // BufferPoolSize is the size of the pool of buffers in number of buffers. + // The magic value 0 will set the option to the optimal size for the transport + // protocol used when creating the client: 2048 for UDP and 512 for UDS. + BufferPoolSize *int `json:"buffer_pool_size" toml:"buffer_pool_size" xml:"buffer_pool_size,attr" yaml:"buffer_pool_size"` + // BufferFlushInterval is the interval after which the current buffer will get flushed. + BufferFlushInterval *time.Duration `json:"buffer_flush_interval" toml:"buffer_flush_interval" xml:"buffer_flush_interval,attr" yaml:"buffer_flush_interval"` + // BufferShardCount is the number of buffer "shards" that will be used. + // Those shards allows the use of multiple buffers at the same time to reduce + // lock contention. + BufferShardCount *int `json:"buffer_shard_count" toml:"buffer_shard_count" xml:"buffer_shard_count,attr" yaml:"buffer_shard_count"` + // SenderQueueSize is the size of the sender queue in number of buffers. + // The magic value 0 will set the option to the optimal size for the transport + // protocol used when creating the client: 2048 for UDP and 512 for UDS. + SenderQueueSize *int `json:"sender_queue_size" toml:"sender_queue_size" xml:"sender_queue_size,attr" yaml:"sender_queue_size"` + // WriteTimeoutUDS is the timeout after which a UDS packet is dropped. + WriteTimeoutUDS *time.Duration `json:"write_timeout_uds" toml:"write_timeout_uds" xml:"write_timeout_uds,attr" yaml:"write_timeout_uds"` + // Telemetry is a set of metrics automatically injected by the client in the + // dogstatsd stream to be able to monitor the client itself. + Telemetry *bool `json:"telemetry" toml:"telemetry" xml:"telemetry,attr" yaml:"telemetry"` + // ReceiveMode determins the behavior of the client when receiving to many + // metrics. The client will either drop the metrics if its buffers are + // full (ChannelMode mode) or block the caller until the metric can be + // handled (MutexMode mode). By default the client will MutexMode. This + // option should be set to ChannelMode only when use under very high + // load. + // + // MutexMode uses a mutex internally which is much faster than + // channel but causes some lock contention when used with a high number + // of threads. Mutex are sharded based on the metrics name which + // limit mutex contention when goroutines send different metrics. + // + // ChannelMode: uses channel (of ChannelModeBufferSize size) to send + // metrics and drop metrics if the channel is full. Sending metrics in + // this mode is slower that MutexMode (because of the channel), but + // will not block the application. This mode is made for application + // using many goroutines, sending the same metrics at a very high + // volume. The goal is to not slow down the application at the cost of + // dropping metrics and having a lower max throughput. + ReceiveMode *statsd.ReceivingMode `json:"receive_mode" toml:"receive_mode" xml:"receive_mode,attr" yaml:"receive_mode"` + // ChannelModeBufferSize is the size of the channel holding incoming metrics + ChannelModeBufferSize *int `json:"channel_mode_buffer_size" toml:"channel_mode_buffer_size" xml:"channel_mode_buffer_size,attr" yaml:"channel_mode_buffer_size"` + // AggregationFlushInterval is the interval for the aggregator to flush metrics + AggregationFlushInterval *time.Duration `json:"aggregation_flush_interval" toml:"aggregation_flush_interval" xml:"aggregation_flush_interval,attr" yaml:"aggregation_flush_interval"` + // [beta] Aggregation enables/disables client side aggregation + Aggregation *bool `json:"aggregation" toml:"aggregation" xml:"aggregation,attr" yaml:"aggregation"` + // TelemetryAddr specify a different endpoint for telemetry metrics. + TelemetryAddr *string `json:"telemetry_address" toml:"telemetry_address" xml:"telemetry_address,attr" yaml:"telemetry_address"` +} + +// Datadog allows the data to be context aware with configuration +type Datadog struct { + *Config `json:"datadog" toml:"datadog" xml:"datadog" yaml:"datadog"` + options []statsd.Option +} + +// DatadogUnifi is returned by New() after you provide a Config. +type DatadogUnifi struct { + Collector poller.Collect + datadog statsd.ClientInterface + LastCheck time.Time + *Datadog +} + +type metric struct { + Name string + Tags map[string]string + Fields map[string]interface{} +} + +func init() { // nolint: gochecknoinits + u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now()} + + poller.NewOutput(&poller.Output{ + Name: "datadog", + Config: u.Datadog, + Method: u.Run, + }) +} + +func (u *DatadogUnifi) setConfigDefaults() { + if u.Interval.Duration == 0 { + u.Interval = cnfg.Duration{Duration: defaultInterval} + } else if u.Interval.Duration < minimumInterval { + u.Interval = cnfg.Duration{Duration: minimumInterval} + } + + u.Interval = cnfg.Duration{Duration: u.Interval.Duration.Round(time.Second)} + + u.options = make([]statsd.Option) + + if u.Namespace != nil { + u.options = append(u.options, statsd.WithNamespace(*u.Namespace)) + } + if u.Tags != nil && len(u.Tags) > 0 { + u.options = append(u.options, statsd.WithTags(u.Tags)) + } + +} + + +// Run runs a ticker to poll the unifi server and update Datadog. +func (u *DatadogUnifi) Run(c poller.Collect) error { + if u.Config == nil || u.Disable { + c.Logf("DataDog config is missing (or disabled): Datadog output is disabled!") + return nil + } + + u.Collector = c + u.setConfigDefaults() + + u.datadog, err := statsd.New(u.Address, u.options...) + if err != nil { + return err + } + + u.PollController() + + return nil +} + + +// PollController runs fover, polling UniFi and pushing to Datadog +// This is started by Run() or RunBoth() after everything is validated. +func (u *DatadogUnifi) PollController() { + interval := u.Interval.Round(time.Second) + ticker := time.NewTicker(interval) + log.Printf("[INFO] Everything checks out! Poller started, Datadog interval: %v", interval) + + for u.LastCheck = range ticker.C { + metrics, ok, collectErr := u.Collector.Metrics() + if collectErr != nil { + u.Collector.LogErrorf("metric fetch for Datadog failed: %v", collectErr) + + if !ok { + continue + } + } + + report, err := u.ReportMetrics(metrics) + if err != nil { + // Is the agent down? + u.Collector.LogErrorf("%v", err) + continue + } + + report.error(collectErr) + u.LogDatadogReport(report) + } +} + +// ReportMetrics batches all device and client data into datadog data points. +// Call this after you've collected all the data you care about. +// Returns an error if datadog statsd calls fail, otherwise returns a report. +func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) { + r := &Report{Metrics: m, ch: make(chan *metric), Start: time.Now()} + + return r, nil +} + + +// collect runs in a go routine and batches all the points. +func (u *InfluxUnifi) collect(r report, ch chan *metric) { + for m := range ch { + pt, err := influx.NewPoint(m.Table, m.Tags, m.Fields, r.metrics().TS) + if err == nil { + r.batch(m, pt) + } + + r.error(err) + r.done() + } +} + +// loopPoints kicks off 3 or 7 go routines to process metrics and send them +// to the collect routine through the metric channel. +func (u *DatadogUnifi) loopPoints(r report) { + m := r.metrics() + + for _, s := range m.SitesDPI { + u.batchSiteDPI(r, s) + } + + for _, s := range m.Sites { + u.batchSite(r, s) + } + + appTotal := make(totalsDPImap) + catTotal := make(totalsDPImap) + + for _, s := range m.ClientsDPI { + u.batchClientDPI(r, s, appTotal, catTotal) + } + + reportClientDPItotals(r, appTotal, catTotal) + + for _, s := range m.Clients { + u.batchClient(r, s) + } + + for _, s := range m.IDSList { + u.batchIDS(r, s) + } + + u.loopDevicePoints(r) +} + +func (u *DatadogUnifi) loopDevicePoints(r report) { + m := r.metrics() + if m.Devices == nil { + m.Devices = &unifi.Devices{} + return + } + + for _, s := range m.UAPs { + u.batchUAP(r, s) + } + + for _, s := range m.USGs { + u.batchUSG(r, s) + } + + for _, s := range m.USWs { + u.batchUSW(r, s) + } + + for _, s := range m.UDMs { + u.batchUDM(r, s) + } +} + +// LogInfluxReport writes a log message after exporting to influxdb. +func (u *DatadogUnifi) LogDatadogReport(r *Report) { + m := r.Metrics + idsMsg := fmt.Sprintf("IDS Events: %d, ", len(m.IDSList)) + + u.Collector.Logf("UniFi Metrics Recorded. Sites: %d, Clients: %d, "+ + "UAP: %d, USG/UDM: %d, USW: %d, %sPoints: %d, Fields: %d, Errs: %d, Elapsed: %v", + len(m.Sites), len(m.Clients), len(m.UAPs), + len(m.UDMs)+len(m.USGs), len(m.USWs), idsMsg, r.Total, + r.Fields, len(r.Errors), r.Elapsed.Round(time.Millisecond)) +} diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index c25bf515..f43d2128 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -1,3 +1,11 @@ module github.com/platinummonkey/datadogunifi go 1.15 + +require ( + github.com/DataDog/datadog-go v4.0.0+incompatible + github.com/pkg/errors v0.9.1 + github.com/unifi-poller/poller v0.0.7 + github.com/unifi-poller/unifi v0.0.6 + golift.io/cnfg v0.0.6 +) diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum new file mode 100644 index 00000000..43175f3c --- /dev/null +++ b/integrations/datadogunifi/go.sum @@ -0,0 +1,180 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/datadog-go v4.0.0+incompatible h1:Dq8Dr+4sV1gBO1sHDWdW+4G+PdsA+YSJOK925MxrrCY= +github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= +github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/unifi-poller/poller v0.0.7 h1:waSPusZd7yPz1zKJgxPSTwjhIUzA+qj8PwVyfLSLjns= +github.com/unifi-poller/poller v0.0.7/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= +github.com/unifi-poller/unifi v0.0.4/go.mod h1:bTUtctrf56aapjKH+L+98eThBaVFbQXw5iNGZI0g/+E= +github.com/unifi-poller/unifi v0.0.6 h1:/nvb4KiB3uwPNh+CTKOZqGhT4K/q9NBjeo0H+YNT224= +github.com/unifi-poller/unifi v0.0.6/go.mod h1:uqBaNCon8FTw6nwGsAYHz/HwBgEYepS0XB5XW+OdBts= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c h1:38q6VNPWR010vN82/SB121GujZNIfAUb4YttE2rhGuc= +golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golift.io/cnfg v0.0.5/go.mod h1:ScFDIJg/rJGHbRaed/i7g1lBhywEjB0JiP2uZr3xC3A= +golift.io/cnfg v0.0.6 h1:7tlP31gKsrGDEfPZmDTDQus8wOzjG91FtuAdGghoB64= +golift.io/cnfg v0.0.6/go.mod h1:F61j5OO4gwOwhJfoquyOEa6idDjbMj4P9KAPJAM4ZLM= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +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/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/integrations/datadogunifi/site.go b/integrations/datadogunifi/site.go new file mode 100644 index 00000000..da3f1b80 --- /dev/null +++ b/integrations/datadogunifi/site.go @@ -0,0 +1,8 @@ +package datadogunifi + +import ( + "github.com/unifi-poller/unifi" +) + +// batchSite generates Unifi Sites' datapoints for Datadog. +// These points can be passed directly to datadog From 51916c19e74a32d2f77187929f2948edd1581a2c Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sun, 11 Oct 2020 11:32:45 -0500 Subject: [PATCH 04/25] all stats should be reporting --- integrations/datadogunifi/clients.go | 162 ++++++++++++++++++++++ integrations/datadogunifi/datadog.go | 139 +++++++++++-------- integrations/datadogunifi/ids.go | 31 +++++ integrations/datadogunifi/points.go | 21 +++ integrations/datadogunifi/report.go | 76 ++++++++++ integrations/datadogunifi/site.go | 76 +++++++++- integrations/datadogunifi/uap.go | 199 +++++++++++++++++++++++++++ integrations/datadogunifi/udm.go | 141 +++++++++++++++++++ integrations/datadogunifi/usg.go | 145 +++++++++++++++++++ integrations/datadogunifi/usw.go | 119 ++++++++++++++++ 10 files changed, 1047 insertions(+), 62 deletions(-) create mode 100644 integrations/datadogunifi/ids.go create mode 100644 integrations/datadogunifi/points.go create mode 100644 integrations/datadogunifi/report.go create mode 100644 integrations/datadogunifi/uap.go create mode 100644 integrations/datadogunifi/udm.go create mode 100644 integrations/datadogunifi/usg.go create mode 100644 integrations/datadogunifi/usw.go diff --git a/integrations/datadogunifi/clients.go b/integrations/datadogunifi/clients.go index 80fc027a..91070964 100644 --- a/integrations/datadogunifi/clients.go +++ b/integrations/datadogunifi/clients.go @@ -4,3 +4,165 @@ import ( "github.com/unifi-poller/unifi" ) +// reportClient generates Unifi Client datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *DatadogUnifi) reportClient(r report, s *unifi.Client) { // nolint: funlen + tags := []string{ + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("ap_name", s.ApName), + tag("gw_name", s.GwName), + tag("sw_name", s.SwName), + tag("oui", s.Oui), + tag("radio_name", s.RadioName), + tag("radio", s.Radio), + tag("radio_proto", s.RadioProto), + tag("name", s.Name), + tag("fixed_ip", s.FixedIP), + tag("sw_port", s.SwPort.Txt), + tag("os_class", s.OsClass.Txt), + tag("os_name", s.OsName.Txt), + tag("dev_cat", s.DevCat.Txt), + tag("dev_id", s.DevID.Txt), + tag("dev_vendor", s.DevVendor.Txt), + tag("dev_family", s.DevFamily.Txt), + tag("is_wired", s.IsWired.Txt), + tag("is_guest", s.IsGuest.Txt), + tag("use_fixedip", s.UseFixedIP.Txt), + tag("channel", s.Channel.Txt), + tag("vlan", s.Vlan.Txt), + tag("hostname", s.Name), + tag("radio_desc", s.RadioDescription), + tag("ip", s.IP), + tag("essid", s.Essid), + tag("bssid", s.Bssid), + } + + data := map[string]float64{ + "anomalies": float64(s.Anomalies), + "channel": s.Channel.Val, + "satisfaction": s.Satisfaction.Val, + "bytes_r": float64(s.BytesR), + "ccq": float64(s.Ccq), + "noise": float64(s.Noise), + "roam_count": float64(s.RoamCount), + "rssi": float64(s.Rssi), + "rx_bytes": float64(s.RxBytes), + "rx_bytes_r": float64(s.RxBytesR), + "rx_packets": float64(s.RxPackets), + "rx_rate": float64(s.RxRate), + "signal": float64(s.Signal), + "tx_bytes": float64(s.TxBytes), + "tx_bytes_r": float64(s.TxBytesR), + "tx_packets": float64(s.TxPackets), + "tx_retries": float64(s.TxRetries), + "tx_power": float64(s.TxPower), + "tx_rate": float64(s.TxRate), + "uptime": float64(s.Uptime), + "wifi_tx_attempts": float64(s.WifiTxAttempts), + "wired-rx_bytes": float64(s.WiredRxBytes), + "wired-rx_bytes-r": float64(s.WiredRxBytesR), + "wired-rx_packets": float64(s.WiredRxPackets), + "wired-tx_bytes": float64(s.WiredTxBytes), + "wired-tx_bytes-r": float64(s.WiredTxBytesR), + "wired-tx_packets": float64(s.WiredTxPackets), + } + metricName := metricNamespace("clients") + reportGaugeForMap(r, metricName, data, tags) +} + +// totalsDPImap: controller, site, name (app/cat name), dpi. +type totalsDPImap map[string]map[string]map[string]unifi.DPIData + +func (u *DatadogUnifi) reportClientDPI(r report, s *unifi.DPITable, appTotal, catTotal totalsDPImap) { + for _, dpi := range s.ByApp { + category := unifi.DPICats.Get(dpi.Cat) + application := unifi.DPIApps.GetApp(dpi.Cat, dpi.App) + fillDPIMapTotals(appTotal, application, s.SourceName, s.SiteName, dpi) + fillDPIMapTotals(catTotal, category, s.SourceName, s.SiteName, dpi) + + tags := []string{ + tag("category", category), + tag("application", application), + tag("name", s.Name), + tag("mac", s.MAC), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + } + data := map[string]float64{ + "tx_packets": float64(dpi.TxPackets), + "rx_packets": float64(dpi.RxPackets), + "tx_bytes": float64(dpi.TxBytes), + "rx_bytes": float64(dpi.RxBytes), + } + metricName := metricNamespace("clientdpi") + reportGaugeForMap(r, metricName, data, tags) + } +} + +// fillDPIMapTotals fills in totals for categories and applications. maybe clients too. +// This allows less processing in InfluxDB to produce total transfer data per cat or app. +func fillDPIMapTotals(m totalsDPImap, name, controller, site string, dpi unifi.DPIData) { + if m[controller] == nil { + m[controller] = make(map[string]map[string]unifi.DPIData) + } + + if m[controller][site] == nil { + m[controller][site] = make(map[string]unifi.DPIData) + } + + existing := m[controller][site][name] + existing.TxPackets += dpi.TxPackets + existing.RxPackets += dpi.RxPackets + existing.TxBytes += dpi.TxBytes + existing.RxBytes += dpi.RxBytes + m[controller][site][name] = existing +} + +func reportClientDPItotals(r report, appTotal, catTotal totalsDPImap) { + type all []struct { + kind string + val totalsDPImap + } + + // This produces 7000+ metrics per site. Disabled for now. + if appTotal != nil { + appTotal = nil + } + + // This can allow us to aggregate other data types later, like `name` or `mac`, or anything else unifi adds. + a := all{ + // This produces 7000+ metrics per site. Disabled for now. + { + kind: "application", + val: appTotal, + }, + { + kind: "category", + val: catTotal, + }, + } + + for _, k := range a { + for controller, s := range k.val { + for site, c := range s { + for name, m := range c { + tags := []string{ + tag("site_name", site), + tag("source", controller), + tag("name", name), + } + data := map[string]float64{ + "tx_packets": float64(m.TxPackets), + "rx_packets": float64(m.RxPackets), + "tx_bytes": float64(m.TxBytes), + "rx_bytes": float64(m.RxBytes), + } + metricName := metricNamespace("clientdpi.totals") + reportGaugeForMap(r, metricName, data, tags) + } + } + } + } +} diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 19fc981c..4f9e4be7 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -3,35 +3,35 @@ package datadogunifi import ( - "crypto/tls" "fmt" - "io/ioutil" "log" - "strings" "time" "github.com/DataDog/datadog-go/statsd" - "github.com/pkg/errors" "github.com/unifi-poller/poller" "github.com/unifi-poller/unifi" "golift.io/cnfg" ) const ( - + defaultInterval = 30 * time.Second + minimumInterval = 10 * time.Second ) // Config defines the data needed to store metrics in Datadog. type Config struct { // Required Config + // Interval controls the collection and reporting interval + Interval cnfg.Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval,omitempty" yaml:"interval,omitempty"` + // Disable when true disables this output plugin Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"` // Address determines how to talk to the Datadog agent - Address string `json:"address" toml:"address" xml:"address,attr" yaml:"address"` - + Address string `json:"address" toml:"address" xml:"address,attr" yaml:"address"` + // Optional Statsd Options - mirrored from statsd.Options - + // Namespace to prepend to all metrics, events and service checks name. Namespace *string `json:"namespace" toml:"namespace" xml:"namespace,attr" yaml:"namespace"` // Tags are global tags to be applied to every metrics, events and service checks. @@ -48,7 +48,7 @@ type Config struct { // protocol used when creating the client: 2048 for UDP and 512 for UDS. BufferPoolSize *int `json:"buffer_pool_size" toml:"buffer_pool_size" xml:"buffer_pool_size,attr" yaml:"buffer_pool_size"` // BufferFlushInterval is the interval after which the current buffer will get flushed. - BufferFlushInterval *time.Duration `json:"buffer_flush_interval" toml:"buffer_flush_interval" xml:"buffer_flush_interval,attr" yaml:"buffer_flush_interval"` + BufferFlushInterval *cnfg.Duration `json:"buffer_flush_interval" toml:"buffer_flush_interval" xml:"buffer_flush_interval,attr" yaml:"buffer_flush_interval"` // BufferShardCount is the number of buffer "shards" that will be used. // Those shards allows the use of multiple buffers at the same time to reduce // lock contention. @@ -58,10 +58,7 @@ type Config struct { // protocol used when creating the client: 2048 for UDP and 512 for UDS. SenderQueueSize *int `json:"sender_queue_size" toml:"sender_queue_size" xml:"sender_queue_size,attr" yaml:"sender_queue_size"` // WriteTimeoutUDS is the timeout after which a UDS packet is dropped. - WriteTimeoutUDS *time.Duration `json:"write_timeout_uds" toml:"write_timeout_uds" xml:"write_timeout_uds,attr" yaml:"write_timeout_uds"` - // Telemetry is a set of metrics automatically injected by the client in the - // dogstatsd stream to be able to monitor the client itself. - Telemetry *bool `json:"telemetry" toml:"telemetry" xml:"telemetry,attr" yaml:"telemetry"` + WriteTimeoutUDS *cnfg.Duration `json:"write_timeout_uds" toml:"write_timeout_uds" xml:"write_timeout_uds,attr" yaml:"write_timeout_uds"` // ReceiveMode determins the behavior of the client when receiving to many // metrics. The client will either drop the metrics if its buffers are // full (ChannelMode mode) or block the caller until the metric can be @@ -86,10 +83,6 @@ type Config struct { ChannelModeBufferSize *int `json:"channel_mode_buffer_size" toml:"channel_mode_buffer_size" xml:"channel_mode_buffer_size,attr" yaml:"channel_mode_buffer_size"` // AggregationFlushInterval is the interval for the aggregator to flush metrics AggregationFlushInterval *time.Duration `json:"aggregation_flush_interval" toml:"aggregation_flush_interval" xml:"aggregation_flush_interval,attr" yaml:"aggregation_flush_interval"` - // [beta] Aggregation enables/disables client side aggregation - Aggregation *bool `json:"aggregation" toml:"aggregation" xml:"aggregation,attr" yaml:"aggregation"` - // TelemetryAddr specify a different endpoint for telemetry metrics. - TelemetryAddr *string `json:"telemetry_address" toml:"telemetry_address" xml:"telemetry_address,attr" yaml:"telemetry_address"` } // Datadog allows the data to be context aware with configuration @@ -101,22 +94,16 @@ type Datadog struct { // DatadogUnifi is returned by New() after you provide a Config. type DatadogUnifi struct { Collector poller.Collect - datadog statsd.ClientInterface + datadog statsd.ClientInterface LastCheck time.Time *Datadog } -type metric struct { - Name string - Tags map[string]string - Fields map[string]interface{} -} - -func init() { // nolint: gochecknoinits +func init() { // nolint: gochecknoinits u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now()} poller.NewOutput(&poller.Output{ - Name: "datadog", + Name: "datadog", Config: u.Datadog, Method: u.Run, }) @@ -131,17 +118,62 @@ func (u *DatadogUnifi) setConfigDefaults() { u.Interval = cnfg.Duration{Duration: u.Interval.Duration.Round(time.Second)} - u.options = make([]statsd.Option) + u.options = make([]statsd.Option, 0) if u.Namespace != nil { u.options = append(u.options, statsd.WithNamespace(*u.Namespace)) } + if u.Tags != nil && len(u.Tags) > 0 { u.options = append(u.options, statsd.WithTags(u.Tags)) } -} + if u.MaxBytesPerPayload != nil { + u.options = append(u.options, statsd.WithMaxBytesPerPayload(*u.MaxBytesPerPayload)) + } + if u.MaxMessagesPerPayload != nil { + u.options = append(u.options, statsd.WithMaxMessagesPerPayload(*u.MaxMessagesPerPayload)) + } + + if u.BufferPoolSize != nil { + u.options = append(u.options, statsd.WithBufferPoolSize(*u.BufferPoolSize)) + } + + if u.BufferFlushInterval != nil { + u.options = append(u.options, statsd.WithBufferFlushInterval((*u.BufferFlushInterval).Duration)) + } + + if u.BufferShardCount != nil { + u.options = append(u.options, statsd.WithBufferShardCount(*u.BufferShardCount)) + } + + if u.SenderQueueSize != nil { + u.options = append(u.options, statsd.WithSenderQueueSize(*u.SenderQueueSize)) + } + + if u.WriteTimeoutUDS != nil { + u.options = append(u.options, statsd.WithWriteTimeoutUDS((*u.WriteTimeoutUDS).Duration)) + } + + if u.ReceiveMode != nil { + switch *u.ReceiveMode { + case statsd.ChannelMode: + u.options = append(u.options, statsd.WithChannelMode()) + case statsd.MutexMode: + u.options = append(u.options, statsd.WithMutexMode()) + } + } + + if u.ChannelModeBufferSize != nil { + u.options = append(u.options, statsd.WithChannelModeBufferSize(*u.ChannelModeBufferSize)) + } + + if u.AggregationFlushInterval != nil { + u.options = append(u.options, statsd.WithAggregationInterval(*u.AggregationFlushInterval)) + } + +} // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { @@ -153,18 +185,18 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { u.Collector = c u.setConfigDefaults() - u.datadog, err := statsd.New(u.Address, u.options...) + var err error + u.datadog, err = statsd.New(u.Address, u.options...) if err != nil { return err } u.PollController() - + return nil } - -// PollController runs fover, polling UniFi and pushing to Datadog +// PollController runs forever, polling UniFi and pushing to Datadog // This is started by Run() or RunBoth() after everything is validated. func (u *DatadogUnifi) PollController() { interval := u.Interval.Round(time.Second) @@ -197,53 +229,41 @@ func (u *DatadogUnifi) PollController() { // Call this after you've collected all the data you care about. // Returns an error if datadog statsd calls fail, otherwise returns a report. func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) { - r := &Report{Metrics: m, ch: make(chan *metric), Start: time.Now()} - + r := &Report{Metrics: m, Start: time.Now()} + // batch all the points. + u.loopPoints(r) + r.End = time.Now() + r.Elapsed = r.End.Sub(r.Start) return r, nil } - -// collect runs in a go routine and batches all the points. -func (u *InfluxUnifi) collect(r report, ch chan *metric) { - for m := range ch { - pt, err := influx.NewPoint(m.Table, m.Tags, m.Fields, r.metrics().TS) - if err == nil { - r.batch(m, pt) - } - - r.error(err) - r.done() - } -} - -// loopPoints kicks off 3 or 7 go routines to process metrics and send them -// to the collect routine through the metric channel. +// loopPoints collects all the data to immediately report to Datadog. func (u *DatadogUnifi) loopPoints(r report) { m := r.metrics() for _, s := range m.SitesDPI { - u.batchSiteDPI(r, s) + u.reportSiteDPI(r, s) } for _, s := range m.Sites { - u.batchSite(r, s) + u.reportSite(r, s) } appTotal := make(totalsDPImap) catTotal := make(totalsDPImap) for _, s := range m.ClientsDPI { - u.batchClientDPI(r, s, appTotal, catTotal) + u.reportClientDPI(r, s, appTotal, catTotal) } reportClientDPItotals(r, appTotal, catTotal) for _, s := range m.Clients { - u.batchClient(r, s) + u.reportClient(r, s) } for _, s := range m.IDSList { - u.batchIDS(r, s) + u.reportIDS(r, s) } u.loopDevicePoints(r) @@ -257,19 +277,19 @@ func (u *DatadogUnifi) loopDevicePoints(r report) { } for _, s := range m.UAPs { - u.batchUAP(r, s) + u.reportUAP(r, s) } for _, s := range m.USGs { - u.batchUSG(r, s) + u.reportUSG(r, s) } for _, s := range m.USWs { - u.batchUSW(r, s) + u.reportUSW(r, s) } for _, s := range m.UDMs { - u.batchUDM(r, s) + u.reportUDM(r, s) } } @@ -277,7 +297,6 @@ func (u *DatadogUnifi) loopDevicePoints(r report) { func (u *DatadogUnifi) LogDatadogReport(r *Report) { m := r.Metrics idsMsg := fmt.Sprintf("IDS Events: %d, ", len(m.IDSList)) - u.Collector.Logf("UniFi Metrics Recorded. Sites: %d, Clients: %d, "+ "UAP: %d, USG/UDM: %d, USW: %d, %sPoints: %d, Fields: %d, Errs: %d, Elapsed: %v", len(m.Sites), len(m.Clients), len(m.UAPs), diff --git a/integrations/datadogunifi/ids.go b/integrations/datadogunifi/ids.go new file mode 100644 index 00000000..2b368f79 --- /dev/null +++ b/integrations/datadogunifi/ids.go @@ -0,0 +1,31 @@ +package datadogunifi + +import ( + "github.com/unifi-poller/unifi" +) + +// reportIDS generates intrusion detection datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) reportIDS(r report, i *unifi.IDS) { + tags := []string{ + tag("site_name", i.SiteName), + tag("source", i.SourceName), + tag("in_iface", i.InIface), + tag("event_type", i.EventType), + tag("proto", i.Proto), + tag("app_proto", i.AppProto), + tag("usgip", i.USGIP), + tag("country_code", i.SourceIPGeo.CountryCode), + tag("country_name", i.SourceIPGeo.CountryName), + tag("city", i.SourceIPGeo.City), + tag("organization", i.SourceIPGeo.Organization), + tag("srcipASN", i.SrcIPASN), + tag("usgipASN", i.USGIPASN), + tag("alert_category", i.InnerAlertCategory), + tag("subsystem", i.Subsystem), + tag("catname", i.Catname), + } + + metricName := metricNamespace("intrusion_detect") + r.reportCount(metricName("count"), 1, tags) +} diff --git a/integrations/datadogunifi/points.go b/integrations/datadogunifi/points.go new file mode 100644 index 00000000..751c2114 --- /dev/null +++ b/integrations/datadogunifi/points.go @@ -0,0 +1,21 @@ +package datadogunifi + +import ( + "fmt" +) + +func tag(name string, value interface{}) string { + return fmt.Sprintf("%s:%v", name, value) +} + +func metricNamespace(namespace string) func(string) string { + return func(name string) string { + return fmt.Sprintf("%s.%s", namespace, name) + } +} + +func reportGaugeForMap(r report, metricName func(string) string, data map[string]float64, tags []string) { + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } +} diff --git a/integrations/datadogunifi/report.go b/integrations/datadogunifi/report.go new file mode 100644 index 00000000..5450606c --- /dev/null +++ b/integrations/datadogunifi/report.go @@ -0,0 +1,76 @@ +package datadogunifi + +import ( + "time" + + "github.com/DataDog/datadog-go/statsd" + "github.com/unifi-poller/poller" +) + +type Report struct { + Metrics *poller.Metrics + Errors []error + Total int + Fields int + Start time.Time + End time.Time + Elapsed time.Duration + + client statsd.ClientInterface +} + +type report interface { + error(err error) + metrics() *poller.Metrics + reportGauge(name string, value float64, tags []string) error + reportCount(name string, value int64, tags []string) error + reportDistribution(name string, value float64, tags []string) error + reportTiming(name string, value time.Duration, tags []string) error + reportEvent(title string, message string, tags []string) error + reportServiceCheck(name string, status statsd.ServiceCheckStatus, message string, tags []string) error +} + +func (r *Report) metrics() *poller.Metrics { + return r.Metrics +} + +func (r *Report) error(err error) { + if err != nil { + r.Errors = append(r.Errors, err) + } +} + +func (r *Report) reportGauge(name string, value float64, tags []string) error { + return r.client.Gauge(name, value, tags, 1.0) +} + +func (r *Report) reportCount(name string, value int64, tags []string) error { + return r.client.Count(name, value, tags, 1.0) +} + +func (r *Report) reportDistribution(name string, value float64, tags []string) error { + return r.client.Distribution(name, value, tags, 1.0) +} + +func (r *Report) reportTiming(name string, value time.Duration, tags []string) error { + return r.client.Timing(name, value, tags, 1.0) +} + +func (r *Report) reportEvent(title string, message string, tags []string) error { + return r.client.Event(&statsd.Event{ + Title: title, + Text: message, + Timestamp: time.Now(), + Tags: tags, + }) +} + +func (r *Report) reportServiceCheck(name string, status statsd.ServiceCheckStatus, message string, tags []string) error { + return r.client.ServiceCheck(&statsd.ServiceCheck{ + Name: name, + Status: status, + Timestamp: time.Now(), + Message: message, + Tags: tags, + }) +} diff --git a/integrations/datadogunifi/site.go b/integrations/datadogunifi/site.go index da3f1b80..a9ffe0a1 100644 --- a/integrations/datadogunifi/site.go +++ b/integrations/datadogunifi/site.go @@ -4,5 +4,77 @@ import ( "github.com/unifi-poller/unifi" ) -// batchSite generates Unifi Sites' datapoints for Datadog. -// These points can be passed directly to datadog +// reportSite generates Unifi Sites' datapoints for Datadog. +// These points can be passed directly to Datadog. +func (u *DatadogUnifi) reportSite(r report, s *unifi.Site) { + metricName := metricNamespace("subsystems") + + for _, h := range s.Health { + tags := []string{ + tag("name", s.Name), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("desc", s.Desc), + tag("status", h.Status), + tag("subsystem", h.Subsystem), + tag("wan_ip", h.WanIP), + tag("gw_name", h.GwName), + tag("lan_ip", h.LanIP), + } + + data := map[string]float64{ + "num_user": h.NumUser.Val, + "num_guest": h.NumGuest.Val, + "num_iot": h.NumIot.Val, + "tx_bytes-r": h.TxBytesR.Val, + "rx_bytes-r": h.RxBytesR.Val, + "num_ap": h.NumAp.Val, + "num_adopted": h.NumAdopted.Val, + "num_disabled": h.NumDisabled.Val, + "num_disconnected": h.NumDisconnected.Val, + "num_pending": h.NumPending.Val, + "num_gw": h.NumGw.Val, + "num_sta": h.NumSta.Val, + "gw_cpu": h.GwSystemStats.CPU.Val, + "gw_mem": h.GwSystemStats.Mem.Val, + "gw_uptime": h.GwSystemStats.Uptime.Val, + "latency": h.Latency.Val, + "uptime": h.Uptime.Val, + "drops": h.Drops.Val, + "xput_up": h.XputUp.Val, + "xput_down": h.XputDown.Val, + "speedtest_ping": h.SpeedtestPing.Val, + "speedtest_lastrun": h.SpeedtestLastrun.Val, + "num_sw": h.NumSw.Val, + "remote_user_num_active": h.RemoteUserNumActive.Val, + "remote_user_num_inactive": h.RemoteUserNumInactive.Val, + "remote_user_rx_bytes": h.RemoteUserRxBytes.Val, + "remote_user_tx_bytes": h.RemoteUserTxBytes.Val, + "remote_user_rx_packets": h.RemoteUserRxPackets.Val, + "remote_user_tx_packets": h.RemoteUserTxPackets.Val, + "num_new_alarms": s.NumNewAlarms.Val, + } + + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } + } +} + +func (u *DatadogUnifi) reportSiteDPI(r report, s *unifi.DPITable) { + for _, dpi := range s.ByApp { + metricName := metricNamespace("sitedpi") + + tags := []string{ + tag("category", unifi.DPICats.Get(dpi.Cat)), + tag("application", unifi.DPIApps.GetApp(dpi.Cat, dpi.App)), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + } + + r.reportCount(metricName("tx_packets"), dpi.TxPackets, tags) + r.reportCount(metricName("rx_packets"), dpi.RxPackets, tags) + r.reportCount(metricName("tx_bytes"), dpi.TxBytes, tags) + r.reportCount(metricName("rx_bytes"), dpi.RxBytes, tags) + } +} diff --git a/integrations/datadogunifi/uap.go b/integrations/datadogunifi/uap.go new file mode 100644 index 00000000..83403c12 --- /dev/null +++ b/integrations/datadogunifi/uap.go @@ -0,0 +1,199 @@ +package datadogunifi + +import ( + "github.com/unifi-poller/unifi" +) + +// reportUAP generates Wireless-Access-Point datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *DatadogUnifi) reportUAP(r report, s *unifi.UAP) { + if !s.Adopted.Val || s.Locating.Val { + return + } + + tags := []string{ + tag("ip", s.IP), + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + } + + metricName := metricNamespace("uap") + + u.reportUAPstats(s.Stat.Ap, r, metricName, tags) + u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + + data := map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "user-num_sta": s.UserNumSta.Val, + "guest-num_sta": s.GuestNumSta.Val, + "num_sta": s.NumSta.Val, + } + reportGaugeForMap(r, metricName, data, tags) + + u.reportRadTable(r, s.Name, s.SiteName, s.SourceName, s.RadioTable, s.RadioTableStats) + u.reportVAPTable(r, s.Name, s.SiteName, s.SourceName, s.VapTable) + u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) +} + +func (u *DatadogUnifi) reportUAPstats(ap *unifi.Ap, r report, metricName func(string) string, tags []string) { + if ap == nil { + return + } + + // Accumulative Statistics. + data := map[string]float64{ + "stat_user-rx_packets": ap.UserRxPackets.Val, + "stat_guest-rx_packets": ap.GuestRxPackets.Val, + "stat_rx_packets": ap.RxPackets.Val, + "stat_user-rx_bytes": ap.UserRxBytes.Val, + "stat_guest-rx_bytes": ap.GuestRxBytes.Val, + "stat_rx_bytes": ap.RxBytes.Val, + "stat_user-rx_errors": ap.UserRxErrors.Val, + "stat_guest-rx_errors": ap.GuestRxErrors.Val, + "stat_rx_errors": ap.RxErrors.Val, + "stat_user-rx_dropped": ap.UserRxDropped.Val, + "stat_guest-rx_dropped": ap.GuestRxDropped.Val, + "stat_rx_dropped": ap.RxDropped.Val, + "stat_user-rx_crypts": ap.UserRxCrypts.Val, + "stat_guest-rx_crypts": ap.GuestRxCrypts.Val, + "stat_rx_crypts": ap.RxCrypts.Val, + "stat_user-rx_frags": ap.UserRxFrags.Val, + "stat_guest-rx_frags": ap.GuestRxFrags.Val, + "stat_rx_frags": ap.RxFrags.Val, + "stat_user-tx_packets": ap.UserTxPackets.Val, + "stat_guest-tx_packets": ap.GuestTxPackets.Val, + "stat_tx_packets": ap.TxPackets.Val, + "stat_user-tx_bytes": ap.UserTxBytes.Val, + "stat_guest-tx_bytes": ap.GuestTxBytes.Val, + "stat_tx_bytes": ap.TxBytes.Val, + "stat_user-tx_errors": ap.UserTxErrors.Val, + "stat_guest-tx_errors": ap.GuestTxErrors.Val, + "stat_tx_errors": ap.TxErrors.Val, + "stat_user-tx_dropped": ap.UserTxDropped.Val, + "stat_guest-tx_dropped": ap.GuestTxDropped.Val, + "stat_tx_dropped": ap.TxDropped.Val, + "stat_user-tx_retries": ap.UserTxRetries.Val, + "stat_guest-tx_retries": ap.GuestTxRetries.Val, + } + reportGaugeForMap(r, metricName, data, tags) +} + +// reportVAPTable creates points for Wifi Radios. This works with several types of UAP-capable devices. +func (u *DatadogUnifi) reportVAPTable(r report, deviceName string, siteName string, source string, vt unifi.VapTable) { // nolint: funlen + for _, s := range vt { + tags := []string{ + tag("device_name", deviceName), + tag("site_name", siteName), + tag("source", source), + tag("ap_mac", s.ApMac), + tag("bssid", s.Bssid), + tag("id", s.ID), + tag("name", s.Name), + tag("radio_name", s.RadioName), + tag("radio", s.Radio), + tag("essid", s.Essid), + tag("site_id", s.SiteID), + tag("usage", s.Usage), + tag("state", s.State), + tag("is_guest", s.IsGuest.Txt), + } + data := map[string]float64{ + "ccq": float64(s.Ccq), + "mac_filter_rejections": float64(s.MacFilterRejections), + "num_satisfaction_sta": s.NumSatisfactionSta.Val, + "avg_client_signal": s.AvgClientSignal.Val, + "satisfaction": s.Satisfaction.Val, + "satisfaction_now": s.SatisfactionNow.Val, + "num_sta": float64(s.NumSta), + "channel": s.Channel.Val, + "rx_bytes": s.RxBytes.Val, + "rx_crypts": s.RxCrypts.Val, + "rx_dropped": s.RxDropped.Val, + "rx_errors": s.RxErrors.Val, + "rx_frags": s.RxFrags.Val, + "rx_nwids": s.RxNwids.Val, + "rx_packets": s.RxPackets.Val, + "tx_bytes": s.TxBytes.Val, + "tx_dropped": s.TxDropped.Val, + "tx_errors": s.TxErrors.Val, + "tx_packets": s.TxPackets.Val, + "tx_power": s.TxPower.Val, + "tx_retries": s.TxRetries.Val, + "tx_combined_retries": s.TxCombinedRetries.Val, + "tx_data_mpdu_bytes": s.TxDataMpduBytes.Val, + "tx_rts_retries": s.TxRtsRetries.Val, + "tx_success": s.TxSuccess.Val, + "tx_total": s.TxTotal.Val, + "tx_tcp_goodbytes": s.TxTCPStats.Goodbytes.Val, + "tx_tcp_lat_avg": s.TxTCPStats.LatAvg.Val, + "tx_tcp_lat_max": s.TxTCPStats.LatMax.Val, + "tx_tcp_lat_min": s.TxTCPStats.LatMin.Val, + "rx_tcp_goodbytes": s.RxTCPStats.Goodbytes.Val, + "rx_tcp_lat_avg": s.RxTCPStats.LatAvg.Val, + "rx_tcp_lat_max": s.RxTCPStats.LatMax.Val, + "rx_tcp_lat_min": s.RxTCPStats.LatMin.Val, + "wifi_tx_latency_mov_avg": s.WifiTxLatencyMov.Avg.Val, + "wifi_tx_latency_mov_max": s.WifiTxLatencyMov.Max.Val, + "wifi_tx_latency_mov_min": s.WifiTxLatencyMov.Min.Val, + "wifi_tx_latency_mov_total": s.WifiTxLatencyMov.Total.Val, + "wifi_tx_latency_mov_cuont": s.WifiTxLatencyMov.TotalCount.Val, + } + + metricName := metricNamespace("uap_vaps") + reportGaugeForMap(r, metricName, data, tags) + } +} + +func (u *DatadogUnifi) reportRadTable(r report, deviceName string, siteName string, source string, rt unifi.RadioTable, rts unifi.RadioTableStats) { + for _, p := range rt { + tags := []string{ + tag("device_name", deviceName), + tag("site_name", siteName), + tag("source", source), + tag("channel", p.Channel.Txt), + tag("radio", p.Radio), + } + data := map[string]float64{ + "current_antenna_gain": p.CurrentAntennaGain.Val, + "ht": p.Ht.Val, + "max_txpower": p.MaxTxpower.Val, + "min_txpower": p.MinTxpower.Val, + "nss": p.Nss.Val, + "radio_caps": p.RadioCaps.Val, + } + + for _, t := range rts { + if t.Name == p.Name { + data["ast_be_xmit"] = t.AstBeXmit.Val + data["channel"] = t.Channel.Val + data["cu_self_rx"] = t.CuSelfRx.Val + data["cu_self_tx"] = t.CuSelfTx.Val + data["cu_total"] = t.CuTotal.Val + data["extchannel"] = t.Extchannel.Val + data["gain"] = t.Gain.Val + data["guest-num_sta"] = t.GuestNumSta.Val + data["num_sta"] = t.NumSta.Val + data["tx_packets"] = t.TxPackets.Val + data["tx_power"] = t.TxPower.Val + data["tx_retries"] = t.TxRetries.Val + data["user-num_sta"] = t.UserNumSta.Val + + break + } + } + + metricName := metricNamespace("uap_radios") + + reportGaugeForMap(r, metricName, data, tags) + } +} diff --git a/integrations/datadogunifi/udm.go b/integrations/datadogunifi/udm.go new file mode 100644 index 00000000..f544648b --- /dev/null +++ b/integrations/datadogunifi/udm.go @@ -0,0 +1,141 @@ +package datadogunifi + +import ( + "fmt" + + "github.com/unifi-poller/unifi" +) + +// reportSysStats is used by all device types. +func (u *DatadogUnifi) reportSysStats(r report, metricName func(string) string, s unifi.SysStats, ss unifi.SystemStats, tags []string) { + data := map[string]float64{ + "loadavg_1": s.Loadavg1.Val, + "loadavg_5": s.Loadavg5.Val, + "loadavg_15": s.Loadavg15.Val, + "mem_used": s.MemUsed.Val, + "mem_buffer": s.MemBuffer.Val, + "mem_total": s.MemTotal.Val, + "cpu": ss.CPU.Val, + "mem": ss.Mem.Val, + "system_uptime": ss.Uptime.Val, + } + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } +} + +func (u *DatadogUnifi) reportUDMtemps(r report, metricName func(string) string, tags []string, temps []unifi.Temperature) { + for _, t := range temps { + name := fmt.Sprintf("temp_%s", t.Name) + r.reportGauge(metricName(name), t.Value, tags) + } +} + +// reportUDM generates Unifi Gateway datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *DatadogUnifi) reportUDM(r report, s *unifi.UDM) { // nolint: funlen + if !s.Adopted.Val || s.Locating.Val { + return + } + + metricName := metricNamespace("usg") + + tags := []string{ + tag("source", s.SourceName), + tag("ip", s.IP), + tag("license_state", s.LicenseState), + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + } + u.reportUDMtemps(r, metricName, tags, s.Temperatures) + u.reportUSGstats(r, metricName, tags, s.SpeedtestStatus, s.Stat.Gw, s.Uplink) + u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + + data := map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "guest-num_sta": s.GuestNumSta.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "num_desktop": s.NumDesktop.Val, + "num_handheld": s.NumHandheld.Val, + "num_mobile": s.NumMobile.Val, + } + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } + u.reportNetTable(r, s.Name, s.SiteName, s.SourceName, s.NetworkTable) + u.reportUSGwans(r, s.Name, s.SiteName, s.SourceName, s.Wan1, s.Wan2) + + tags = []string{ + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + tag("ip", s.IP), + } + metricName = metricNamespace("usw") + u.reportUSWstat(r, metricName, tags, s.Stat.Sw) + + data = map[string]float64{ + "guest-num_sta": s.GuestNumSta.Val, + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + } + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } + + u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) // udm has a usw in it. + + if s.Stat.Ap == nil { + return // we're done now. the following code process UDM (non-pro) UAP data. + } + + tags = []string{ + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + } + + metricName = metricNamespace("uap") + u.reportUAPstats(s.Stat.Ap, r, metricName, tags) + + data = map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "guest-num_sta": s.GuestNumSta.Val, + "num_sta": s.NumSta.Val, + } + for name, value := range data { + r.reportGauge(metricName(name), value, tags) + } + + u.reportRadTable(r, s.Name, s.SiteName, s.SourceName, *s.RadioTable, *s.RadioTableStats) + u.reportVAPTable(r, s.Name, s.SiteName, s.SourceName, *s.VapTable) +} diff --git a/integrations/datadogunifi/usg.go b/integrations/datadogunifi/usg.go new file mode 100644 index 00000000..613c4c6c --- /dev/null +++ b/integrations/datadogunifi/usg.go @@ -0,0 +1,145 @@ +package datadogunifi + +import ( + "github.com/unifi-poller/unifi" +) + +// reportUSG generates Unifi Gateway datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) reportUSG(r report, s *unifi.USG) { + if !s.Adopted.Val || s.Locating.Val { + return + } + + tags := []string{ + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + tag("ip", s.IP), + tag("license_state", s.LicenseState), + } + metricName := metricNamespace("usg") + u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + u.reportUSGstats(r, metricName, tags, s.SpeedtestStatus, s.Stat.Gw, s.Uplink) + + data := map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "guest-num_sta": s.GuestNumSta.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "num_desktop": s.NumDesktop.Val, + "num_handheld": s.NumHandheld.Val, + "num_mobile": s.NumMobile.Val, + } + reportGaugeForMap(r, metricName, data, tags) + + u.reportNetTable(r, s.Name, s.SiteName, s.SourceName, s.NetworkTable) + u.reportUSGwans(r, s.Name, s.SiteName, s.SourceName, s.Wan1, s.Wan2) +} + +func (u *DatadogUnifi) reportUSGstats(r report, metricName func(string) string, tags []string, ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) { + if gw == nil { + return + } + data := map[string]float64{ + "uplink_latency": ul.Latency.Val, + "uplink_speed": ul.Speed.Val, + "speedtest-status_latency": ss.Latency.Val, + "speedtest-status_runtime": ss.Runtime.Val, + "speedtest-status_rundate": ss.Rundate.Val, + "speedtest-status_ping": ss.StatusPing.Val, + "speedtest-status_xput_download": ss.XputDownload.Val, + "speedtest-status_xput_upload": ss.XputUpload.Val, + "lan-rx_bytes": gw.LanRxBytes.Val, + "lan-rx_packets": gw.LanRxPackets.Val, + "lan-tx_bytes": gw.LanTxBytes.Val, + "lan-tx_packets": gw.LanTxPackets.Val, + "lan-rx_dropped": gw.LanRxDropped.Val, + } + reportGaugeForMap(r, metricName, data, tags) +} + +func (u *DatadogUnifi) reportUSGwans(r report, deviceName string, siteName string, source string, wans ...unifi.Wan) { + for _, wan := range wans { + if !wan.Up.Val { + continue + } + + tags := []string{ + tag("device_name", deviceName), + tag("site_name", siteName), + tag("source", source), + tag("ip", wan.IP), + tag("purpose", wan.Name), + tag("mac", wan.Mac), + tag("ifname", wan.Ifname), + tag("type", wan.Type), + tag("up", wan.Up.Txt), + tag("enabled", wan.Enable.Txt), + tag("gateway", wan.Gateway), + } + fullDuplex := float64(0) + if wan.FullDuplex.Val { + fullDuplex = 1 + } + + data := map[string]float64{ + "bytes-r": wan.BytesR.Val, + "full_duplex": fullDuplex, + "max_speed": wan.MaxSpeed.Val, + "rx_bytes": wan.RxBytes.Val, + "rx_bytes-r": wan.RxBytesR.Val, + "rx_dropped": wan.RxDropped.Val, + "rx_errors": wan.RxErrors.Val, + "rx_broadcast": wan.RxBroadcast.Val, + "rx_multicast": wan.RxMulticast.Val, + "rx_packets": wan.RxPackets.Val, + "speed": wan.Speed.Val, + "tx_bytes": wan.TxBytes.Val, + "tx_bytes-r": wan.TxBytesR.Val, + "tx_dropped": wan.TxDropped.Val, + "tx_errors": wan.TxErrors.Val, + "tx_packets": wan.TxPackets.Val, + "tx_broadcast": wan.TxBroadcast.Val, + "tx_multicast": wan.TxMulticast.Val, + } + metricName := metricNamespace("usg_wan_ports") + reportGaugeForMap(r, metricName, data, tags) + } +} + +func (u *DatadogUnifi) reportNetTable(r report, deviceName string, siteName string, source string, nt unifi.NetworkTable) { + for _, p := range nt { + tags := []string{ + tag("device_name", deviceName), + tag("site_name", siteName), + tag("source", source), + tag("up", p.Up.Txt), + tag("enabled", p.Enabled.Txt), + tag("ip", p.IP), + tag("mac", p.Mac), + tag("name", p.Name), + tag("domain_name", p.DomainName), + tag("purpose", p.Purpose), + tag("is_guest", p.IsGuest.Txt), + } + data := map[string]float64{ + "num_sta": p.NumSta.Val, + "rx_bytes": p.RxBytes.Val, + "rx_packets": p.RxPackets.Val, + "tx_bytes": p.TxBytes.Val, + "tx_packets": p.TxPackets.Val, + } + metricName := metricNamespace("usg_networks") + reportGaugeForMap(r, metricName, data, tags) + } +} diff --git a/integrations/datadogunifi/usw.go b/integrations/datadogunifi/usw.go new file mode 100644 index 00000000..1dd4ea4b --- /dev/null +++ b/integrations/datadogunifi/usw.go @@ -0,0 +1,119 @@ +package datadogunifi + +import ( + "fmt" + + "github.com/unifi-poller/unifi" +) + +// reportUSW generates Unifi Switch datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) reportUSW(r report, s *unifi.USW) { + if !s.Adopted.Val || s.Locating.Val { + return + } + + tags := []string{ + tag("mac", s.Mac), + tag("site_name", s.SiteName), + tag("source", s.SourceName), + tag("name", s.Name), + tag("version", s.Version), + tag("model", s.Model), + tag("serial", s.Serial), + tag("type", s.Type), + tag("ip", s.IP), + } + metricName := metricNamespace("usw") + u.reportUSWstat(r, metricName, tags, s.Stat.Sw) + u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + + data := map[string]float64{ + "guest-num_sta": s.GuestNumSta.Val, + "bytes": s.Bytes.Val, + "fan_level": s.FanLevel.Val, + "general_temperature": s.GeneralTemperature.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + } + reportGaugeForMap(r, metricName, data, tags) + u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) +} + +func (u *DatadogUnifi) reportUSWstat(r report, metricName func(string) string, tags []string, sw *unifi.Sw) { + if sw == nil { + return + } + + data := map[string]float64{ + "stat_bytes": sw.Bytes.Val, + "stat_rx_bytes": sw.RxBytes.Val, + "stat_rx_crypts": sw.RxCrypts.Val, + "stat_rx_dropped": sw.RxDropped.Val, + "stat_rx_errors": sw.RxErrors.Val, + "stat_rx_frags": sw.RxFrags.Val, + "stat_rx_packets": sw.TxPackets.Val, + "stat_tx_bytes": sw.TxBytes.Val, + "stat_tx_dropped": sw.TxDropped.Val, + "stat_tx_errors": sw.TxErrors.Val, + "stat_tx_packets": sw.TxPackets.Val, + "stat_tx_retries": sw.TxRetries.Val, + } + reportGaugeForMap(r, metricName, data, tags) +} + +func (u *DatadogUnifi) reportPortTable(r report, deviceName string, siteName string, source string, typeTag string, pt []unifi.Port) { + for _, p := range pt { + if !p.Up.Val || !p.Enable.Val { + continue // only record UP ports. + } + + tags := []string{ + tag("site_name", siteName), + tag("device_name", deviceName), + tag("source", source), + tag("type", typeTag), + tag("name", p.Name), + tag("poe_mode", p.PoeMode), + tag("port_poe", p.PortPoe.Txt), + tag("port_idx", p.PortIdx.Txt), + tag("port_id", fmt.Sprintf("%s_port_%s", deviceName, p.PortIdx.Txt)), + tag("poe_enable", p.PoeEnable.Txt), + tag("flowctrl_rx", p.FlowctrlRx.Txt), + tag("flowctrl_tx", p.FlowctrlTx.Txt), + tag("media", p.Media), + } + data := map[string]float64{ + "dbytes_r": p.BytesR.Val, + "rx_broadcast": p.RxBroadcast.Val, + "rx_bytes": p.RxBytes.Val, + "rx_bytes-r": p.RxBytesR.Val, + "rx_dropped": p.RxDropped.Val, + "rx_errors": p.RxErrors.Val, + "rx_multicast": p.RxMulticast.Val, + "rx_packets": p.RxPackets.Val, + "speed": p.Speed.Val, + "stp_pathcost": p.StpPathcost.Val, + "tx_broadcast": p.TxBroadcast.Val, + "tx_bytes": p.TxBytes.Val, + "tx_bytes-r": p.TxBytesR.Val, + "tx_dropped": p.TxDropped.Val, + "tx_errors": p.TxErrors.Val, + "tx_multicast": p.TxMulticast.Val, + "tx_packets": p.TxPackets.Val, + } + + if p.PoeEnable.Val && p.PortPoe.Val { + data["poe_current"] = p.PoeCurrent.Val + data["poe_power"] = p.PoePower.Val + data["poe_voltage"] = p.PoeVoltage.Val + } + + metricName := metricNamespace("usw_ports") + reportGaugeForMap(r, metricName, data, tags) + } +} From 057faf9de9b4d1ba18f48cf5d793ed35b62d1843 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sun, 11 Oct 2020 11:45:20 -0500 Subject: [PATCH 05/25] update readme --- integrations/datadogunifi/README.md | 80 ++++++++++++++++++++++++++++ integrations/datadogunifi/datadog.go | 13 ++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/integrations/datadogunifi/README.md b/integrations/datadogunifi/README.md index 4b3cf5ca..a3755288 100644 --- a/integrations/datadogunifi/README.md +++ b/integrations/datadogunifi/README.md @@ -1,3 +1,83 @@ # datadogunifi UniFi Poller Output Plugin for DataDog + +## Configuration + +```yaml +datadog: + # How often to poll UniFi and report to Datadog. + interval: "2m" + + # To disable this output plugin + disable: false + + # Datadog Custom Options + + # address to talk to the datadog agent, by default this uses the local statsd UDP interface + # address: "..." + + # namespace to prepend to all data + # namespace: "" + + # tags to append to all data + # tags: + # - foo + + # max_bytes_per_payload is the maximum number of bytes a single payload will contain. + # The magic value 0 will set the option to the optimal size for the transport + # protocol used when creating the client: 1432 for UDP and 8192 for UDS. + # max_bytes_per_payload: 0 + + # max_messages_per_payload is the maximum number of metrics, events and/or service checks a single payload will contain. + # This option can be set to `1` to create an unbuffered client. + # max_messages_per_payload: 0 + + # BufferPoolSize is the size of the pool of buffers in number of buffers. + # The magic value 0 will set the option to the optimal size for the transport + # protocol used when creating the client: 2048 for UDP and 512 for UDS. + # buffer_pool_size: 0 + + # buffer_flush_interval is the interval after which the current buffer will get flushed. + # buffer_flush_interval: 0 + + # buffer_shard_count is the number of buffer "shards" that will be used. + # Those shards allows the use of multiple buffers at the same time to reduce + # lock contention. + # buffer_shard_count: 0 + + # sender_queue_size is the size of the sender queue in number of buffers. + # The magic value 0 will set the option to the optimal size for the transport + # protocol used when creating the client: 2048 for UDP and 512 for UDS. + # sender_queue_size: 0 + + # write_timeout_uds is the timeout after which a UDS packet is dropped. + # write_timeout_uds: 5000 + + # receive_mode determines the behavior of the client when receiving to many + # metrics. The client will either drop the metrics if its buffers are + # full (ChannelMode mode) or block the caller until the metric can be + # handled (MutexMode mode). By default the client will MutexMode. This + # option should be set to ChannelMode only when use under very high + # load. + # + # MutexMode uses a mutex internally which is much faster than + # channel but causes some lock contention when used with a high number + # of threads. Mutex are sharded based on the metrics name which + # limit mutex contention when goroutines send different metrics. + # + # ChannelMode: uses channel (of ChannelModeBufferSize size) to send + # metrics and drop metrics if the channel is full. Sending metrics in + # this mode is slower that MutexMode (because of the channel), but + # will not block the application. This mode is made for application + # using many goroutines, sending the same metrics at a very high + # volume. The goal is to not slow down the application at the cost of + # dropping metrics and having a lower max throughput. + # receive_mode: 0 + + # channel_mode_buffer_size is the size of the channel holding incoming metrics + # channel_mode_buffer_size: 0 + + # aggregation_flush_interval is the interval for the aggregator to flush metrics + # aggregation_flush_interval: 0 +``` \ No newline at end of file diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 4f9e4be7..377dca26 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -34,32 +34,41 @@ type Config struct { // Namespace to prepend to all metrics, events and service checks name. Namespace *string `json:"namespace" toml:"namespace" xml:"namespace,attr" yaml:"namespace"` + // Tags are global tags to be applied to every metrics, events and service checks. Tags []string `json:"tags" toml:"tags" xml:"tags,attr" yaml:"tags"` + // MaxBytesPerPayload is the maximum number of bytes a single payload will contain. // The magic value 0 will set the option to the optimal size for the transport // protocol used when creating the client: 1432 for UDP and 8192 for UDS. MaxBytesPerPayload *int `json:"max_bytes_per_payload" toml:"max_bytes_per_payload" xml:"max_bytes_per_payload,attr" yaml:"max_bytes_per_payload"` + // MaxMessagesPerPayload is the maximum number of metrics, events and/or service checks a single payload will contain. // This option can be set to `1` to create an unbuffered client. MaxMessagesPerPayload *int `json:"max_messages_per_payload" toml:"max_messages_per_payload" xml:"max_messages_per_payload,attr" yaml:"max_messages_per_payload"` + // BufferPoolSize is the size of the pool of buffers in number of buffers. // The magic value 0 will set the option to the optimal size for the transport // protocol used when creating the client: 2048 for UDP and 512 for UDS. BufferPoolSize *int `json:"buffer_pool_size" toml:"buffer_pool_size" xml:"buffer_pool_size,attr" yaml:"buffer_pool_size"` + // BufferFlushInterval is the interval after which the current buffer will get flushed. BufferFlushInterval *cnfg.Duration `json:"buffer_flush_interval" toml:"buffer_flush_interval" xml:"buffer_flush_interval,attr" yaml:"buffer_flush_interval"` + // BufferShardCount is the number of buffer "shards" that will be used. // Those shards allows the use of multiple buffers at the same time to reduce // lock contention. BufferShardCount *int `json:"buffer_shard_count" toml:"buffer_shard_count" xml:"buffer_shard_count,attr" yaml:"buffer_shard_count"` + // SenderQueueSize is the size of the sender queue in number of buffers. // The magic value 0 will set the option to the optimal size for the transport // protocol used when creating the client: 2048 for UDP and 512 for UDS. SenderQueueSize *int `json:"sender_queue_size" toml:"sender_queue_size" xml:"sender_queue_size,attr" yaml:"sender_queue_size"` + // WriteTimeoutUDS is the timeout after which a UDS packet is dropped. WriteTimeoutUDS *cnfg.Duration `json:"write_timeout_uds" toml:"write_timeout_uds" xml:"write_timeout_uds,attr" yaml:"write_timeout_uds"` - // ReceiveMode determins the behavior of the client when receiving to many + + // ReceiveMode determines the behavior of the client when receiving to many // metrics. The client will either drop the metrics if its buffers are // full (ChannelMode mode) or block the caller until the metric can be // handled (MutexMode mode). By default the client will MutexMode. This @@ -79,8 +88,10 @@ type Config struct { // volume. The goal is to not slow down the application at the cost of // dropping metrics and having a lower max throughput. ReceiveMode *statsd.ReceivingMode `json:"receive_mode" toml:"receive_mode" xml:"receive_mode,attr" yaml:"receive_mode"` + // ChannelModeBufferSize is the size of the channel holding incoming metrics ChannelModeBufferSize *int `json:"channel_mode_buffer_size" toml:"channel_mode_buffer_size" xml:"channel_mode_buffer_size,attr" yaml:"channel_mode_buffer_size"` + // AggregationFlushInterval is the interval for the aggregator to flush metrics AggregationFlushInterval *time.Duration `json:"aggregation_flush_interval" toml:"aggregation_flush_interval" xml:"aggregation_flush_interval,attr" yaml:"aggregation_flush_interval"` } From 21735aedfeed03e815c780f5cdb92097a0d095ff Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sun, 11 Oct 2020 11:49:53 -0500 Subject: [PATCH 06/25] fix dep versions --- integrations/datadogunifi/go.mod | 4 ++-- integrations/datadogunifi/go.sum | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index f43d2128..59f2a409 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -4,8 +4,8 @@ go 1.15 require ( github.com/DataDog/datadog-go v4.0.0+incompatible - github.com/pkg/errors v0.9.1 + github.com/pkg/errors v0.9.1 // indirect github.com/unifi-poller/poller v0.0.7 - github.com/unifi-poller/unifi v0.0.6 + github.com/unifi-poller/unifi v0.0.5 golift.io/cnfg v0.0.6 ) diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index 43175f3c..b5219921 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -97,9 +97,13 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/unifi-poller/poller v0.0.6 h1:KhOWUeYI029Nn/4NOIk/yblQ3tEd9QhS+u/8/S9ZoDs= +github.com/unifi-poller/poller v0.0.6/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= github.com/unifi-poller/poller v0.0.7 h1:waSPusZd7yPz1zKJgxPSTwjhIUzA+qj8PwVyfLSLjns= github.com/unifi-poller/poller v0.0.7/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= github.com/unifi-poller/unifi v0.0.4/go.mod h1:bTUtctrf56aapjKH+L+98eThBaVFbQXw5iNGZI0g/+E= +github.com/unifi-poller/unifi v0.0.5 h1:Izeun32YxcQOeKZUXY0Sy4ltKYFuYxWGcN9JS6xkIJU= +github.com/unifi-poller/unifi v0.0.5/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= github.com/unifi-poller/unifi v0.0.6 h1:/nvb4KiB3uwPNh+CTKOZqGhT4K/q9NBjeo0H+YNT224= github.com/unifi-poller/unifi v0.0.6/go.mod h1:uqBaNCon8FTw6nwGsAYHz/HwBgEYepS0XB5XW+OdBts= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -117,6 +121,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= From b216b0702054144c6095a96fa59ee5069ec976fb Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sun, 11 Oct 2020 11:50:37 -0500 Subject: [PATCH 07/25] update gitignore --- integrations/datadogunifi/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/datadogunifi/.gitignore b/integrations/datadogunifi/.gitignore index 0ce503cb..4c6c1ca3 100644 --- a/integrations/datadogunifi/.gitignore +++ b/integrations/datadogunifi/.gitignore @@ -14,4 +14,4 @@ .vscode/ # Dependency directories (remove the comment below to include it) -# vendor/ +vendor/ From 7a24cc1f9bc4a2bf785ee4ea2546d99e67941588 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sun, 11 Oct 2020 11:52:06 -0500 Subject: [PATCH 08/25] fix ids --- integrations/datadogunifi/ids.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/integrations/datadogunifi/ids.go b/integrations/datadogunifi/ids.go index 2b368f79..f4bb29e3 100644 --- a/integrations/datadogunifi/ids.go +++ b/integrations/datadogunifi/ids.go @@ -14,13 +14,12 @@ func (u *DatadogUnifi) reportIDS(r report, i *unifi.IDS) { tag("event_type", i.EventType), tag("proto", i.Proto), tag("app_proto", i.AppProto), - tag("usgip", i.USGIP), - tag("country_code", i.SourceIPGeo.CountryCode), - tag("country_name", i.SourceIPGeo.CountryName), - tag("city", i.SourceIPGeo.City), - tag("organization", i.SourceIPGeo.Organization), - tag("srcipASN", i.SrcIPASN), - tag("usgipASN", i.USGIPASN), + tag("usgip", i.Usgip), + tag("country_code", i.SrcipGeo.CountryCode), + tag("country_name", i.SrcipGeo.CountryName), + tag("city", i.SrcipGeo.City), + tag("srcipASN", i.SrcipASN), + tag("usgipASN", i.UsgipASN), tag("alert_category", i.InnerAlertCategory), tag("subsystem", i.Subsystem), tag("catname", i.Catname), From 7833500d2a07f494f165542d4f5862477a637fc1 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sat, 4 Dec 2021 21:01:38 -0600 Subject: [PATCH 09/25] bring this up to recent specs --- integrations/datadogunifi/alarms.go | 1 + integrations/datadogunifi/events.go | 1 + integrations/datadogunifi/go.sum | 196 +++++----------------------- integrations/datadogunifi/logger.go | 1 + integrations/datadogunifi/uxg.go | 1 + 5 files changed, 39 insertions(+), 161 deletions(-) create mode 100644 integrations/datadogunifi/alarms.go create mode 100644 integrations/datadogunifi/events.go create mode 100644 integrations/datadogunifi/logger.go create mode 100644 integrations/datadogunifi/uxg.go diff --git a/integrations/datadogunifi/alarms.go b/integrations/datadogunifi/alarms.go new file mode 100644 index 00000000..a18029d3 --- /dev/null +++ b/integrations/datadogunifi/alarms.go @@ -0,0 +1 @@ +package datadogunifi diff --git a/integrations/datadogunifi/events.go b/integrations/datadogunifi/events.go new file mode 100644 index 00000000..a18029d3 --- /dev/null +++ b/integrations/datadogunifi/events.go @@ -0,0 +1 @@ +package datadogunifi diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index b5219921..f3eb0480 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -1,185 +1,59 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v4.0.0+incompatible h1:Dq8Dr+4sV1gBO1sHDWdW+4G+PdsA+YSJOK925MxrrCY= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= -github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c h1:zqmyTlQyufRC65JnImJ6H1Sf7BDj8bG31EV919NVEQc= +github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/unifi-poller/poller v0.0.6 h1:KhOWUeYI029Nn/4NOIk/yblQ3tEd9QhS+u/8/S9ZoDs= -github.com/unifi-poller/poller v0.0.6/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= -github.com/unifi-poller/poller v0.0.7 h1:waSPusZd7yPz1zKJgxPSTwjhIUzA+qj8PwVyfLSLjns= -github.com/unifi-poller/poller v0.0.7/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= -github.com/unifi-poller/unifi v0.0.4/go.mod h1:bTUtctrf56aapjKH+L+98eThBaVFbQXw5iNGZI0g/+E= -github.com/unifi-poller/unifi v0.0.5 h1:Izeun32YxcQOeKZUXY0Sy4ltKYFuYxWGcN9JS6xkIJU= -github.com/unifi-poller/unifi v0.0.5/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= -github.com/unifi-poller/unifi v0.0.6 h1:/nvb4KiB3uwPNh+CTKOZqGhT4K/q9NBjeo0H+YNT224= -github.com/unifi-poller/unifi v0.0.6/go.mod h1:uqBaNCon8FTw6nwGsAYHz/HwBgEYepS0XB5XW+OdBts= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 h1:YAv5naMdpOFahnxteFFRidZlrSEwLv8V2nBKJKmLmHg= +github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= +github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80 h1:XjHGfJhMwnB63DYHgtWGJgDxLhxVcAOtf+cfuvpGoyo= +github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= +github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf h1:HhXi3qca3kyFEFPh0mqdr0bpQs94hJvMbUJztwPtf2A= +github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf/go.mod h1:77PywuUvspdtoRuH1htFhR3Tp0pLyWj6kJlYR4tBYho= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c h1:38q6VNPWR010vN82/SB121GujZNIfAUb4YttE2rhGuc= -golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golift.io/cnfg v0.0.5/go.mod h1:ScFDIJg/rJGHbRaed/i7g1lBhywEjB0JiP2uZr3xC3A= -golift.io/cnfg v0.0.6 h1:7tlP31gKsrGDEfPZmDTDQus8wOzjG91FtuAdGghoB64= -golift.io/cnfg v0.0.6/go.mod h1:F61j5OO4gwOwhJfoquyOEa6idDjbMj4P9KAPJAM4ZLM= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golift.io/cnfg v0.0.7 h1:qkNpP5Bq+5Gtoc6HcI8kapMD5zFOVan6qguxqBQF3OY= +golift.io/cnfg v0.0.7/go.mod h1:AsB0DJe7nv0bizKaoy3e3MjjOF7upTpMOMvsfv4CNNk= +golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= +golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integrations/datadogunifi/logger.go b/integrations/datadogunifi/logger.go new file mode 100644 index 00000000..a18029d3 --- /dev/null +++ b/integrations/datadogunifi/logger.go @@ -0,0 +1 @@ +package datadogunifi diff --git a/integrations/datadogunifi/uxg.go b/integrations/datadogunifi/uxg.go new file mode 100644 index 00000000..a18029d3 --- /dev/null +++ b/integrations/datadogunifi/uxg.go @@ -0,0 +1 @@ +package datadogunifi From db85c29aba3dde2044437c00ac38a66b60cea3a8 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sat, 4 Dec 2021 21:01:49 -0600 Subject: [PATCH 10/25] bring this up to recent specs --- integrations/datadogunifi/alarms.go | 87 +++++++++ integrations/datadogunifi/clients.go | 183 ++++++++++--------- integrations/datadogunifi/datadog.go | 166 +++++++++++------- integrations/datadogunifi/events.go | 142 +++++++++++++++ integrations/datadogunifi/go.mod | 9 +- integrations/datadogunifi/go.sum | 29 +++ integrations/datadogunifi/ids.go | 2 +- integrations/datadogunifi/logger.go | 37 ++++ integrations/datadogunifi/points.go | 64 ++++++- integrations/datadogunifi/report.go | 74 +++++++- integrations/datadogunifi/site.go | 2 +- integrations/datadogunifi/uap.go | 166 +++++++++++------- integrations/datadogunifi/udm.go | 253 ++++++++++++++++----------- integrations/datadogunifi/usg.go | 156 +++++++++-------- integrations/datadogunifi/usw.go | 130 ++++++++------ integrations/datadogunifi/uxg.go | 82 +++++++++ 16 files changed, 1129 insertions(+), 453 deletions(-) diff --git a/integrations/datadogunifi/alarms.go b/integrations/datadogunifi/alarms.go index a18029d3..dbbacd9b 100644 --- a/integrations/datadogunifi/alarms.go +++ b/integrations/datadogunifi/alarms.go @@ -1 +1,88 @@ package datadogunifi + +import ( + "fmt" + "strconv" + "time" + + "github.com/unpoller/unifi" +) + +const ( + alarmT = item("Alarm") + anomalyT = item("Anomaly") +) + +// batchAlarms generates alarm events and logs for Datadog. +func (u *DatadogUnifi) batchAlarms(r report, event *unifi.Alarm) { // nolint:dupl + if time.Since(event.Datetime) > u.Interval.Duration+time.Second { + return // The event is older than our interval, ignore it. + } + + tagMap := map[string]string{ + "dest_port": strconv.Itoa(event.DestPort), + "src_port": strconv.Itoa(event.SrcPort), + "dest_ip": event.DestIP, + "dst_mac": event.DstMAC, + "host": event.Host, + "msg": event.Msg, + "src_ip": event.SrcIP, + "src_mac": event.SrcMAC, + "dstip_asn": fmt.Sprintf("%d", event.DestIPGeo.Asn), + "dstip_latitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Latitude), + "dstip_longitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Longitude), + "dstip_city": event.DestIPGeo.City, + "dstip_continent_code": event.DestIPGeo.ContinentCode, + "dstip_country_code": event.DestIPGeo.CountryCode, + "dstip_country_name": event.DestIPGeo.CountryName, + "dstip_organization": event.DestIPGeo.Organization, + "srcip_asn": fmt.Sprintf("%d", event.SourceIPGeo.Asn), + "srcip_latitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Latitude), + "srcip_longitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Longitude), + "srcip_city": event.SourceIPGeo.City, + "srcip_continent_code": event.SourceIPGeo.ContinentCode, + "srcip_country_code": event.SourceIPGeo.CountryCode, + "srcip_country_name": event.SourceIPGeo.CountryName, + "srcip_organization": event.SourceIPGeo.Organization, + "site_name": event.SiteName, + "source": event.SourceName, + "in_iface": event.InIface, + "event_type": event.EventType, + "subsystem": event.Subsystem, + "archived": event.Archived.Txt, + "usgip": event.USGIP, + "proto": event.Proto, + "key": event.Key, + "catname": event.Catname, + "app_proto": event.AppProto, + "action": event.InnerAlertAction, + } + r.addCount(alarmT) + + tagMap = cleanTags(tagMap) + tags := tagMapToTags(tagMap) + title := fmt.Sprintf("[%s][%s] Alarm at %s from %s", event.EventType, event.Catname, event.SiteName, event.SourceName) + r.reportEvent(title, event.Datetime, event.Msg, tags) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", event.Datetime.Unix(), title, event.Msg), tagMapToZapFields(tagMap)) +} + +// batchAnomaly generates Anomalies from UniFi for Datadog. +func (u *DatadogUnifi) batchAnomaly(r report, event *unifi.Anomaly) { + if time.Since(event.Datetime) > u.Interval.Duration+time.Second { + return // The event is older than our interval, ignore it. + } + + r.addCount(anomalyT) + + tagMap := cleanTags(map[string]string{ + "application": "unifi_anomaly", + "source": event.SourceName, + "site_name": event.SiteName, + "device_mac": event.DeviceMAC, + }) + tags := tagMapToTags(tagMap) + + title := fmt.Sprintf("Anomaly detected at %s from %s", event.SiteName, event.SourceName) + r.reportEvent(title, event.Datetime, event.Anomaly, tags) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", event.Datetime.Unix(), title, event.Anomaly), tagMapToZapFields(tagMap)) +} diff --git a/integrations/datadogunifi/clients.go b/integrations/datadogunifi/clients.go index 91070964..a8422fee 100644 --- a/integrations/datadogunifi/clients.go +++ b/integrations/datadogunifi/clients.go @@ -1,108 +1,122 @@ package datadogunifi import ( - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) -// reportClient generates Unifi Client datapoints for InfluxDB. -// These points can be passed directly to influx. -func (u *DatadogUnifi) reportClient(r report, s *unifi.Client) { // nolint: funlen - tags := []string{ - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("ap_name", s.ApName), - tag("gw_name", s.GwName), - tag("sw_name", s.SwName), - tag("oui", s.Oui), - tag("radio_name", s.RadioName), - tag("radio", s.Radio), - tag("radio_proto", s.RadioProto), - tag("name", s.Name), - tag("fixed_ip", s.FixedIP), - tag("sw_port", s.SwPort.Txt), - tag("os_class", s.OsClass.Txt), - tag("os_name", s.OsName.Txt), - tag("dev_cat", s.DevCat.Txt), - tag("dev_id", s.DevID.Txt), - tag("dev_vendor", s.DevVendor.Txt), - tag("dev_family", s.DevFamily.Txt), - tag("is_wired", s.IsWired.Txt), - tag("is_guest", s.IsGuest.Txt), - tag("use_fixedip", s.UseFixedIP.Txt), - tag("channel", s.Channel.Txt), - tag("vlan", s.Vlan.Txt), - tag("hostname", s.Name), - tag("radio_desc", s.RadioDescription), - tag("ip", s.IP), - tag("essid", s.Essid), - tag("bssid", s.Bssid), +// batchClient generates Unifi Client datapoints for Datadog. +// These points can be passed directly to Datadog. +func (u *DatadogUnifi) batchClient(r report, s *unifi.Client) { // nolint: funlen + tags := map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "ap_name": s.ApName, + "gw_name": s.GwName, + "sw_name": s.SwName, + "oui": s.Oui, + "radio_name": s.RadioName, + "radio": s.Radio, + "radio_proto": s.RadioProto, + "name": s.Name, + "fixed_ip": s.FixedIP, + "sw_port": s.SwPort.Txt, + "os_class": s.OsClass.Txt, + "os_name": s.OsName.Txt, + "dev_cat": s.DevCat.Txt, + "dev_id": s.DevID.Txt, + "dev_vendor": s.DevVendor.Txt, + "dev_family": s.DevFamily.Txt, + "is_wired": s.IsWired.Txt, + "is_guest": s.IsGuest.Txt, + "use_fixedip": s.UseFixedIP.Txt, + "channel": s.Channel.Txt, + "vlan": s.Vlan.Txt, + "hostname": s.Name, + "essid": s.Essid, + "bssid": s.Bssid, + "ip": s.IP, + } + powerSaveEnabled := 0.0 + if s.PowersaveEnabled.Val { + powerSaveEnabled = 1.0 + } + data := map[string]float64{ + "anomalies": float64(s.Anomalies), + "channel": s.Channel.Val, + "satisfaction": s.Satisfaction.Val, + "bytes_r": float64(s.BytesR), + "ccq": float64(s.Ccq), + "noise": float64(s.Noise), + "powersave_enabled": powerSaveEnabled, + "roam_count": float64(s.RoamCount), + "rssi": float64(s.Rssi), + "rx_bytes": float64(s.RxBytes), + "rx_bytes_r": float64(s.RxBytesR), + "rx_packets": float64(s.RxPackets), + "rx_rate": float64(s.RxRate), + "signal": float64(s.Signal), + "tx_bytes": float64(s.TxBytes), + "tx_bytes_r": float64(s.TxBytesR), + "tx_packets": float64(s.TxPackets), + "tx_retries": float64(s.TxRetries), + "tx_power": float64(s.TxPower), + "tx_rate": float64(s.TxRate), + "uptime": float64(s.Uptime), + "wifi_tx_attempts": float64(s.WifiTxAttempts), + "wired-rx_bytes": float64(s.WiredRxBytes), + "wired-rx_bytes-r": float64(s.WiredRxBytesR), + "wired-rx_packets": float64(s.WiredRxPackets), + "wired-tx_bytes": float64(s.WiredTxBytes), + "wired-tx_bytes-r": float64(s.WiredTxBytesR), + "wired-tx_packets": float64(s.WiredTxPackets), } - data := map[string]float64{ - "anomalies": float64(s.Anomalies), - "channel": s.Channel.Val, - "satisfaction": s.Satisfaction.Val, - "bytes_r": float64(s.BytesR), - "ccq": float64(s.Ccq), - "noise": float64(s.Noise), - "roam_count": float64(s.RoamCount), - "rssi": float64(s.Rssi), - "rx_bytes": float64(s.RxBytes), - "rx_bytes_r": float64(s.RxBytesR), - "rx_packets": float64(s.RxPackets), - "rx_rate": float64(s.RxRate), - "signal": float64(s.Signal), - "tx_bytes": float64(s.TxBytes), - "tx_bytes_r": float64(s.TxBytesR), - "tx_packets": float64(s.TxPackets), - "tx_retries": float64(s.TxRetries), - "tx_power": float64(s.TxPower), - "tx_rate": float64(s.TxRate), - "uptime": float64(s.Uptime), - "wifi_tx_attempts": float64(s.WifiTxAttempts), - "wired-rx_bytes": float64(s.WiredRxBytes), - "wired-rx_bytes-r": float64(s.WiredRxBytesR), - "wired-rx_packets": float64(s.WiredRxPackets), - "wired-tx_bytes": float64(s.WiredTxBytes), - "wired-tx_bytes-r": float64(s.WiredTxBytesR), - "wired-tx_packets": float64(s.WiredTxPackets), - } metricName := metricNamespace("clients") - reportGaugeForMap(r, metricName, data, tags) + + reportGaugeForFloat64Map(r, metricName, data, tags) } // totalsDPImap: controller, site, name (app/cat name), dpi. type totalsDPImap map[string]map[string]map[string]unifi.DPIData -func (u *DatadogUnifi) reportClientDPI(r report, s *unifi.DPITable, appTotal, catTotal totalsDPImap) { +func (u *DatadogUnifi) batchClientDPI(r report, v interface{}, appTotal, catTotal totalsDPImap) { + s, ok := v.(*unifi.DPITable) + if !ok { + u.LogErrorf("invalid type given to batchClientDPI: %T", v) + return + } + for _, dpi := range s.ByApp { category := unifi.DPICats.Get(dpi.Cat) application := unifi.DPIApps.GetApp(dpi.Cat, dpi.App) fillDPIMapTotals(appTotal, application, s.SourceName, s.SiteName, dpi) fillDPIMapTotals(catTotal, category, s.SourceName, s.SiteName, dpi) - tags := []string{ - tag("category", category), - tag("application", application), - tag("name", s.Name), - tag("mac", s.MAC), - tag("site_name", s.SiteName), - tag("source", s.SourceName), + tags := map[string]string{ + "category": category, + "application": application, + "name": s.Name, + "mac": s.MAC, + "site_name": s.SiteName, + "source": s.SourceName, } + data := map[string]float64{ "tx_packets": float64(dpi.TxPackets), "rx_packets": float64(dpi.RxPackets), "tx_bytes": float64(dpi.TxBytes), "rx_bytes": float64(dpi.RxBytes), } - metricName := metricNamespace("clientdpi") - reportGaugeForMap(r, metricName, data, tags) + + metricName := metricNamespace("client_dpi") + + reportGaugeForFloat64Map(r, metricName, data, tags) } } // fillDPIMapTotals fills in totals for categories and applications. maybe clients too. -// This allows less processing in InfluxDB to produce total transfer data per cat or app. +// This allows less processing in Datadog to produce total transfer data per cat or app. func fillDPIMapTotals(m totalsDPImap, name, controller, site string, dpi unifi.DPIData) { if m[controller] == nil { m[controller] = make(map[string]map[string]unifi.DPIData) @@ -148,19 +162,26 @@ func reportClientDPItotals(r report, appTotal, catTotal totalsDPImap) { for controller, s := range k.val { for site, c := range s { for name, m := range c { - tags := []string{ - tag("site_name", site), - tag("source", controller), - tag("name", name), + tags := map[string]string{ + "category": "TOTAL", + "application": "TOTAL", + "name": "TOTAL", + "mac": "TOTAL", + "site_name": site, + "source": controller, } + tags[k.kind] = name + data := map[string]float64{ "tx_packets": float64(m.TxPackets), "rx_packets": float64(m.RxPackets), "tx_bytes": float64(m.TxBytes), "rx_bytes": float64(m.RxBytes), } - metricName := metricNamespace("clientdpi.totals") - reportGaugeForMap(r, metricName, data, tags) + + metricName := metricNamespace("client_dpi") + + reportGaugeForFloat64Map(r, metricName, data, tags) } } } diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 377dca26..af94e22b 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -3,13 +3,12 @@ package datadogunifi import ( - "fmt" - "log" "time" "github.com/DataDog/datadog-go/statsd" - "github.com/unifi-poller/poller" - "github.com/unifi-poller/unifi" + "github.com/unpoller/poller" + "github.com/unpoller/unifi" + "go.uber.org/zap" "golift.io/cnfg" ) @@ -25,6 +24,9 @@ type Config struct { // Interval controls the collection and reporting interval Interval cnfg.Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval,omitempty" yaml:"interval,omitempty"` + // Save data for dead ports? ie. ports that are down or disabled. + DeadPorts bool `json:"dead_ports,omitempty" toml:"dead_ports,omitempty" xml:"dead_ports,omitempty" yaml:"dead_ports,omitempty"` + // Disable when true disables this output plugin Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"` // Address determines how to talk to the Datadog agent @@ -107,11 +109,13 @@ type DatadogUnifi struct { Collector poller.Collect datadog statsd.ClientInterface LastCheck time.Time + Logger *zap.SugaredLogger *Datadog } func init() { // nolint: gochecknoinits - u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now()} + l, _ := zap.NewProduction() + u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now(), Logger: l.Sugar()} poller.NewOutput(&poller.Output{ Name: "datadog", @@ -188,8 +192,13 @@ func (u *DatadogUnifi) setConfigDefaults() { // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { - if u.Config == nil || u.Disable { - c.Logf("DataDog config is missing (or disabled): Datadog output is disabled!") + defer u.Logger.Sync() + if u.Disable { + u.Logger.Debug("Datadog config is disabled, output is disabled.") + return nil + } + if u.Config == nil && !u.Disable { + u.Logger.Error("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil } @@ -212,26 +221,29 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { func (u *DatadogUnifi) PollController() { interval := u.Interval.Round(time.Second) ticker := time.NewTicker(interval) - log.Printf("[INFO] Everything checks out! Poller started, Datadog interval: %v", interval) + u.Logger.Info("Everything checks out! Poller started", zap.Duration("interval", interval)) for u.LastCheck = range ticker.C { - metrics, ok, collectErr := u.Collector.Metrics() - if collectErr != nil { - u.Collector.LogErrorf("metric fetch for Datadog failed: %v", collectErr) - - if !ok { - continue - } - } - - report, err := u.ReportMetrics(metrics) + metrics, err := u.Collector.Metrics(&poller.Filter{Name: "unifi"}) if err != nil { - // Is the agent down? - u.Collector.LogErrorf("%v", err) + u.Logger.Error("metric fetch for Datadog failed", zap.Error(err)) continue } - report.error(collectErr) + events, err := u.Collector.Events(&poller.Filter{Name: "unifi", Dur: interval}) + if err != nil { + u.Logger.Error("event fetch for Datadog failed", zap.Error(err)) + continue + } + + report, err := u.ReportMetrics(metrics, events) + if err != nil { + // Is the agent down? + u.Logger.Error("unable to report metrics and events", zap.Error(err)) + report.reportCount("unifi.collect.errors", 1, []string{}) + continue + } + report.reportCount("unifi.collect.success", 1, []string{}) u.LogDatadogReport(report) } } @@ -239,12 +251,19 @@ func (u *DatadogUnifi) PollController() { // ReportMetrics batches all device and client data into datadog data points. // Call this after you've collected all the data you care about. // Returns an error if datadog statsd calls fail, otherwise returns a report. -func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) { - r := &Report{Metrics: m, Start: time.Now()} +func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics, e *poller.Events) (*Report, error) { + r := &Report{ + Metrics: m, + Events: e, + Start: time.Now(), + Counts: &Counts{Val: make(map[item]int)}, + Logger: u.Logger, + } // batch all the points. u.loopPoints(r) r.End = time.Now() r.Elapsed = r.End.Sub(r.Start) + r.reportTiming("unifi.collector_timing", r.Elapsed, []string{}) return r, nil } @@ -252,65 +271,82 @@ func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics) (*Report, error) { func (u *DatadogUnifi) loopPoints(r report) { m := r.metrics() - for _, s := range m.SitesDPI { - u.reportSiteDPI(r, s) + for _, s := range m.RogueAPs { + u.switchExport(r, s) } for _, s := range m.Sites { - u.reportSite(r, s) + u.switchExport(r, s) + } + + for _, s := range m.SitesDPI { + u.reportSiteDPI(r, s.(*unifi.DPITable)) + } + + for _, s := range m.Clients { + u.switchExport(r, s) + } + + for _, s := range m.Devices { + u.switchExport(r, s) + } + + for _, s := range r.events().Logs { + u.switchExport(r, s) } appTotal := make(totalsDPImap) catTotal := make(totalsDPImap) for _, s := range m.ClientsDPI { - u.reportClientDPI(r, s, appTotal, catTotal) + u.batchClientDPI(r, s, appTotal, catTotal) } reportClientDPItotals(r, appTotal, catTotal) - - for _, s := range m.Clients { - u.reportClient(r, s) - } - - for _, s := range m.IDSList { - u.reportIDS(r, s) - } - - u.loopDevicePoints(r) } -func (u *DatadogUnifi) loopDevicePoints(r report) { - m := r.metrics() - if m.Devices == nil { - m.Devices = &unifi.Devices{} - return - } - - for _, s := range m.UAPs { - u.reportUAP(r, s) - } - - for _, s := range m.USGs { - u.reportUSG(r, s) - } - - for _, s := range m.USWs { - u.reportUSW(r, s) - } - - for _, s := range m.UDMs { - u.reportUDM(r, s) +func (u *DatadogUnifi) switchExport(r report, v interface{}) { //nolint:cyclop + switch v := v.(type) { + case *unifi.RogueAP: + u.batchRogueAP(r, v) + case *unifi.UAP: + u.batchUAP(r, v) + case *unifi.USW: + u.batchUSW(r, v) + case *unifi.USG: + u.batchUSG(r, v) + case *unifi.UXG: + u.batchUXG(r, v) + case *unifi.UDM: + u.batchUDM(r, v) + case *unifi.Site: + u.reportSite(r, v) + case *unifi.Client: + u.batchClient(r, v) + case *unifi.Event: + u.batchEvent(r, v) + case *unifi.IDS: + u.batchIDS(r, v) + case *unifi.Alarm: + u.batchAlarms(r, v) + case *unifi.Anomaly: + u.batchAnomaly(r, v) + default: + u.Logger.Error("invalid export", zap.Reflect("type", v)) } } -// LogInfluxReport writes a log message after exporting to influxdb. +// LogDatadogReport writes a log message after exporting to Datadog. func (u *DatadogUnifi) LogDatadogReport(r *Report) { m := r.Metrics - idsMsg := fmt.Sprintf("IDS Events: %d, ", len(m.IDSList)) - u.Collector.Logf("UniFi Metrics Recorded. Sites: %d, Clients: %d, "+ - "UAP: %d, USG/UDM: %d, USW: %d, %sPoints: %d, Fields: %d, Errs: %d, Elapsed: %v", - len(m.Sites), len(m.Clients), len(m.UAPs), - len(m.UDMs)+len(m.USGs), len(m.USWs), idsMsg, r.Total, - r.Fields, len(r.Errors), r.Elapsed.Round(time.Millisecond)) + u.Logger.Info("UniFi Metrics Recorded", + zap.Int("num_sites", len(m.Sites)), + zap.Int("num_sites_dpi", len(m.SitesDPI)), + zap.Int("num_clients", len(m.Clients)), + zap.Int("num_clients_dpi", len(m.ClientsDPI)), + zap.Int("num_rogue_ap", len(m.RogueAPs)), + zap.Int("num_devices", len(m.Devices)), + zap.Errors("errors", r.Errors), + zap.Duration("elapsed", r.Elapsed), + ) } diff --git a/integrations/datadogunifi/events.go b/integrations/datadogunifi/events.go index a18029d3..a95f3e25 100644 --- a/integrations/datadogunifi/events.go +++ b/integrations/datadogunifi/events.go @@ -1 +1,143 @@ package datadogunifi + +import ( + "fmt" + "strconv" + "time" + + "github.com/unpoller/unifi" +) + +// These constants are used as names for printed/logged counters. +const ( + eventT = item("Event") + idsT = item("IDS") +) + +// batchIDS generates intrusion detection datapoints for Datadog. +func (u *DatadogUnifi) batchIDS(r report, i *unifi.IDS) { // nolint:dupl + if time.Since(i.Datetime) > u.Interval.Duration+time.Second { + return // The event is older than our interval, ignore it. + } + + tagMap := map[string]string{ + "dest_port": strconv.Itoa(i.DestPort), + "src_port": strconv.Itoa(i.SrcPort), + "dest_ip": i.DestIP, + "dst_mac": i.DstMAC, + "host": i.Host, + "msg": i.Msg, + "src_ip": i.SrcIP, + "src_mac": i.SrcMAC, + "dstip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), + "dstip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), + "dstip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), + "dstip_city": i.DestIPGeo.City, + "dstip_continent_code": i.DestIPGeo.ContinentCode, + "dstip_country_code": i.DestIPGeo.CountryCode, + "dstip_country_name": i.DestIPGeo.CountryName, + "dstip_organization": i.DestIPGeo.Organization, + "srcip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), + "srcip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), + "srcip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), + "srcip_city": i.SourceIPGeo.City, + "srcip_continent_code": i.SourceIPGeo.ContinentCode, + "srcip_country_code": i.SourceIPGeo.CountryCode, + "srcip_country_name": i.SourceIPGeo.CountryName, + "srcip_organization": i.SourceIPGeo.Organization, + "site_name": i.SiteName, + "source": i.SourceName, + "in_iface": i.InIface, + "event_type": i.EventType, + "subsystem": i.Subsystem, + "archived": i.Archived.Txt, + "usgip": i.USGIP, + "proto": i.Proto, + "key": i.Key, + "catname": i.Catname, + "app_proto": i.AppProto, + "action": i.InnerAlertAction, + } + + r.addCount(idsT) + + tagMap = cleanTags(tagMap) + tags := tagMapToTags(tagMap) + title := fmt.Sprintf("Intrusion Detection at %s from %s", i.SiteName, i.SourceName) + r.reportEvent(title, i.Datetime, i.Msg, tags) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", i.Datetime.Unix(), title, i.Msg), tagMapToZapFields(tagMap)) +} + +// batchEvents generates events from UniFi for Datadog. +func (u *DatadogUnifi) batchEvent(r report, i *unifi.Event) { // nolint: funlen + if time.Since(i.Datetime) > u.Interval.Duration+time.Second { + return // The event is older than our interval, ignore it. + } + + tagMap := map[string]string{ + "guest": i.Guest, // mac address + "user": i.User, // mac address + "host": i.Host, // usg device? + "hostname": i.Hostname, // client name + "dest_port": strconv.Itoa(i.DestPort), + "src_port": strconv.Itoa(i.SrcPort), + "dest_ip": i.DestIP, + "dst_mac": i.DstMAC, + "ip": i.IP, + "src_ip": i.SrcIP, + "src_mac": i.SrcMAC, + "dstip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), + "dstip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), + "dstip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), + "dstip_city": i.DestIPGeo.City, + "dstip_continent_code": i.DestIPGeo.ContinentCode, + "dstip_country_code": i.DestIPGeo.CountryCode, + "dstip_country_name": i.DestIPGeo.CountryName, + "dstip_organization": i.DestIPGeo.Organization, + "srcip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), + "srcip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), + "srcip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), + "srcip_city": i.SourceIPGeo.City, + "srcip_continent_code": i.SourceIPGeo.ContinentCode, + "srcip_country_code": i.SourceIPGeo.CountryCode, + "srcip_country_name": i.SourceIPGeo.CountryName, + "srcip_organization": i.SourceIPGeo.Organization, + "admin": i.Admin, // username + "site_name": i.SiteName, + "source": i.SourceName, + "ap_from": i.ApFrom, + "ap_to": i.ApTo, + "ap": i.Ap, + "ap_name": i.ApName, + "gw": i.Gw, + "gw_name": i.GwName, + "sw": i.Sw, + "sw_name": i.SwName, + "catname": i.Catname, + "radio": i.Radio, + "radio_from": i.RadioFrom, + "radio_to": i.RadioTo, + "key": i.Key, + "in_iface": i.InIface, + "event_type": i.EventType, + "subsystem": i.Subsystem, + "ssid": i.SSID, + "is_admin": i.IsAdmin.Txt, + "channel": i.Channel.Txt, + "channel_from": i.ChannelFrom.Txt, + "channel_to": i.ChannelTo.Txt, + "usgip": i.USGIP, + "network": i.Network, + "app_proto": i.AppProto, + "proto": i.Proto, + "action": i.InnerAlertAction, + } + + r.addCount(eventT) + + tagMap = cleanTags(tagMap) + tags := tagMapToTags(tagMap) + title := fmt.Sprintf("Unifi Event at %s from %s", i.SiteName, i.SourceName) + r.reportEvent(title, i.Datetime, i.Msg, tags) + r.reportInfoLog(fmt.Sprintf("[%d] %s: %s", i.Datetime.Unix(), title, i.Msg), tagMapToZapFields(tagMap)) +} diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index 59f2a409..e4001308 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -5,7 +5,10 @@ go 1.15 require ( github.com/DataDog/datadog-go v4.0.0+incompatible github.com/pkg/errors v0.9.1 // indirect - github.com/unifi-poller/poller v0.0.7 - github.com/unifi-poller/unifi v0.0.5 - golift.io/cnfg v0.0.6 + github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 + github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80 + github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf + go.uber.org/zap v1.19.1 + golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect + golift.io/cnfg v0.0.7 ) diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index f3eb0480..16bdb5f0 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -2,6 +2,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v4.0.0+incompatible h1:Dq8Dr+4sV1gBO1sHDWdW+4G+PdsA+YSJOK925MxrrCY= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -9,33 +10,53 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c h1:zqmyTlQyufRC65JnImJ6H1Sf7BDj8bG31EV919NVEQc= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 h1:YAv5naMdpOFahnxteFFRidZlrSEwLv8V2nBKJKmLmHg= github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80 h1:XjHGfJhMwnB63DYHgtWGJgDxLhxVcAOtf+cfuvpGoyo= github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf h1:HhXi3qca3kyFEFPh0mqdr0bpQs94hJvMbUJztwPtf2A= github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf/go.mod h1:77PywuUvspdtoRuH1htFhR3Tp0pLyWj6kJlYR4tBYho= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -46,13 +67,21 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golift.io/cnfg v0.0.7 h1:qkNpP5Bq+5Gtoc6HcI8kapMD5zFOVan6qguxqBQF3OY= golift.io/cnfg v0.0.7/go.mod h1:AsB0DJe7nv0bizKaoy3e3MjjOF7upTpMOMvsfv4CNNk= golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= diff --git a/integrations/datadogunifi/ids.go b/integrations/datadogunifi/ids.go index f4bb29e3..a79b7bb8 100644 --- a/integrations/datadogunifi/ids.go +++ b/integrations/datadogunifi/ids.go @@ -1,7 +1,7 @@ package datadogunifi import ( - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) // reportIDS generates intrusion detection datapoints for Datadog. diff --git a/integrations/datadogunifi/logger.go b/integrations/datadogunifi/logger.go index a18029d3..eed2685e 100644 --- a/integrations/datadogunifi/logger.go +++ b/integrations/datadogunifi/logger.go @@ -1 +1,38 @@ package datadogunifi + +import ( + "fmt" + "time" + + "github.com/unpoller/webserver" +) + +// Logf logs a message. +func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { + webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "info"}, + }) + u.Collector.Logf(msg, v...) +} + +// LogErrorf logs an error message. +func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { + webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "error"}, + }) + u.Collector.LogErrorf(msg, v...) +} + +// LogDebugf logs a debug message. +func (u *DatadogUnifi) LogDebugf(msg string, v ...interface{}) { + webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "debug"}, + }) + u.Collector.LogDebugf(msg, v...) +} diff --git a/integrations/datadogunifi/points.go b/integrations/datadogunifi/points.go index 751c2114..c269ee78 100644 --- a/integrations/datadogunifi/points.go +++ b/integrations/datadogunifi/points.go @@ -2,20 +2,78 @@ package datadogunifi import ( "fmt" + + "github.com/unpoller/unifi" + "go.uber.org/zap" ) func tag(name string, value interface{}) string { return fmt.Sprintf("%s:%v", name, value) } +func tagMapToTags(tagMap map[string]string) []string { + tags := make([]string, 0) + for k, v := range tagMap { + tags = append(tags, tag(k, v)) + } + return tags +} + +func tagMapToZapFields(tagMap map[string]string) []zap.Field { + fields := make([]zap.Field, 0) + for k, v := range tagMap { + fields = append(fields, zap.String(k, v)) + } + return fields +} + func metricNamespace(namespace string) func(string) string { return func(name string) string { - return fmt.Sprintf("%s.%s", namespace, name) + return fmt.Sprintf("unifi.%s.%s", namespace, name) } } -func reportGaugeForMap(r report, metricName func(string) string, data map[string]float64, tags []string) { +func reportGaugeForFloat64Map(r report, metricName func(string) string, data map[string]float64, tags map[string]string) { for name, value := range data { - r.reportGauge(metricName(name), value, tags) + r.reportGauge(metricName(name), value, tagMapToTags(tags)) } } + +// cleanTags removes any tag that is empty. +func cleanTags(tags map[string]string) map[string]string { + for i := range tags { + if tags[i] == "" { + delete(tags, i) + } + } + + return tags +} + +// cleanFields removes any field with a default (or empty) value. +func cleanFields(fields map[string]interface{}) map[string]interface{} { //nolint:cyclop + for s := range fields { + switch v := fields[s].(type) { + case nil: + delete(fields, s) + case int, int64, float64: + if v == 0 { + delete(fields, s) + } + case unifi.FlexBool: + if v.Txt == "" { + delete(fields, s) + } + case unifi.FlexInt: + if v.Txt == "" { + delete(fields, s) + } + case string: + if v == "" { + delete(fields, s) + } + } + } + + return fields +} diff --git a/integrations/datadogunifi/report.go b/integrations/datadogunifi/report.go index 5450606c..e1ffaebc 100644 --- a/integrations/datadogunifi/report.go +++ b/integrations/datadogunifi/report.go @@ -1,39 +1,90 @@ package datadogunifi import ( + "sync" "time" "github.com/DataDog/datadog-go/statsd" - "github.com/unifi-poller/poller" + "github.com/unpoller/poller" + "go.uber.org/zap" ) type Report struct { Metrics *poller.Metrics + Events *poller.Events Errors []error - Total int - Fields int + Counts *Counts Start time.Time End time.Time Elapsed time.Duration + Logger *zap.SugaredLogger + + Total int + Fields int + + wg sync.WaitGroup + client statsd.ClientInterface } +// Counts holds counters and has a lock to deal with routines. +type Counts struct { + Val map[item]int + sync.RWMutex +} + type report interface { + add() + done() error(err error) metrics() *poller.Metrics + events() *poller.Events + addCount(item, ...int) + reportGauge(name string, value float64, tags []string) error reportCount(name string, value int64, tags []string) error reportDistribution(name string, value float64, tags []string) error reportTiming(name string, value time.Duration, tags []string) error - reportEvent(title string, message string, tags []string) error + reportEvent(title string, date time.Time, message string, tags []string) error + reportInfoLog(message string, f ...interface{}) + reportWarnLog(message string, f ...interface{}) reportServiceCheck(name string, status statsd.ServiceCheckStatus, message string, tags []string) error } +func (r *Report) add() { + r.wg.Add(1) +} + +func (r *Report) done() { + r.wg.Done() +} + func (r *Report) metrics() *poller.Metrics { return r.Metrics } +func (r *Report) events() *poller.Events { + return r.Events +} + +/* The following methods are not thread safe. */ + +type item string + +func (r *Report) addCount(name item, counts ...int) { + r.Counts.Lock() + defer r.Counts.Unlock() + + if len(counts) == 0 { + r.Counts.Val[name]++ + } + + for _, c := range counts { + r.Counts.Val[name] += c + } +} + func (r *Report) error(err error) { if err != nil { r.Errors = append(r.Errors, err) @@ -56,15 +107,26 @@ func (r *Report) reportTiming(name string, value time.Duration, tags []string) e return r.client.Timing(name, value, tags, 1.0) } -func (r *Report) reportEvent(title string, message string, tags []string) error { +func (r *Report) reportEvent(title string, date time.Time, message string, tags []string) error { + if date.IsZero() { + date = time.Now() + } return r.client.Event(&statsd.Event{ Title: title, Text: message, - Timestamp: time.Now(), + Timestamp: date, Tags: tags, }) } +func (r *Report) reportInfoLog(message string, f ...interface{}) { + r.Logger.Info(message, f) +} + +func (r *Report) reportWarnLog(message string, f ...interface{}) { + r.Logger.Warn(message, f) +} + func (r *Report) reportServiceCheck(name string, status statsd.ServiceCheckStatus, message string, tags []string) error { return r.client.ServiceCheck(&statsd.ServiceCheck{ Name: name, diff --git a/integrations/datadogunifi/site.go b/integrations/datadogunifi/site.go index a9ffe0a1..38c6e7c5 100644 --- a/integrations/datadogunifi/site.go +++ b/integrations/datadogunifi/site.go @@ -1,7 +1,7 @@ package datadogunifi import ( - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) // reportSite generates Unifi Sites' datapoints for Datadog. diff --git a/integrations/datadogunifi/uap.go b/integrations/datadogunifi/uap.go index 83403c12..37729fba 100644 --- a/integrations/datadogunifi/uap.go +++ b/integrations/datadogunifi/uap.go @@ -1,57 +1,93 @@ package datadogunifi import ( - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) -// reportUAP generates Wireless-Access-Point datapoints for InfluxDB. -// These points can be passed directly to influx. -func (u *DatadogUnifi) reportUAP(r report, s *unifi.UAP) { +// uapT is used as a name for printed/logged counters. +const uapT = item("UAP") + +// batchRogueAP generates metric points for neighboring access points. +func (u *DatadogUnifi) batchRogueAP(r report, s *unifi.RogueAP) { + if s.Age.Val == 0 { + return // only keep metrics for things that are recent. + } + + tags := cleanTags(map[string]string{ + "security": s.Security, + "oui": s.Oui, + "band": s.Band, + "mac": s.Bssid, + "ap_mac": s.ApMac, + "radio": s.Radio, + "radio_name": s.RadioName, + "site_name": s.SiteName, + "name": s.Essid, + "source": s.SourceName, + }) + + data := map[string]float64{ + "age": s.Age.Val, + "bw": s.Bw.Val, + "center_freq": s.CenterFreq.Val, + "channel": float64(s.Channel), + "freq": s.Freq.Val, + "noise": s.Noise.Val, + "rssi": s.Rssi.Val, + "rssi_age": s.RssiAge.Val, + "signal": s.Signal.Val, + } + + metricName := metricNamespace("uap_rogue") + + reportGaugeForFloat64Map(r, metricName, data, tags) +} + +// batchUAP generates Wireless-Access-Point datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) batchUAP(r report, s *unifi.UAP) { if !s.Adopted.Val || s.Locating.Val { return } - tags := []string{ - tag("ip", s.IP), - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - } + tags := cleanTags(map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + }) + data := CombineFloat64(u.processUAPstats(s.Stat.Ap), u.batchSysStats(s.SysStats, s.SystemStats)) + data["bytes"] = s.Bytes.Val + data["last_seen"] = s.LastSeen.Val + data["rx_bytes"] = s.RxBytes.Val + data["tx_bytes"] = s.TxBytes.Val + data["uptime"] = s.Uptime.Val + data["user_num_sta"] = s.UserNumSta.Val + data["guest_num_sta"] = s.GuestNumSta.Val + data["num_sta"] = s.NumSta.Val + + r.addCount(uapT) metricName := metricNamespace("uap") - u.reportUAPstats(s.Stat.Ap, r, metricName, tags) - u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + reportGaugeForFloat64Map(r, metricName, data, tags) - data := map[string]float64{ - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - "user-num_sta": s.UserNumSta.Val, - "guest-num_sta": s.GuestNumSta.Val, - "num_sta": s.NumSta.Val, - } - reportGaugeForMap(r, metricName, data, tags) - - u.reportRadTable(r, s.Name, s.SiteName, s.SourceName, s.RadioTable, s.RadioTableStats) - u.reportVAPTable(r, s.Name, s.SiteName, s.SourceName, s.VapTable) - u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) + u.processVAPTable(r, tags, s.VapTable) + u.batchPortTable(r, tags, s.PortTable) } -func (u *DatadogUnifi) reportUAPstats(ap *unifi.Ap, r report, metricName func(string) string, tags []string) { +func (u *DatadogUnifi) processUAPstats(ap *unifi.Ap) map[string]float64 { if ap == nil { - return + return map[string]float64{} } // Accumulative Statistics. - data := map[string]float64{ + return map[string]float64{ "stat_user-rx_packets": ap.UserRxPackets.Val, "stat_guest-rx_packets": ap.GuestRxPackets.Val, "stat_rx_packets": ap.RxPackets.Val, @@ -85,27 +121,26 @@ func (u *DatadogUnifi) reportUAPstats(ap *unifi.Ap, r report, metricName func(st "stat_user-tx_retries": ap.UserTxRetries.Val, "stat_guest-tx_retries": ap.GuestTxRetries.Val, } - reportGaugeForMap(r, metricName, data, tags) } -// reportVAPTable creates points for Wifi Radios. This works with several types of UAP-capable devices. -func (u *DatadogUnifi) reportVAPTable(r report, deviceName string, siteName string, source string, vt unifi.VapTable) { // nolint: funlen +// processVAPTable creates points for Wifi Radios. This works with several types of UAP-capable devices. +func (u *DatadogUnifi) processVAPTable(r report, t map[string]string, vt unifi.VapTable) { // nolint: funlen for _, s := range vt { - tags := []string{ - tag("device_name", deviceName), - tag("site_name", siteName), - tag("source", source), - tag("ap_mac", s.ApMac), - tag("bssid", s.Bssid), - tag("id", s.ID), - tag("name", s.Name), - tag("radio_name", s.RadioName), - tag("radio", s.Radio), - tag("essid", s.Essid), - tag("site_id", s.SiteID), - tag("usage", s.Usage), - tag("state", s.State), - tag("is_guest", s.IsGuest.Txt), + tags := map[string]string{ + "device_name": t["name"], + "site_name": t["site_name"], + "source": t["source"], + "ap_mac": s.ApMac, + "bssid": s.Bssid, + "id": s.ID, + "name": s.Name, + "radio_name": s.RadioName, + "radio": s.Radio, + "essid": s.Essid, + "site_id": s.SiteID, + "usage": s.Usage, + "state": s.State, + "is_guest": s.IsGuest.Txt, } data := map[string]float64{ "ccq": float64(s.Ccq), @@ -150,22 +185,23 @@ func (u *DatadogUnifi) reportVAPTable(r report, deviceName string, siteName stri } metricName := metricNamespace("uap_vaps") - reportGaugeForMap(r, metricName, data, tags) + + reportGaugeForFloat64Map(r, metricName, data, tags) } } -func (u *DatadogUnifi) reportRadTable(r report, deviceName string, siteName string, source string, rt unifi.RadioTable, rts unifi.RadioTableStats) { +func (u *DatadogUnifi) processRadTable(r report, t map[string]string, rt unifi.RadioTable, rts unifi.RadioTableStats) { for _, p := range rt { - tags := []string{ - tag("device_name", deviceName), - tag("site_name", siteName), - tag("source", source), - tag("channel", p.Channel.Txt), - tag("radio", p.Radio), + tags := map[string]string{ + "device_name": t["name"], + "site_name": t["site_name"], + "source": t["source"], + "channel": p.Channel.Txt, + "radio": p.Radio, + "ht": p.Ht.Txt, } data := map[string]float64{ "current_antenna_gain": p.CurrentAntennaGain.Val, - "ht": p.Ht.Val, "max_txpower": p.MaxTxpower.Val, "min_txpower": p.MinTxpower.Val, "nss": p.Nss.Val, @@ -181,12 +217,12 @@ func (u *DatadogUnifi) reportRadTable(r report, deviceName string, siteName stri data["cu_total"] = t.CuTotal.Val data["extchannel"] = t.Extchannel.Val data["gain"] = t.Gain.Val - data["guest-num_sta"] = t.GuestNumSta.Val + data["guest_num_sta"] = t.GuestNumSta.Val data["num_sta"] = t.NumSta.Val data["tx_packets"] = t.TxPackets.Val data["tx_power"] = t.TxPower.Val data["tx_retries"] = t.TxRetries.Val - data["user-num_sta"] = t.UserNumSta.Val + data["user_num_sta"] = t.UserNumSta.Val break } @@ -194,6 +230,6 @@ func (u *DatadogUnifi) reportRadTable(r report, deviceName string, siteName stri metricName := metricNamespace("uap_radios") - reportGaugeForMap(r, metricName, data, tags) + reportGaugeForFloat64Map(r, metricName, data, tags) } } diff --git a/integrations/datadogunifi/udm.go b/integrations/datadogunifi/udm.go index f544648b..4529086c 100644 --- a/integrations/datadogunifi/udm.go +++ b/integrations/datadogunifi/udm.go @@ -1,14 +1,44 @@ package datadogunifi import ( - "fmt" + "strconv" + "strings" - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) -// reportSysStats is used by all device types. -func (u *DatadogUnifi) reportSysStats(r report, metricName func(string) string, s unifi.SysStats, ss unifi.SystemStats, tags []string) { - data := map[string]float64{ +// udmT is used as a name for printed/logged counters. +const udmT = item("UDM") + +// Combine concatenates N maps. This will delete things if not used with caution. +func Combine(in ...map[string]interface{}) map[string]interface{} { + out := make(map[string]interface{}) + + for i := range in { + for k := range in[i] { + out[k] = in[i][k] + } + } + + return out +} + +// CombineFloat64 concatenates N maps. This will delete things if not used with caution. +func CombineFloat64(in ...map[string]float64) map[string]float64 { + out := make(map[string]float64) + + for i := range in { + for k := range in[i] { + out[k] = in[i][k] + } + } + + return out +} + +// batchSysStats is used by all device types. +func (u *DatadogUnifi) batchSysStats(s unifi.SysStats, ss unifi.SystemStats) map[string]float64 { + m := map[string]float64{ "loadavg_1": s.Loadavg1.Val, "loadavg_5": s.Loadavg5.Val, "loadavg_15": s.Loadavg15.Val, @@ -19,123 +49,148 @@ func (u *DatadogUnifi) reportSysStats(r report, metricName func(string) string, "mem": ss.Mem.Val, "system_uptime": ss.Uptime.Val, } - for name, value := range data { - r.reportGauge(metricName(name), value, tags) + + for k, v := range ss.Temps { + temp, _ := strconv.Atoi(strings.Split(v, " ")[0]) + k = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(k, " ", "_"), ")", ""), "(", "") + + if temp != 0 && k != "" { + m["temp_"+strings.ToLower(k)] = float64(temp) + } } + + return m } -func (u *DatadogUnifi) reportUDMtemps(r report, metricName func(string) string, tags []string, temps []unifi.Temperature) { +func (u *DatadogUnifi) batchUDMtemps(temps []unifi.Temperature) map[string]float64 { + output := make(map[string]float64) + for _, t := range temps { - name := fmt.Sprintf("temp_%s", t.Name) - r.reportGauge(metricName(name), t.Value, tags) + output["temp_"+t.Name] = t.Value } + + return output } -// reportUDM generates Unifi Gateway datapoints for InfluxDB. -// These points can be passed directly to influx. -func (u *DatadogUnifi) reportUDM(r report, s *unifi.UDM) { // nolint: funlen +func (u *DatadogUnifi) batchUDMstorage(storage []*unifi.Storage) map[string]float64 { + output := make(map[string]float64) + + for _, t := range storage { + output["storage_"+t.Name+"_size"] = t.Size.Val + output["storage_"+t.Name+"_used"] = t.Used.Val + + if t.Size.Val != 0 && t.Used.Val != 0 && t.Used.Val < t.Size.Val { + output["storage_"+t.Name+"_pct"] = t.Used.Val / t.Size.Val * 100 //nolint:gomnd + } else { + output["storage_"+t.Name+"_pct"] = 0 + } + } + + return output +} + +// batchUDM generates Unifi Gateway datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) batchUDM(r report, s *unifi.UDM) { // nolint: funlen if !s.Adopted.Val || s.Locating.Val { return } + tags := cleanTags(map[string]string{ + "source": s.SourceName, + "mac": s.Mac, + "site_name": s.SiteName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + "license_state": s.LicenseState, + }) + data := CombineFloat64( + u.batchUDMstorage(s.Storage), + u.batchUDMtemps(s.Temperatures), + u.batchUSGstats(s.SpeedtestStatus, s.Stat.Gw, s.Uplink), + u.batchSysStats(s.SysStats, s.SystemStats), + map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "guest-num_sta": s.GuestNumSta.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "num_desktop": s.NumDesktop.Val, + "num_handheld": s.NumHandheld.Val, + "num_mobile": s.NumMobile.Val, + }, + ) + + r.addCount(udmT) metricName := metricNamespace("usg") + reportGaugeForFloat64Map(r, metricName, data, tags) - tags := []string{ - tag("source", s.SourceName), - tag("ip", s.IP), - tag("license_state", s.LicenseState), - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - } - u.reportUDMtemps(r, metricName, tags, s.Temperatures) - u.reportUSGstats(r, metricName, tags, s.SpeedtestStatus, s.Stat.Gw, s.Uplink) - u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + u.batchNetTable(r, tags, s.NetworkTable) + u.batchUSGwans(r, tags, s.Wan1, s.Wan2) - data := map[string]float64{ - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "guest-num_sta": s.GuestNumSta.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, - "num_desktop": s.NumDesktop.Val, - "num_handheld": s.NumHandheld.Val, - "num_mobile": s.NumMobile.Val, - } - for name, value := range data { - r.reportGauge(metricName(name), value, tags) - } - u.reportNetTable(r, s.Name, s.SiteName, s.SourceName, s.NetworkTable) - u.reportUSGwans(r, s.Name, s.SiteName, s.SourceName, s.Wan1, s.Wan2) + tags = cleanTags(map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + }) + data = CombineFloat64( + u.batchUSWstat(s.Stat.Sw), + map[string]float64{ + "guest-num_sta": s.GuestNumSta.Val, + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + }) - tags = []string{ - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - tag("ip", s.IP), - } metricName = metricNamespace("usw") - u.reportUSWstat(r, metricName, tags, s.Stat.Sw) + reportGaugeForFloat64Map(r, metricName, data, tags) - data = map[string]float64{ - "guest-num_sta": s.GuestNumSta.Val, - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - } - for name, value := range data { - r.reportGauge(metricName(name), value, tags) - } - - u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) // udm has a usw in it. + u.batchPortTable(r, tags, s.PortTable) // udm has a usw in it. if s.Stat.Ap == nil { return // we're done now. the following code process UDM (non-pro) UAP data. } - tags = []string{ - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - } + tags = cleanTags(map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + }) + data = u.processUAPstats(s.Stat.Ap) + data["bytes"] = s.Bytes.Val + data["last_seen"] = s.LastSeen.Val + data["rx_bytes"] = s.RxBytes.Val + data["tx_bytes"] = s.TxBytes.Val + data["uptime"] = s.Uptime.Val + data["state"] = s.State.Val + data["user-num_sta"] = s.UserNumSta.Val + data["guest-num_sta"] = s.GuestNumSta.Val + data["num_sta"] = s.NumSta.Val metricName = metricNamespace("uap") - u.reportUAPstats(s.Stat.Ap, r, metricName, tags) + reportGaugeForFloat64Map(r, metricName, data, tags) - data = map[string]float64{ - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, - "guest-num_sta": s.GuestNumSta.Val, - "num_sta": s.NumSta.Val, - } - for name, value := range data { - r.reportGauge(metricName(name), value, tags) - } - - u.reportRadTable(r, s.Name, s.SiteName, s.SourceName, *s.RadioTable, *s.RadioTableStats) - u.reportVAPTable(r, s.Name, s.SiteName, s.SourceName, *s.VapTable) + u.processRadTable(r, tags, *s.RadioTable, *s.RadioTableStats) + u.processVAPTable(r, tags, *s.VapTable) } diff --git a/integrations/datadogunifi/usg.go b/integrations/datadogunifi/usg.go index 613c4c6c..269793c7 100644 --- a/integrations/datadogunifi/usg.go +++ b/integrations/datadogunifi/usg.go @@ -1,56 +1,65 @@ package datadogunifi import ( - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) -// reportUSG generates Unifi Gateway datapoints for Datadog. +// usgT is used as a name for printed/logged counters. +const usgT = item("USG") + +// batchUSG generates Unifi Gateway datapoints for Datadog. // These points can be passed directly to datadog. -func (u *DatadogUnifi) reportUSG(r report, s *unifi.USG) { +func (u *DatadogUnifi) batchUSG(r report, s *unifi.USG) { if !s.Adopted.Val || s.Locating.Val { return } - tags := []string{ - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - tag("ip", s.IP), - tag("license_state", s.LicenseState), + tags := map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + "license_state": s.LicenseState, } + data := CombineFloat64( + u.batchUDMtemps(s.Temperatures), + u.batchSysStats(s.SysStats, s.SystemStats), + u.batchUSGstats(s.SpeedtestStatus, s.Stat.Gw, s.Uplink), + map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "guest-num_sta": s.GuestNumSta.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "num_desktop": s.NumDesktop.Val, + "num_handheld": s.NumHandheld.Val, + "num_mobile": s.NumMobile.Val, + }, + ) + + r.addCount(usgT) + metricName := metricNamespace("usg") - u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) - u.reportUSGstats(r, metricName, tags, s.SpeedtestStatus, s.Stat.Gw, s.Uplink) + reportGaugeForFloat64Map(r, metricName, data, tags) - data := map[string]float64{ - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "guest-num_sta": s.GuestNumSta.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, - "num_desktop": s.NumDesktop.Val, - "num_handheld": s.NumHandheld.Val, - "num_mobile": s.NumMobile.Val, - } - reportGaugeForMap(r, metricName, data, tags) - - u.reportNetTable(r, s.Name, s.SiteName, s.SourceName, s.NetworkTable) - u.reportUSGwans(r, s.Name, s.SiteName, s.SourceName, s.Wan1, s.Wan2) + u.batchNetTable(r, tags, s.NetworkTable) + u.batchUSGwans(r, tags, s.Wan1, s.Wan2) } -func (u *DatadogUnifi) reportUSGstats(r report, metricName func(string) string, tags []string, ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) { +func (u *DatadogUnifi) batchUSGstats(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) map[string]float64 { if gw == nil { - return + return map[string]float64{} } - data := map[string]float64{ + + return map[string]float64{ "uplink_latency": ul.Latency.Val, "uplink_speed": ul.Speed.Val, "speedtest-status_latency": ss.Latency.Val, @@ -65,33 +74,32 @@ func (u *DatadogUnifi) reportUSGstats(r report, metricName func(string) string, "lan-tx_packets": gw.LanTxPackets.Val, "lan-rx_dropped": gw.LanRxDropped.Val, } - reportGaugeForMap(r, metricName, data, tags) } -func (u *DatadogUnifi) reportUSGwans(r report, deviceName string, siteName string, source string, wans ...unifi.Wan) { +func (u *DatadogUnifi) batchUSGwans(r report, tags map[string]string, wans ...unifi.Wan) { for _, wan := range wans { if !wan.Up.Val { continue } - tags := []string{ - tag("device_name", deviceName), - tag("site_name", siteName), - tag("source", source), - tag("ip", wan.IP), - tag("purpose", wan.Name), - tag("mac", wan.Mac), - tag("ifname", wan.Ifname), - tag("type", wan.Type), - tag("up", wan.Up.Txt), - tag("enabled", wan.Enable.Txt), - tag("gateway", wan.Gateway), - } - fullDuplex := float64(0) - if wan.FullDuplex.Val { - fullDuplex = 1 - } + tags := cleanTags(map[string]string{ + "device_name": tags["name"], + "site_name": tags["site_name"], + "source": tags["source"], + "ip": wan.IP, + "purpose": wan.Name, + "mac": wan.Mac, + "ifname": wan.Ifname, + "type": wan.Type, + "up": wan.Up.Txt, + "enabled": wan.Enable.Txt, + "gateway": wan.Gateway, + }) + fullDuplex := 0.0 + if wan.FullDuplex.Val { + fullDuplex = 1.0 + } data := map[string]float64{ "bytes-r": wan.BytesR.Val, "full_duplex": fullDuplex, @@ -112,26 +120,27 @@ func (u *DatadogUnifi) reportUSGwans(r report, deviceName string, siteName strin "tx_broadcast": wan.TxBroadcast.Val, "tx_multicast": wan.TxMulticast.Val, } - metricName := metricNamespace("usg_wan_ports") - reportGaugeForMap(r, metricName, data, tags) + + metricName := metricNamespace("usg.wan_ports") + reportGaugeForFloat64Map(r, metricName, data, tags) } } -func (u *DatadogUnifi) reportNetTable(r report, deviceName string, siteName string, source string, nt unifi.NetworkTable) { +func (u *DatadogUnifi) batchNetTable(r report, tags map[string]string, nt unifi.NetworkTable) { for _, p := range nt { - tags := []string{ - tag("device_name", deviceName), - tag("site_name", siteName), - tag("source", source), - tag("up", p.Up.Txt), - tag("enabled", p.Enabled.Txt), - tag("ip", p.IP), - tag("mac", p.Mac), - tag("name", p.Name), - tag("domain_name", p.DomainName), - tag("purpose", p.Purpose), - tag("is_guest", p.IsGuest.Txt), - } + tags := cleanTags(map[string]string{ + "device_name": tags["name"], + "site_name": tags["site_name"], + "source": tags["source"], + "up": p.Up.Txt, + "enabled": p.Enabled.Txt, + "ip": p.IP, + "mac": p.Mac, + "name": p.Name, + "domain_name": p.DomainName, + "purpose": p.Purpose, + "is_guest": p.IsGuest.Txt, + }) data := map[string]float64{ "num_sta": p.NumSta.Val, "rx_bytes": p.RxBytes.Val, @@ -139,7 +148,8 @@ func (u *DatadogUnifi) reportNetTable(r report, deviceName string, siteName stri "tx_bytes": p.TxBytes.Val, "tx_packets": p.TxPackets.Val, } - metricName := metricNamespace("usg_networks") - reportGaugeForMap(r, metricName, data, tags) + + metricName := metricNamespace("usg.networks") + reportGaugeForFloat64Map(r, metricName, data, tags) } } diff --git a/integrations/datadogunifi/usw.go b/integrations/datadogunifi/usw.go index 1dd4ea4b..9d0f7948 100644 --- a/integrations/datadogunifi/usw.go +++ b/integrations/datadogunifi/usw.go @@ -1,55 +1,60 @@ package datadogunifi import ( - "fmt" - - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) -// reportUSW generates Unifi Switch datapoints for Datadog. +// uswT is used as a name for printed/logged counters. +const uswT = item("USW") + +// batchUSW generates Unifi Switch datapoints for Datadog. // These points can be passed directly to datadog. -func (u *DatadogUnifi) reportUSW(r report, s *unifi.USW) { +func (u *DatadogUnifi) batchUSW(r report, s *unifi.USW) { if !s.Adopted.Val || s.Locating.Val { return } - tags := []string{ - tag("mac", s.Mac), - tag("site_name", s.SiteName), - tag("source", s.SourceName), - tag("name", s.Name), - tag("version", s.Version), - tag("model", s.Model), - tag("serial", s.Serial), - tag("type", s.Type), - tag("ip", s.IP), - } - metricName := metricNamespace("usw") - u.reportUSWstat(r, metricName, tags, s.Stat.Sw) - u.reportSysStats(r, metricName, s.SysStats, s.SystemStats, tags) + tags := cleanTags(map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + }) + data := CombineFloat64( + u.batchUSWstat(s.Stat.Sw), + u.batchSysStats(s.SysStats, s.SystemStats), + map[string]float64{ + "guest-num_sta": s.GuestNumSta.Val, - data := map[string]float64{ - "guest-num_sta": s.GuestNumSta.Val, - "bytes": s.Bytes.Val, - "fan_level": s.FanLevel.Val, - "general_temperature": s.GeneralTemperature.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, - } - reportGaugeForMap(r, metricName, data, tags) - u.reportPortTable(r, s.Name, s.SiteName, s.SourceName, s.Type, s.PortTable) + "bytes": s.Bytes.Val, + "fan_level": s.FanLevel.Val, + "general_temperature": s.GeneralTemperature.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + }) + + r.addCount(uswT) + metricName := metricNamespace("usw") + reportGaugeForFloat64Map(r, metricName, data, tags) + + u.batchPortTable(r, tags, s.PortTable) } -func (u *DatadogUnifi) reportUSWstat(r report, metricName func(string) string, tags []string, sw *unifi.Sw) { +func (u *DatadogUnifi) batchUSWstat(sw *unifi.Sw) map[string]float64 { if sw == nil { - return + return map[string]float64{} } - data := map[string]float64{ + return map[string]float64{ "stat_bytes": sw.Bytes.Val, "stat_rx_bytes": sw.RxBytes.Val, "stat_rx_crypts": sw.RxCrypts.Val, @@ -63,30 +68,35 @@ func (u *DatadogUnifi) reportUSWstat(r report, metricName func(string) string, t "stat_tx_packets": sw.TxPackets.Val, "stat_tx_retries": sw.TxRetries.Val, } - reportGaugeForMap(r, metricName, data, tags) } -func (u *DatadogUnifi) reportPortTable(r report, deviceName string, siteName string, source string, typeTag string, pt []unifi.Port) { +//nolint:funlen +func (u *DatadogUnifi) batchPortTable(r report, t map[string]string, pt []unifi.Port) { for _, p := range pt { - if !p.Up.Val || !p.Enable.Val { + if !u.DeadPorts && (!p.Up.Val || !p.Enable.Val) { continue // only record UP ports. } - tags := []string{ - tag("site_name", siteName), - tag("device_name", deviceName), - tag("source", source), - tag("type", typeTag), - tag("name", p.Name), - tag("poe_mode", p.PoeMode), - tag("port_poe", p.PortPoe.Txt), - tag("port_idx", p.PortIdx.Txt), - tag("port_id", fmt.Sprintf("%s_port_%s", deviceName, p.PortIdx.Txt)), - tag("poe_enable", p.PoeEnable.Txt), - tag("flowctrl_rx", p.FlowctrlRx.Txt), - tag("flowctrl_tx", p.FlowctrlTx.Txt), - tag("media", p.Media), - } + tags := cleanTags(map[string]string{ + "site_name": t["site_name"], + "device_name": t["name"], + "source": t["source"], + "type": t["type"], + "name": p.Name, + "poe_mode": p.PoeMode, + "port_poe": p.PortPoe.Txt, + "port_idx": p.PortIdx.Txt, + "port_id": t["name"] + " Port " + p.PortIdx.Txt, + "poe_enable": p.PoeEnable.Txt, + "flowctrl_rx": p.FlowctrlRx.Txt, + "flowctrl_tx": p.FlowctrlTx.Txt, + "media": p.Media, + "has_sfp": p.SFPFound.Txt, + "sfp_compliance": p.SFPCompliance, + "sfp_serial": p.SFPSerial, + "sfp_vendor": p.SFPVendor, + "sfp_part": p.SFPPart, + }) data := map[string]float64{ "dbytes_r": p.BytesR.Val, "rx_broadcast": p.RxBroadcast.Val, @@ -113,7 +123,15 @@ func (u *DatadogUnifi) reportPortTable(r report, deviceName string, siteName str data["poe_voltage"] = p.PoeVoltage.Val } - metricName := metricNamespace("usw_ports") - reportGaugeForMap(r, metricName, data, tags) + if p.SFPFound.Val { + data["sfp_current"] = p.SFPCurrent.Val + data["sfp_voltage"] = p.SFPVoltage.Val + data["sfp_temperature"] = p.SFPTemperature.Val + data["sfp_txpower"] = p.SFPTxpower.Val + data["sfp_rxpower"] = p.SFPRxpower.Val + } + + metricName := metricNamespace("usw.ports") + reportGaugeForFloat64Map(r, metricName, data, tags) } } diff --git a/integrations/datadogunifi/uxg.go b/integrations/datadogunifi/uxg.go index a18029d3..df92d9d8 100644 --- a/integrations/datadogunifi/uxg.go +++ b/integrations/datadogunifi/uxg.go @@ -1 +1,83 @@ package datadogunifi + +import ( + "github.com/unpoller/unifi" +) + +// uxgT is used as a name for printed/logged counters. +const uxgT = item("UXG") + +// batchUXG generates 10Gb Unifi Gateway datapoints for Datadog. +// These points can be passed directly to datadog. +func (u *DatadogUnifi) batchUXG(r report, s *unifi.UXG) { // nolint: funlen + if !s.Adopted.Val || s.Locating.Val { + return + } + + tags := cleanTags(map[string]string{ + "source": s.SourceName, + "mac": s.Mac, + "site_name": s.SiteName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + "license_state": s.LicenseState, + }) + data := CombineFloat64( + u.batchUDMstorage(s.Storage), + u.batchUDMtemps(s.Temperatures), + u.batchUSGstats(s.SpeedtestStatus, s.Stat.Gw, s.Uplink), + u.batchSysStats(s.SysStats, s.SystemStats), + map[string]float64{ + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "guest-num_sta": s.GuestNumSta.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + "state": s.State.Val, + "user-num_sta": s.UserNumSta.Val, + "num_desktop": s.NumDesktop.Val, + "num_handheld": s.NumHandheld.Val, + "num_mobile": s.NumMobile.Val, + }, + ) + + r.addCount(uxgT) + + metricName := metricNamespace("usg") + reportGaugeForFloat64Map(r, metricName, data, tags) + + u.batchNetTable(r, tags, s.NetworkTable) + u.batchUSGwans(r, tags, s.Wan1, s.Wan2) + + tags = cleanTags(map[string]string{ + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "name": s.Name, + "version": s.Version, + "model": s.Model, + "serial": s.Serial, + "type": s.Type, + "ip": s.IP, + }) + data = CombineFloat64( + u.batchUSWstat(s.Stat.Sw), + map[string]float64{ + "guest_num_sta": s.GuestNumSta.Val, + "bytes": s.Bytes.Val, + "last_seen": s.LastSeen.Val, + "rx_bytes": s.RxBytes.Val, + "tx_bytes": s.TxBytes.Val, + "uptime": s.Uptime.Val, + }) + + metricName = metricNamespace("usw") + reportGaugeForFloat64Map(r, metricName, data, tags) + + u.batchPortTable(r, tags, s.PortTable) // udm has a usw in it. +} From 16bb468d7d45c257c9f5ad72051d2d160ef749b9 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 16:22:53 -0600 Subject: [PATCH 11/25] add log when configured --- integrations/datadogunifi/datadog.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index af94e22b..5a1c4b2c 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -201,6 +201,7 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { u.Logger.Error("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil } + u.Logger.Info("Datadog is configured.") u.Collector = c u.setConfigDefaults() @@ -208,6 +209,7 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { var err error u.datadog, err = statsd.New(u.Address, u.options...) if err != nil { + u.Logger.Error("Error configuration Datadog agent reporting", zap.Error(err)) return err } From aaf062d4747bb7f76464807c897e59c52f716be3 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 16:45:06 -0600 Subject: [PATCH 12/25] fix syntax issues --- integrations/datadogunifi/alarms.go | 72 +++++------ integrations/datadogunifi/clients.go | 68 +++++----- integrations/datadogunifi/events.go | 184 +++++++++++++-------------- integrations/datadogunifi/ids.go | 12 +- integrations/datadogunifi/logger.go | 6 +- integrations/datadogunifi/site.go | 4 +- integrations/datadogunifi/uap.go | 2 +- integrations/datadogunifi/udm.go | 10 +- integrations/datadogunifi/usg.go | 32 ++--- integrations/datadogunifi/usw.go | 47 ++++--- integrations/datadogunifi/uxg.go | 4 +- 11 files changed, 220 insertions(+), 221 deletions(-) diff --git a/integrations/datadogunifi/alarms.go b/integrations/datadogunifi/alarms.go index dbbacd9b..9808f1d3 100644 --- a/integrations/datadogunifi/alarms.go +++ b/integrations/datadogunifi/alarms.go @@ -20,42 +20,42 @@ func (u *DatadogUnifi) batchAlarms(r report, event *unifi.Alarm) { // nolint:dup } tagMap := map[string]string{ - "dest_port": strconv.Itoa(event.DestPort), - "src_port": strconv.Itoa(event.SrcPort), - "dest_ip": event.DestIP, - "dst_mac": event.DstMAC, - "host": event.Host, - "msg": event.Msg, - "src_ip": event.SrcIP, - "src_mac": event.SrcMAC, - "dstip_asn": fmt.Sprintf("%d", event.DestIPGeo.Asn), - "dstip_latitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Latitude), - "dstip_longitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Longitude), - "dstip_city": event.DestIPGeo.City, - "dstip_continent_code": event.DestIPGeo.ContinentCode, - "dstip_country_code": event.DestIPGeo.CountryCode, - "dstip_country_name": event.DestIPGeo.CountryName, - "dstip_organization": event.DestIPGeo.Organization, - "srcip_asn": fmt.Sprintf("%d", event.SourceIPGeo.Asn), - "srcip_latitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Latitude), - "srcip_longitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Longitude), - "srcip_city": event.SourceIPGeo.City, - "srcip_continent_code": event.SourceIPGeo.ContinentCode, - "srcip_country_code": event.SourceIPGeo.CountryCode, - "srcip_country_name": event.SourceIPGeo.CountryName, - "srcip_organization": event.SourceIPGeo.Organization, - "site_name": event.SiteName, - "source": event.SourceName, - "in_iface": event.InIface, - "event_type": event.EventType, - "subsystem": event.Subsystem, - "archived": event.Archived.Txt, - "usgip": event.USGIP, - "proto": event.Proto, - "key": event.Key, - "catname": event.Catname, - "app_proto": event.AppProto, - "action": event.InnerAlertAction, + "dst_port": strconv.Itoa(event.DestPort), + "src_port": strconv.Itoa(event.SrcPort), + "dest_ip": event.DestIP, + "dst_mac": event.DstMAC, + "host": event.Host, + "msg": event.Msg, + "src_ip": event.SrcIP, + "src_mac": event.SrcMAC, + "dst_ip_asn": fmt.Sprintf("%d", event.DestIPGeo.Asn), + "dst_ip_latitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Latitude), + "dst_ip_longitude": fmt.Sprintf("%0.6f", event.DestIPGeo.Longitude), + "dst_ip_city": event.DestIPGeo.City, + "dst_ip_continent_code": event.DestIPGeo.ContinentCode, + "dst_ip_country_code": event.DestIPGeo.CountryCode, + "dst_ip_country_name": event.DestIPGeo.CountryName, + "dst_ip_organization": event.DestIPGeo.Organization, + "src_ip_asn": fmt.Sprintf("%d", event.SourceIPGeo.Asn), + "src_ip_latitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Latitude), + "src_ip_longitude": fmt.Sprintf("%0.6f", event.SourceIPGeo.Longitude), + "src_ip_city": event.SourceIPGeo.City, + "src_ip_continent_code": event.SourceIPGeo.ContinentCode, + "src_ip_country_code": event.SourceIPGeo.CountryCode, + "src_ip_country_name": event.SourceIPGeo.CountryName, + "src_ip_organization": event.SourceIPGeo.Organization, + "site_name": event.SiteName, + "source": event.SourceName, + "in_iface": event.InIface, + "event_type": event.EventType, + "subsystem": event.Subsystem, + "archived": event.Archived.Txt, + "usg_ip": event.USGIP, + "proto": event.Proto, + "key": event.Key, + "catname": event.Catname, + "app_proto": event.AppProto, + "action": event.InnerAlertAction, } r.addCount(alarmT) diff --git a/integrations/datadogunifi/clients.go b/integrations/datadogunifi/clients.go index a8422fee..8c2ef504 100644 --- a/integrations/datadogunifi/clients.go +++ b/integrations/datadogunifi/clients.go @@ -8,34 +8,34 @@ import ( // These points can be passed directly to Datadog. func (u *DatadogUnifi) batchClient(r report, s *unifi.Client) { // nolint: funlen tags := map[string]string{ - "mac": s.Mac, - "site_name": s.SiteName, - "source": s.SourceName, - "ap_name": s.ApName, - "gw_name": s.GwName, - "sw_name": s.SwName, - "oui": s.Oui, - "radio_name": s.RadioName, - "radio": s.Radio, - "radio_proto": s.RadioProto, - "name": s.Name, - "fixed_ip": s.FixedIP, - "sw_port": s.SwPort.Txt, - "os_class": s.OsClass.Txt, - "os_name": s.OsName.Txt, - "dev_cat": s.DevCat.Txt, - "dev_id": s.DevID.Txt, - "dev_vendor": s.DevVendor.Txt, - "dev_family": s.DevFamily.Txt, - "is_wired": s.IsWired.Txt, - "is_guest": s.IsGuest.Txt, - "use_fixedip": s.UseFixedIP.Txt, - "channel": s.Channel.Txt, - "vlan": s.Vlan.Txt, - "hostname": s.Name, - "essid": s.Essid, - "bssid": s.Bssid, - "ip": s.IP, + "mac": s.Mac, + "site_name": s.SiteName, + "source": s.SourceName, + "ap_name": s.ApName, + "gw_name": s.GwName, + "sw_name": s.SwName, + "oui": s.Oui, + "radio_name": s.RadioName, + "radio": s.Radio, + "radio_proto": s.RadioProto, + "name": s.Name, + "fixed_ip": s.FixedIP, + "sw_port": s.SwPort.Txt, + "os_class": s.OsClass.Txt, + "os_name": s.OsName.Txt, + "dev_cat": s.DevCat.Txt, + "dev_id": s.DevID.Txt, + "dev_vendor": s.DevVendor.Txt, + "dev_family": s.DevFamily.Txt, + "is_wired": s.IsWired.Txt, + "is_guest": s.IsGuest.Txt, + "use_fixed_ip": s.UseFixedIP.Txt, + "channel": s.Channel.Txt, + "vlan": s.Vlan.Txt, + "hostname": s.Name, + "essid": s.Essid, + "bssid": s.Bssid, + "ip": s.IP, } powerSaveEnabled := 0.0 if s.PowersaveEnabled.Val { @@ -64,12 +64,12 @@ func (u *DatadogUnifi) batchClient(r report, s *unifi.Client) { // nolint: funle "tx_rate": float64(s.TxRate), "uptime": float64(s.Uptime), "wifi_tx_attempts": float64(s.WifiTxAttempts), - "wired-rx_bytes": float64(s.WiredRxBytes), - "wired-rx_bytes-r": float64(s.WiredRxBytesR), - "wired-rx_packets": float64(s.WiredRxPackets), - "wired-tx_bytes": float64(s.WiredTxBytes), - "wired-tx_bytes-r": float64(s.WiredTxBytesR), - "wired-tx_packets": float64(s.WiredTxPackets), + "wired_rx_bytes": float64(s.WiredRxBytes), + "wired_rx_bytes-r": float64(s.WiredRxBytesR), + "wired_rx_packets": float64(s.WiredRxPackets), + "wired_tx_bytes": float64(s.WiredTxBytes), + "wired_tx_bytes-r": float64(s.WiredTxBytesR), + "wired_tx_packets": float64(s.WiredTxPackets), } metricName := metricNamespace("clients") diff --git a/integrations/datadogunifi/events.go b/integrations/datadogunifi/events.go index a95f3e25..76ffb164 100644 --- a/integrations/datadogunifi/events.go +++ b/integrations/datadogunifi/events.go @@ -21,42 +21,42 @@ func (u *DatadogUnifi) batchIDS(r report, i *unifi.IDS) { // nolint:dupl } tagMap := map[string]string{ - "dest_port": strconv.Itoa(i.DestPort), - "src_port": strconv.Itoa(i.SrcPort), - "dest_ip": i.DestIP, - "dst_mac": i.DstMAC, - "host": i.Host, - "msg": i.Msg, - "src_ip": i.SrcIP, - "src_mac": i.SrcMAC, - "dstip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), - "dstip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), - "dstip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), - "dstip_city": i.DestIPGeo.City, - "dstip_continent_code": i.DestIPGeo.ContinentCode, - "dstip_country_code": i.DestIPGeo.CountryCode, - "dstip_country_name": i.DestIPGeo.CountryName, - "dstip_organization": i.DestIPGeo.Organization, - "srcip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), - "srcip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), - "srcip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), - "srcip_city": i.SourceIPGeo.City, - "srcip_continent_code": i.SourceIPGeo.ContinentCode, - "srcip_country_code": i.SourceIPGeo.CountryCode, - "srcip_country_name": i.SourceIPGeo.CountryName, - "srcip_organization": i.SourceIPGeo.Organization, - "site_name": i.SiteName, - "source": i.SourceName, - "in_iface": i.InIface, - "event_type": i.EventType, - "subsystem": i.Subsystem, - "archived": i.Archived.Txt, - "usgip": i.USGIP, - "proto": i.Proto, - "key": i.Key, - "catname": i.Catname, - "app_proto": i.AppProto, - "action": i.InnerAlertAction, + "dest_port": strconv.Itoa(i.DestPort), + "src_port": strconv.Itoa(i.SrcPort), + "dest_ip": i.DestIP, + "dst_mac": i.DstMAC, + "host": i.Host, + "msg": i.Msg, + "src_ip": i.SrcIP, + "src_mac": i.SrcMAC, + "dst_ip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), + "dst_ip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), + "dst_ip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), + "dst_ip_city": i.DestIPGeo.City, + "dst_ip_continent_code": i.DestIPGeo.ContinentCode, + "dst_ip_country_code": i.DestIPGeo.CountryCode, + "dst_ip_country_name": i.DestIPGeo.CountryName, + "dst_ip_organization": i.DestIPGeo.Organization, + "src_ip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), + "src_ip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), + "src_ip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), + "src_ip_city": i.SourceIPGeo.City, + "src_ip_continent_code": i.SourceIPGeo.ContinentCode, + "src_ip_country_code": i.SourceIPGeo.CountryCode, + "src_ip_country_name": i.SourceIPGeo.CountryName, + "src_ip_organization": i.SourceIPGeo.Organization, + "site_name": i.SiteName, + "source": i.SourceName, + "in_iface": i.InIface, + "event_type": i.EventType, + "subsystem": i.Subsystem, + "archived": i.Archived.Txt, + "usg_ip": i.USGIP, + "proto": i.Proto, + "key": i.Key, + "catname": i.Catname, + "app_proto": i.AppProto, + "action": i.InnerAlertAction, } r.addCount(idsT) @@ -75,62 +75,62 @@ func (u *DatadogUnifi) batchEvent(r report, i *unifi.Event) { // nolint: funlen } tagMap := map[string]string{ - "guest": i.Guest, // mac address - "user": i.User, // mac address - "host": i.Host, // usg device? - "hostname": i.Hostname, // client name - "dest_port": strconv.Itoa(i.DestPort), - "src_port": strconv.Itoa(i.SrcPort), - "dest_ip": i.DestIP, - "dst_mac": i.DstMAC, - "ip": i.IP, - "src_ip": i.SrcIP, - "src_mac": i.SrcMAC, - "dstip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), - "dstip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), - "dstip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), - "dstip_city": i.DestIPGeo.City, - "dstip_continent_code": i.DestIPGeo.ContinentCode, - "dstip_country_code": i.DestIPGeo.CountryCode, - "dstip_country_name": i.DestIPGeo.CountryName, - "dstip_organization": i.DestIPGeo.Organization, - "srcip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), - "srcip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), - "srcip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), - "srcip_city": i.SourceIPGeo.City, - "srcip_continent_code": i.SourceIPGeo.ContinentCode, - "srcip_country_code": i.SourceIPGeo.CountryCode, - "srcip_country_name": i.SourceIPGeo.CountryName, - "srcip_organization": i.SourceIPGeo.Organization, - "admin": i.Admin, // username - "site_name": i.SiteName, - "source": i.SourceName, - "ap_from": i.ApFrom, - "ap_to": i.ApTo, - "ap": i.Ap, - "ap_name": i.ApName, - "gw": i.Gw, - "gw_name": i.GwName, - "sw": i.Sw, - "sw_name": i.SwName, - "catname": i.Catname, - "radio": i.Radio, - "radio_from": i.RadioFrom, - "radio_to": i.RadioTo, - "key": i.Key, - "in_iface": i.InIface, - "event_type": i.EventType, - "subsystem": i.Subsystem, - "ssid": i.SSID, - "is_admin": i.IsAdmin.Txt, - "channel": i.Channel.Txt, - "channel_from": i.ChannelFrom.Txt, - "channel_to": i.ChannelTo.Txt, - "usgip": i.USGIP, - "network": i.Network, - "app_proto": i.AppProto, - "proto": i.Proto, - "action": i.InnerAlertAction, + "guest": i.Guest, // mac address + "user": i.User, // mac address + "host": i.Host, // usg device? + "hostname": i.Hostname, // client name + "dest_port": strconv.Itoa(i.DestPort), + "src_port": strconv.Itoa(i.SrcPort), + "dst_ip": i.DestIP, + "dst_mac": i.DstMAC, + "ip": i.IP, + "src_ip": i.SrcIP, + "src_mac": i.SrcMAC, + "dst_ip_asn": fmt.Sprintf("%d", i.DestIPGeo.Asn), + "dst_ip_latitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Latitude), + "dst_ip_longitude": fmt.Sprintf("%0.6f", i.DestIPGeo.Longitude), + "dst_ip_city": i.DestIPGeo.City, + "dst_ip_continent_code": i.DestIPGeo.ContinentCode, + "dst_ip_country_code": i.DestIPGeo.CountryCode, + "dst_ip_country_name": i.DestIPGeo.CountryName, + "dst_ip_organization": i.DestIPGeo.Organization, + "src_ip_asn": fmt.Sprintf("%d", i.SourceIPGeo.Asn), + "src_ip_latitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Latitude), + "src_ip_longitude": fmt.Sprintf("%0.6f", i.SourceIPGeo.Longitude), + "src_ip_city": i.SourceIPGeo.City, + "src_ip_continent_code": i.SourceIPGeo.ContinentCode, + "src_ip_country_code": i.SourceIPGeo.CountryCode, + "src_ip_country_name": i.SourceIPGeo.CountryName, + "src_ip_organization": i.SourceIPGeo.Organization, + "admin": i.Admin, // username + "site_name": i.SiteName, + "source": i.SourceName, + "ap_from": i.ApFrom, + "ap_to": i.ApTo, + "ap": i.Ap, + "ap_name": i.ApName, + "gw": i.Gw, + "gw_name": i.GwName, + "sw": i.Sw, + "sw_name": i.SwName, + "catname": i.Catname, + "radio": i.Radio, + "radio_from": i.RadioFrom, + "radio_to": i.RadioTo, + "key": i.Key, + "in_iface": i.InIface, + "event_type": i.EventType, + "subsystem": i.Subsystem, + "ssid": i.SSID, + "is_admin": i.IsAdmin.Txt, + "channel": i.Channel.Txt, + "channel_from": i.ChannelFrom.Txt, + "channel_to": i.ChannelTo.Txt, + "usg_ip": i.USGIP, + "network": i.Network, + "app_proto": i.AppProto, + "proto": i.Proto, + "action": i.InnerAlertAction, } r.addCount(eventT) diff --git a/integrations/datadogunifi/ids.go b/integrations/datadogunifi/ids.go index a79b7bb8..90bdaef7 100644 --- a/integrations/datadogunifi/ids.go +++ b/integrations/datadogunifi/ids.go @@ -14,12 +14,12 @@ func (u *DatadogUnifi) reportIDS(r report, i *unifi.IDS) { tag("event_type", i.EventType), tag("proto", i.Proto), tag("app_proto", i.AppProto), - tag("usgip", i.Usgip), - tag("country_code", i.SrcipGeo.CountryCode), - tag("country_name", i.SrcipGeo.CountryName), - tag("city", i.SrcipGeo.City), - tag("srcipASN", i.SrcipASN), - tag("usgipASN", i.UsgipASN), + tag("usg_ip", i.USGIP), + tag("country_code", i.SourceIPGeo.CountryCode), + tag("country_name", i.SourceIPGeo.CountryName), + tag("city", i.SourceIPGeo.City), + tag("src_ip_ASN", i.SrcIPASN), + tag("usg_ip_ASN", i.USGIPASN), tag("alert_category", i.InnerAlertCategory), tag("subsystem", i.Subsystem), tag("catname", i.Catname), diff --git a/integrations/datadogunifi/logger.go b/integrations/datadogunifi/logger.go index eed2685e..c223fb7c 100644 --- a/integrations/datadogunifi/logger.go +++ b/integrations/datadogunifi/logger.go @@ -9,7 +9,7 @@ import ( // Logf logs a message. func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { - webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ Ts: time.Now(), Msg: fmt.Sprintf(msg, v...), Tags: map[string]string{"type": "info"}, @@ -19,7 +19,7 @@ func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { // LogErrorf logs an error message. func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { - webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ Ts: time.Now(), Msg: fmt.Sprintf(msg, v...), Tags: map[string]string{"type": "error"}, @@ -29,7 +29,7 @@ func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { // LogDebugf logs a debug message. func (u *DatadogUnifi) LogDebugf(msg string, v ...interface{}) { - webserver.NewOutputEvent(PluginName, PluginName, &webserver.Event{ + webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ Ts: time.Now(), Msg: fmt.Sprintf(msg, v...), Tags: map[string]string{"type": "debug"}, diff --git a/integrations/datadogunifi/site.go b/integrations/datadogunifi/site.go index 38c6e7c5..f21dbc8a 100644 --- a/integrations/datadogunifi/site.go +++ b/integrations/datadogunifi/site.go @@ -26,8 +26,8 @@ func (u *DatadogUnifi) reportSite(r report, s *unifi.Site) { "num_user": h.NumUser.Val, "num_guest": h.NumGuest.Val, "num_iot": h.NumIot.Val, - "tx_bytes-r": h.TxBytesR.Val, - "rx_bytes-r": h.RxBytesR.Val, + "tx_bytes_r": h.TxBytesR.Val, + "rx_bytes_r": h.RxBytesR.Val, "num_ap": h.NumAp.Val, "num_adopted": h.NumAdopted.Val, "num_disabled": h.NumDisabled.Val, diff --git a/integrations/datadogunifi/uap.go b/integrations/datadogunifi/uap.go index 37729fba..62ebe3ae 100644 --- a/integrations/datadogunifi/uap.go +++ b/integrations/datadogunifi/uap.go @@ -215,7 +215,7 @@ func (u *DatadogUnifi) processRadTable(r report, t map[string]string, rt unifi.R data["cu_self_rx"] = t.CuSelfRx.Val data["cu_self_tx"] = t.CuSelfTx.Val data["cu_total"] = t.CuTotal.Val - data["extchannel"] = t.Extchannel.Val + data["ext_channel"] = t.Extchannel.Val data["gain"] = t.Gain.Val data["guest_num_sta"] = t.GuestNumSta.Val data["num_sta"] = t.NumSta.Val diff --git a/integrations/datadogunifi/udm.go b/integrations/datadogunifi/udm.go index 4529086c..796beb95 100644 --- a/integrations/datadogunifi/udm.go +++ b/integrations/datadogunifi/udm.go @@ -116,12 +116,12 @@ func (u *DatadogUnifi) batchUDM(r report, s *unifi.UDM) { // nolint: funlen map[string]float64{ "bytes": s.Bytes.Val, "last_seen": s.LastSeen.Val, - "guest-num_sta": s.GuestNumSta.Val, + "guest_num_sta": s.GuestNumSta.Val, "rx_bytes": s.RxBytes.Val, "tx_bytes": s.TxBytes.Val, "uptime": s.Uptime.Val, "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, + "user_num_sta": s.UserNumSta.Val, "num_desktop": s.NumDesktop.Val, "num_handheld": s.NumHandheld.Val, "num_mobile": s.NumMobile.Val, @@ -149,7 +149,7 @@ func (u *DatadogUnifi) batchUDM(r report, s *unifi.UDM) { // nolint: funlen data = CombineFloat64( u.batchUSWstat(s.Stat.Sw), map[string]float64{ - "guest-num_sta": s.GuestNumSta.Val, + "guest_num_sta": s.GuestNumSta.Val, "bytes": s.Bytes.Val, "last_seen": s.LastSeen.Val, "rx_bytes": s.RxBytes.Val, @@ -184,8 +184,8 @@ func (u *DatadogUnifi) batchUDM(r report, s *unifi.UDM) { // nolint: funlen data["tx_bytes"] = s.TxBytes.Val data["uptime"] = s.Uptime.Val data["state"] = s.State.Val - data["user-num_sta"] = s.UserNumSta.Val - data["guest-num_sta"] = s.GuestNumSta.Val + data["user_num_sta"] = s.UserNumSta.Val + data["guest_num_sta"] = s.GuestNumSta.Val data["num_sta"] = s.NumSta.Val metricName = metricNamespace("uap") diff --git a/integrations/datadogunifi/usg.go b/integrations/datadogunifi/usg.go index 269793c7..95065e27 100644 --- a/integrations/datadogunifi/usg.go +++ b/integrations/datadogunifi/usg.go @@ -33,12 +33,12 @@ func (u *DatadogUnifi) batchUSG(r report, s *unifi.USG) { map[string]float64{ "bytes": s.Bytes.Val, "last_seen": s.LastSeen.Val, - "guest-num_sta": s.GuestNumSta.Val, + "guest_num_sta": s.GuestNumSta.Val, "rx_bytes": s.RxBytes.Val, "tx_bytes": s.TxBytes.Val, "uptime": s.Uptime.Val, "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, + "user_num_sta": s.UserNumSta.Val, "num_desktop": s.NumDesktop.Val, "num_handheld": s.NumHandheld.Val, "num_mobile": s.NumMobile.Val, @@ -62,17 +62,17 @@ func (u *DatadogUnifi) batchUSGstats(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul return map[string]float64{ "uplink_latency": ul.Latency.Val, "uplink_speed": ul.Speed.Val, - "speedtest-status_latency": ss.Latency.Val, - "speedtest-status_runtime": ss.Runtime.Val, - "speedtest-status_rundate": ss.Rundate.Val, - "speedtest-status_ping": ss.StatusPing.Val, - "speedtest-status_xput_download": ss.XputDownload.Val, - "speedtest-status_xput_upload": ss.XputUpload.Val, - "lan-rx_bytes": gw.LanRxBytes.Val, - "lan-rx_packets": gw.LanRxPackets.Val, - "lan-tx_bytes": gw.LanTxBytes.Val, - "lan-tx_packets": gw.LanTxPackets.Val, - "lan-rx_dropped": gw.LanRxDropped.Val, + "speedtest_status_latency": ss.Latency.Val, + "speedtest_status_runtime": ss.Runtime.Val, + "speedtest_status_rundate": ss.Rundate.Val, + "speedtest_status_ping": ss.StatusPing.Val, + "speedtest_status_xput_download": ss.XputDownload.Val, + "speedtest_status_xput_upload": ss.XputUpload.Val, + "lan_rx_bytes": gw.LanRxBytes.Val, + "lan_rx_packets": gw.LanRxPackets.Val, + "lan_tx_bytes": gw.LanTxBytes.Val, + "lan_tx_packets": gw.LanTxPackets.Val, + "lan_rx_dropped": gw.LanRxDropped.Val, } } @@ -101,11 +101,11 @@ func (u *DatadogUnifi) batchUSGwans(r report, tags map[string]string, wans ...un fullDuplex = 1.0 } data := map[string]float64{ - "bytes-r": wan.BytesR.Val, + "bytes_r": wan.BytesR.Val, "full_duplex": fullDuplex, "max_speed": wan.MaxSpeed.Val, "rx_bytes": wan.RxBytes.Val, - "rx_bytes-r": wan.RxBytesR.Val, + "rx_bytes_r": wan.RxBytesR.Val, "rx_dropped": wan.RxDropped.Val, "rx_errors": wan.RxErrors.Val, "rx_broadcast": wan.RxBroadcast.Val, @@ -113,7 +113,7 @@ func (u *DatadogUnifi) batchUSGwans(r report, tags map[string]string, wans ...un "rx_packets": wan.RxPackets.Val, "speed": wan.Speed.Val, "tx_bytes": wan.TxBytes.Val, - "tx_bytes-r": wan.TxBytesR.Val, + "tx_bytes_r": wan.TxBytesR.Val, "tx_dropped": wan.TxDropped.Val, "tx_errors": wan.TxErrors.Val, "tx_packets": wan.TxPackets.Val, diff --git a/integrations/datadogunifi/usw.go b/integrations/datadogunifi/usw.go index 9d0f7948..aac3ae0b 100644 --- a/integrations/datadogunifi/usw.go +++ b/integrations/datadogunifi/usw.go @@ -29,8 +29,7 @@ func (u *DatadogUnifi) batchUSW(r report, s *unifi.USW) { u.batchUSWstat(s.Stat.Sw), u.batchSysStats(s.SysStats, s.SystemStats), map[string]float64{ - "guest-num_sta": s.GuestNumSta.Val, - + "guest_num_sta": s.GuestNumSta.Val, "bytes": s.Bytes.Val, "fan_level": s.FanLevel.Val, "general_temperature": s.GeneralTemperature.Val, @@ -39,7 +38,7 @@ func (u *DatadogUnifi) batchUSW(r report, s *unifi.USW) { "tx_bytes": s.TxBytes.Val, "uptime": s.Uptime.Val, "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, + "user_num_sta": s.UserNumSta.Val, }) r.addCount(uswT) @@ -88,8 +87,8 @@ func (u *DatadogUnifi) batchPortTable(r report, t map[string]string, pt []unifi. "port_idx": p.PortIdx.Txt, "port_id": t["name"] + " Port " + p.PortIdx.Txt, "poe_enable": p.PoeEnable.Txt, - "flowctrl_rx": p.FlowctrlRx.Txt, - "flowctrl_tx": p.FlowctrlTx.Txt, + "flow_ctrl_rx": p.FlowctrlRx.Txt, + "flow_ctrl_tx": p.FlowctrlTx.Txt, "media": p.Media, "has_sfp": p.SFPFound.Txt, "sfp_compliance": p.SFPCompliance, @@ -98,23 +97,23 @@ func (u *DatadogUnifi) batchPortTable(r report, t map[string]string, pt []unifi. "sfp_part": p.SFPPart, }) data := map[string]float64{ - "dbytes_r": p.BytesR.Val, - "rx_broadcast": p.RxBroadcast.Val, - "rx_bytes": p.RxBytes.Val, - "rx_bytes-r": p.RxBytesR.Val, - "rx_dropped": p.RxDropped.Val, - "rx_errors": p.RxErrors.Val, - "rx_multicast": p.RxMulticast.Val, - "rx_packets": p.RxPackets.Val, - "speed": p.Speed.Val, - "stp_pathcost": p.StpPathcost.Val, - "tx_broadcast": p.TxBroadcast.Val, - "tx_bytes": p.TxBytes.Val, - "tx_bytes-r": p.TxBytesR.Val, - "tx_dropped": p.TxDropped.Val, - "tx_errors": p.TxErrors.Val, - "tx_multicast": p.TxMulticast.Val, - "tx_packets": p.TxPackets.Val, + "bytes_r": p.BytesR.Val, + "rx_broadcast": p.RxBroadcast.Val, + "rx_bytes": p.RxBytes.Val, + "rx_bytes_r": p.RxBytesR.Val, + "rx_dropped": p.RxDropped.Val, + "rx_errors": p.RxErrors.Val, + "rx_multicast": p.RxMulticast.Val, + "rx_packets": p.RxPackets.Val, + "speed": p.Speed.Val, + "stp_path_cost": p.StpPathcost.Val, + "tx_broadcast": p.TxBroadcast.Val, + "tx_bytes": p.TxBytes.Val, + "tx_bytes_r": p.TxBytesR.Val, + "tx_dropped": p.TxDropped.Val, + "tx_errors": p.TxErrors.Val, + "tx_multicast": p.TxMulticast.Val, + "tx_packets": p.TxPackets.Val, } if p.PoeEnable.Val && p.PortPoe.Val { @@ -127,8 +126,8 @@ func (u *DatadogUnifi) batchPortTable(r report, t map[string]string, pt []unifi. data["sfp_current"] = p.SFPCurrent.Val data["sfp_voltage"] = p.SFPVoltage.Val data["sfp_temperature"] = p.SFPTemperature.Val - data["sfp_txpower"] = p.SFPTxpower.Val - data["sfp_rxpower"] = p.SFPRxpower.Val + data["sfp_tx_power"] = p.SFPTxpower.Val + data["sfp_rx_power"] = p.SFPRxpower.Val } metricName := metricNamespace("usw.ports") diff --git a/integrations/datadogunifi/uxg.go b/integrations/datadogunifi/uxg.go index df92d9d8..c79f5e05 100644 --- a/integrations/datadogunifi/uxg.go +++ b/integrations/datadogunifi/uxg.go @@ -34,12 +34,12 @@ func (u *DatadogUnifi) batchUXG(r report, s *unifi.UXG) { // nolint: funlen map[string]float64{ "bytes": s.Bytes.Val, "last_seen": s.LastSeen.Val, - "guest-num_sta": s.GuestNumSta.Val, + "guest_num_sta": s.GuestNumSta.Val, "rx_bytes": s.RxBytes.Val, "tx_bytes": s.TxBytes.Val, "uptime": s.Uptime.Val, "state": s.State.Val, - "user-num_sta": s.UserNumSta.Val, + "user_num_sta": s.UserNumSta.Val, "num_desktop": s.NumDesktop.Val, "num_handheld": s.NumHandheld.Val, "num_mobile": s.NumMobile.Val, From f17912202581fcaf25c35c69cf1778a2170d37b1 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 16:56:56 -0600 Subject: [PATCH 13/25] mirror unpoller/unpoller go mod --- integrations/datadogunifi/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index e4001308..234ae25d 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -1,6 +1,6 @@ module github.com/platinummonkey/datadogunifi -go 1.15 +go 1.16 require ( github.com/DataDog/datadog-go v4.0.0+incompatible From 8730b0c2afacf928643c83e0209b68bb69953cf9 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 17:01:45 -0600 Subject: [PATCH 14/25] use corrected version of unpoller/unifi --- integrations/datadogunifi/go.mod | 2 +- integrations/datadogunifi/go.sum | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index 234ae25d..f91fe14c 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -6,7 +6,7 @@ require ( github.com/DataDog/datadog-go v4.0.0+incompatible github.com/pkg/errors v0.9.1 // indirect github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 - github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80 + github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf go.uber.org/zap v1.19.1 golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index 16bdb5f0..6d87660a 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -2,33 +2,42 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v4.0.0+incompatible h1:Dq8Dr+4sV1gBO1sHDWdW+4G+PdsA+YSJOK925MxrrCY= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c h1:zqmyTlQyufRC65JnImJ6H1Sf7BDj8bG31EV919NVEQc= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 h1:YAv5naMdpOFahnxteFFRidZlrSEwLv8V2nBKJKmLmHg= github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= -github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80 h1:XjHGfJhMwnB63DYHgtWGJgDxLhxVcAOtf+cfuvpGoyo= -github.com/unpoller/unifi v0.0.9-0.20210623100314-3dccfdbc4c80/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= +github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 h1:OYfAGqNNevU4ARJL1yE1v7VUvce1gJEsgzAxCH23cYQ= +github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf h1:HhXi3qca3kyFEFPh0mqdr0bpQs94hJvMbUJztwPtf2A= github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf/go.mod h1:77PywuUvspdtoRuH1htFhR3Tp0pLyWj6kJlYR4tBYho= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -79,8 +88,10 @@ golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 5faa0791b2614556f2f4b26c44d4858f0d977733 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 17:28:20 -0600 Subject: [PATCH 15/25] all latest commits --- integrations/datadogunifi/go.mod | 2 +- integrations/datadogunifi/go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index f91fe14c..c82ba227 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/DataDog/datadog-go v4.0.0+incompatible github.com/pkg/errors v0.9.1 // indirect - github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 + github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf go.uber.org/zap v1.19.1 diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index 6d87660a..fc2a130f 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -28,8 +28,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28 h1:YAv5naMdpOFahnxteFFRidZlrSEwLv8V2nBKJKmLmHg= github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= +github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e h1:tNBIBCmtc7whuhkjKyEzpU3OHzYHyGCBy/LERhHxh3A= +github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 h1:OYfAGqNNevU4ARJL1yE1v7VUvce1gJEsgzAxCH23cYQ= github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf h1:HhXi3qca3kyFEFPh0mqdr0bpQs94hJvMbUJztwPtf2A= From cca20ab019575b3630f1a3e79ae399eb66c3baab Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 9 Dec 2021 17:36:45 -0600 Subject: [PATCH 16/25] fix nil client in report --- integrations/datadogunifi/datadog.go | 1 + 1 file changed, 1 insertion(+) diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 5a1c4b2c..33baf172 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -260,6 +260,7 @@ func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics, e *poller.Events) (*Repo Start: time.Now(), Counts: &Counts{Val: make(map[item]int)}, Logger: u.Logger, + client: u.datadog, } // batch all the points. u.loopPoints(r) From e366b15c69dca86912a24a836f69cec3ddc035fa Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Mon, 17 Jan 2022 15:02:57 -0600 Subject: [PATCH 17/25] final cleanup of datadog unifi plugin --- integrations/datadogunifi/alarms.go | 4 +- integrations/datadogunifi/datadog.go | 64 +++++++++++++++------------- integrations/datadogunifi/events.go | 4 +- integrations/datadogunifi/go.mod | 5 +-- integrations/datadogunifi/go.sum | 41 +----------------- integrations/datadogunifi/logger.go | 22 ---------- integrations/datadogunifi/points.go | 10 ++--- integrations/datadogunifi/report.go | 8 ++-- 8 files changed, 51 insertions(+), 107 deletions(-) diff --git a/integrations/datadogunifi/alarms.go b/integrations/datadogunifi/alarms.go index 9808f1d3..7db18b9c 100644 --- a/integrations/datadogunifi/alarms.go +++ b/integrations/datadogunifi/alarms.go @@ -63,7 +63,7 @@ func (u *DatadogUnifi) batchAlarms(r report, event *unifi.Alarm) { // nolint:dup tags := tagMapToTags(tagMap) title := fmt.Sprintf("[%s][%s] Alarm at %s from %s", event.EventType, event.Catname, event.SiteName, event.SourceName) r.reportEvent(title, event.Datetime, event.Msg, tags) - r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", event.Datetime.Unix(), title, event.Msg), tagMapToZapFields(tagMap)) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s - %s", event.Datetime.Unix(), title, event.Msg, tagMapToSimpleStrings(tagMap))) } // batchAnomaly generates Anomalies from UniFi for Datadog. @@ -84,5 +84,5 @@ func (u *DatadogUnifi) batchAnomaly(r report, event *unifi.Anomaly) { title := fmt.Sprintf("Anomaly detected at %s from %s", event.SiteName, event.SourceName) r.reportEvent(title, event.Datetime, event.Anomaly, tags) - r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", event.Datetime.Unix(), title, event.Anomaly), tagMapToZapFields(tagMap)) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s - %s", event.Datetime.Unix(), title, event.Anomaly, tagMapToSimpleStrings(tagMap))) } diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 33baf172..9b1ac76d 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -3,12 +3,12 @@ package datadogunifi import ( + "reflect" "time" "github.com/DataDog/datadog-go/statsd" "github.com/unpoller/poller" "github.com/unpoller/unifi" - "go.uber.org/zap" "golift.io/cnfg" ) @@ -109,13 +109,11 @@ type DatadogUnifi struct { Collector poller.Collect datadog statsd.ClientInterface LastCheck time.Time - Logger *zap.SugaredLogger *Datadog } func init() { // nolint: gochecknoinits - l, _ := zap.NewProduction() - u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now(), Logger: l.Sugar()} + u := &DatadogUnifi{Datadog: &Datadog{}, LastCheck: time.Now()} poller.NewOutput(&poller.Output{ Name: "datadog", @@ -192,16 +190,15 @@ func (u *DatadogUnifi) setConfigDefaults() { // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { - defer u.Logger.Sync() if u.Disable { - u.Logger.Debug("Datadog config is disabled, output is disabled.") + u.LogDebugf("Datadog config is disabled, output is disabled.") return nil } if u.Config == nil && !u.Disable { - u.Logger.Error("DataDog config is missing and is not disabled: Datadog output is disabled!") + u.LogErrorf("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil } - u.Logger.Info("Datadog is configured.") + u.Logf("Datadog is configured.") u.Collector = c u.setConfigDefaults() @@ -209,7 +206,7 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { var err error u.datadog, err = statsd.New(u.Address, u.options...) if err != nil { - u.Logger.Error("Error configuration Datadog agent reporting", zap.Error(err)) + u.LogErrorf("Error configuration Datadog agent reporting: %+v", err) return err } @@ -223,25 +220,25 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { func (u *DatadogUnifi) PollController() { interval := u.Interval.Round(time.Second) ticker := time.NewTicker(interval) - u.Logger.Info("Everything checks out! Poller started", zap.Duration("interval", interval)) + u.Logf("Everything checks out! Poller started, interval=%+v", interval) for u.LastCheck = range ticker.C { metrics, err := u.Collector.Metrics(&poller.Filter{Name: "unifi"}) if err != nil { - u.Logger.Error("metric fetch for Datadog failed", zap.Error(err)) + u.LogErrorf("metric fetch for Datadog failed: %v", err) continue } events, err := u.Collector.Events(&poller.Filter{Name: "unifi", Dur: interval}) if err != nil { - u.Logger.Error("event fetch for Datadog failed", zap.Error(err)) + u.LogErrorf("event fetch for Datadog failed", err) continue } report, err := u.ReportMetrics(metrics, events) if err != nil { // Is the agent down? - u.Logger.Error("unable to report metrics and events", zap.Error(err)) + u.LogErrorf("unable to report metrics and events", err) report.reportCount("unifi.collect.errors", 1, []string{}) continue } @@ -255,12 +252,12 @@ func (u *DatadogUnifi) PollController() { // Returns an error if datadog statsd calls fail, otherwise returns a report. func (u *DatadogUnifi) ReportMetrics(m *poller.Metrics, e *poller.Events) (*Report, error) { r := &Report{ - Metrics: m, - Events: e, - Start: time.Now(), - Counts: &Counts{Val: make(map[item]int)}, - Logger: u.Logger, - client: u.datadog, + Metrics: m, + Events: e, + Start: time.Now(), + Counts: &Counts{Val: make(map[item]int)}, + Collector: u.Collector, + client: u.datadog, } // batch all the points. u.loopPoints(r) @@ -335,21 +332,30 @@ func (u *DatadogUnifi) switchExport(r report, v interface{}) { //nolint:cyclop case *unifi.Anomaly: u.batchAnomaly(r, v) default: - u.Logger.Error("invalid export", zap.Reflect("type", v)) + u.LogErrorf("invalid export, type=%+v", reflect.TypeOf(v)) } } // LogDatadogReport writes a log message after exporting to Datadog. func (u *DatadogUnifi) LogDatadogReport(r *Report) { m := r.Metrics - u.Logger.Info("UniFi Metrics Recorded", - zap.Int("num_sites", len(m.Sites)), - zap.Int("num_sites_dpi", len(m.SitesDPI)), - zap.Int("num_clients", len(m.Clients)), - zap.Int("num_clients_dpi", len(m.ClientsDPI)), - zap.Int("num_rogue_ap", len(m.RogueAPs)), - zap.Int("num_devices", len(m.Devices)), - zap.Errors("errors", r.Errors), - zap.Duration("elapsed", r.Elapsed), + u.Logf("UniFi Metrics Recorded num_sites=%d num_sites_dpi=%d num_clients=%d num_clients_dpi=%d num_rogue_ap=%d num_devices=%d errors=%v elapsec=%v", + len(m.Sites), + len(m.SitesDPI), + len(m.Clients), + len(m.ClientsDPI), + len(m.RogueAPs), + len(m.Devices), + r.Errors, + r.Elapsed, ) + metricName := metricNamespace("collector") + r.reportCount(metricName("num_sites"), int64(len(m.Sites)), u.Tags) + r.reportCount(metricName("num_sites_dpi"), int64(len(m.SitesDPI)), u.Tags) + r.reportCount(metricName("num_clients"), int64(len(m.Clients)), u.Tags) + r.reportCount(metricName("num_clients_dpi"), int64(len(m.ClientsDPI)), u.Tags) + r.reportCount(metricName("num_rogue_ap"), int64(len(m.RogueAPs)), u.Tags) + r.reportCount(metricName("num_devices"), int64(len(m.Devices)), u.Tags) + r.reportCount(metricName("num_errors"), int64(len(r.Errors)), u.Tags) + r.reportTiming(metricName("elapsed_time"), r.Elapsed, u.Tags) } diff --git a/integrations/datadogunifi/events.go b/integrations/datadogunifi/events.go index 76ffb164..ce0b0c4a 100644 --- a/integrations/datadogunifi/events.go +++ b/integrations/datadogunifi/events.go @@ -65,7 +65,7 @@ func (u *DatadogUnifi) batchIDS(r report, i *unifi.IDS) { // nolint:dupl tags := tagMapToTags(tagMap) title := fmt.Sprintf("Intrusion Detection at %s from %s", i.SiteName, i.SourceName) r.reportEvent(title, i.Datetime, i.Msg, tags) - r.reportWarnLog(fmt.Sprintf("[%d] %s: %s", i.Datetime.Unix(), title, i.Msg), tagMapToZapFields(tagMap)) + r.reportWarnLog(fmt.Sprintf("[%d] %s: %s - %s", i.Datetime.Unix(), title, i.Msg, tagMapToSimpleStrings(tagMap))) } // batchEvents generates events from UniFi for Datadog. @@ -139,5 +139,5 @@ func (u *DatadogUnifi) batchEvent(r report, i *unifi.Event) { // nolint: funlen tags := tagMapToTags(tagMap) title := fmt.Sprintf("Unifi Event at %s from %s", i.SiteName, i.SourceName) r.reportEvent(title, i.Datetime, i.Msg, tags) - r.reportInfoLog(fmt.Sprintf("[%d] %s: %s", i.Datetime.Unix(), title, i.Msg), tagMapToZapFields(tagMap)) + r.reportInfoLog(fmt.Sprintf("[%d] %s: %s - %s", i.Datetime.Unix(), title, i.Msg, tagMapToSimpleStrings(tagMap))) } diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index c82ba227..ecf221c6 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -4,11 +4,10 @@ go 1.16 require ( github.com/DataDog/datadog-go v4.0.0+incompatible - github.com/pkg/errors v0.9.1 // indirect + github.com/kr/pretty v0.1.0 // indirect github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 - github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf - go.uber.org/zap v1.19.1 golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect golift.io/cnfg v0.0.7 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index fc2a130f..e5fb6216 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -2,71 +2,41 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v4.0.0+incompatible h1:Dq8Dr+4sV1gBO1sHDWdW+4G+PdsA+YSJOK925MxrrCY= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c h1:zqmyTlQyufRC65JnImJ6H1Sf7BDj8bG31EV919NVEQc= github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/unpoller/poller v0.0.0-20210623101401-f12841d79a28/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e h1:tNBIBCmtc7whuhkjKyEzpU3OHzYHyGCBy/LERhHxh3A= github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 h1:OYfAGqNNevU4ARJL1yE1v7VUvce1gJEsgzAxCH23cYQ= github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= -github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf h1:HhXi3qca3kyFEFPh0mqdr0bpQs94hJvMbUJztwPtf2A= -github.com/unpoller/webserver v0.0.0-20210623101543-90d89bb0acdf/go.mod h1:77PywuUvspdtoRuH1htFhR3Tp0pLyWj6kJlYR4tBYho= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -77,23 +47,14 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golift.io/cnfg v0.0.7 h1:qkNpP5Bq+5Gtoc6HcI8kapMD5zFOVan6qguxqBQF3OY= golift.io/cnfg v0.0.7/go.mod h1:AsB0DJe7nv0bizKaoy3e3MjjOF7upTpMOMvsfv4CNNk= golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE= golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= diff --git a/integrations/datadogunifi/logger.go b/integrations/datadogunifi/logger.go index c223fb7c..29801bc5 100644 --- a/integrations/datadogunifi/logger.go +++ b/integrations/datadogunifi/logger.go @@ -1,38 +1,16 @@ package datadogunifi -import ( - "fmt" - "time" - - "github.com/unpoller/webserver" -) - // Logf logs a message. func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { - webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ - Ts: time.Now(), - Msg: fmt.Sprintf(msg, v...), - Tags: map[string]string{"type": "info"}, - }) u.Collector.Logf(msg, v...) } // LogErrorf logs an error message. func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { - webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ - Ts: time.Now(), - Msg: fmt.Sprintf(msg, v...), - Tags: map[string]string{"type": "error"}, - }) u.Collector.LogErrorf(msg, v...) } // LogDebugf logs a debug message. func (u *DatadogUnifi) LogDebugf(msg string, v ...interface{}) { - webserver.NewOutputEvent(webserver.PluginName, webserver.PluginName, &webserver.Event{ - Ts: time.Now(), - Msg: fmt.Sprintf(msg, v...), - Tags: map[string]string{"type": "debug"}, - }) u.Collector.LogDebugf(msg, v...) } diff --git a/integrations/datadogunifi/points.go b/integrations/datadogunifi/points.go index c269ee78..a4af569c 100644 --- a/integrations/datadogunifi/points.go +++ b/integrations/datadogunifi/points.go @@ -2,9 +2,9 @@ package datadogunifi import ( "fmt" + "strings" "github.com/unpoller/unifi" - "go.uber.org/zap" ) func tag(name string, value interface{}) string { @@ -19,12 +19,12 @@ func tagMapToTags(tagMap map[string]string) []string { return tags } -func tagMapToZapFields(tagMap map[string]string) []zap.Field { - fields := make([]zap.Field, 0) +func tagMapToSimpleStrings(tagMap map[string]string) string { + result := "" for k, v := range tagMap { - fields = append(fields, zap.String(k, v)) + result = fmt.Sprintf("%s%s=\"%v\", ", result, k, v) } - return fields + return strings.TrimRight(result, ", ") } func metricNamespace(namespace string) func(string) string { diff --git a/integrations/datadogunifi/report.go b/integrations/datadogunifi/report.go index e1ffaebc..f86a1cfd 100644 --- a/integrations/datadogunifi/report.go +++ b/integrations/datadogunifi/report.go @@ -6,9 +6,9 @@ import ( "github.com/DataDog/datadog-go/statsd" "github.com/unpoller/poller" - "go.uber.org/zap" ) +// Report is a will report the current collection run data. type Report struct { Metrics *poller.Metrics Events *poller.Events @@ -18,7 +18,7 @@ type Report struct { End time.Time Elapsed time.Duration - Logger *zap.SugaredLogger + Collector poller.Collect Total int Fields int @@ -120,11 +120,11 @@ func (r *Report) reportEvent(title string, date time.Time, message string, tags } func (r *Report) reportInfoLog(message string, f ...interface{}) { - r.Logger.Info(message, f) + r.Collector.Logf(message, f) } func (r *Report) reportWarnLog(message string, f ...interface{}) { - r.Logger.Warn(message, f) + r.Collector.Logf(message, f) } func (r *Report) reportServiceCheck(name string, status statsd.ServiceCheckStatus, message string, tags []string) error { From 1756fe7ccc1b969bbdf3709ec74e795399b7518c Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Mon, 17 Jan 2022 15:07:09 -0600 Subject: [PATCH 18/25] fix go mod --- integrations/datadogunifi/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index ecf221c6..bec4d6f2 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -1,4 +1,4 @@ -module github.com/platinummonkey/datadogunifi +module github.com/unpoller/datadogunifi go 1.16 From 27187efdf89f1d06fc268d4f22c057dd684b7bf5 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Tue, 18 Jan 2022 08:39:42 -0600 Subject: [PATCH 19/25] address golangci-lint --- integrations/datadogunifi/.travis.yml | 2 +- integrations/datadogunifi/datadog.go | 2 +- integrations/datadogunifi/ids.go | 30 --------------------------- integrations/datadogunifi/points.go | 30 --------------------------- 4 files changed, 2 insertions(+), 62 deletions(-) delete mode 100644 integrations/datadogunifi/ids.go diff --git a/integrations/datadogunifi/.travis.yml b/integrations/datadogunifi/.travis.yml index 909e2741..eaf8a5eb 100644 --- a/integrations/datadogunifi/.travis.yml +++ b/integrations/datadogunifi/.travis.yml @@ -7,4 +7,4 @@ before_install: - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest script: - go test ./... -- golangci-lint run --enable-all +- golangci-lint run --disable errcheck diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index 9b1ac76d..db268231 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -101,7 +101,7 @@ type Config struct { // Datadog allows the data to be context aware with configuration type Datadog struct { *Config `json:"datadog" toml:"datadog" xml:"datadog" yaml:"datadog"` - options []statsd.Option + options []statsd.Option // nolint } // DatadogUnifi is returned by New() after you provide a Config. diff --git a/integrations/datadogunifi/ids.go b/integrations/datadogunifi/ids.go deleted file mode 100644 index 90bdaef7..00000000 --- a/integrations/datadogunifi/ids.go +++ /dev/null @@ -1,30 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// reportIDS generates intrusion detection datapoints for Datadog. -// These points can be passed directly to datadog. -func (u *DatadogUnifi) reportIDS(r report, i *unifi.IDS) { - tags := []string{ - tag("site_name", i.SiteName), - tag("source", i.SourceName), - tag("in_iface", i.InIface), - tag("event_type", i.EventType), - tag("proto", i.Proto), - tag("app_proto", i.AppProto), - tag("usg_ip", i.USGIP), - tag("country_code", i.SourceIPGeo.CountryCode), - tag("country_name", i.SourceIPGeo.CountryName), - tag("city", i.SourceIPGeo.City), - tag("src_ip_ASN", i.SrcIPASN), - tag("usg_ip_ASN", i.USGIPASN), - tag("alert_category", i.InnerAlertCategory), - tag("subsystem", i.Subsystem), - tag("catname", i.Catname), - } - - metricName := metricNamespace("intrusion_detect") - r.reportCount(metricName("count"), 1, tags) -} diff --git a/integrations/datadogunifi/points.go b/integrations/datadogunifi/points.go index a4af569c..8c6832ee 100644 --- a/integrations/datadogunifi/points.go +++ b/integrations/datadogunifi/points.go @@ -3,8 +3,6 @@ package datadogunifi import ( "fmt" "strings" - - "github.com/unpoller/unifi" ) func tag(name string, value interface{}) string { @@ -49,31 +47,3 @@ func cleanTags(tags map[string]string) map[string]string { return tags } - -// cleanFields removes any field with a default (or empty) value. -func cleanFields(fields map[string]interface{}) map[string]interface{} { //nolint:cyclop - for s := range fields { - switch v := fields[s].(type) { - case nil: - delete(fields, s) - case int, int64, float64: - if v == 0 { - delete(fields, s) - } - case unifi.FlexBool: - if v.Txt == "" { - delete(fields, s) - } - case unifi.FlexInt: - if v.Txt == "" { - delete(fields, s) - } - case string: - if v == "" { - delete(fields, s) - } - } - } - - return fields -} From 1dcea47a762402326289e0d87df40e3f1d5bbe7c Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 27 Oct 2022 16:17:37 -0500 Subject: [PATCH 20/25] fix nil pointer bug --- integrations/datadogunifi/datadog.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index db268231..e5e4e3c7 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -198,9 +198,8 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { u.LogErrorf("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil } - u.Logf("Datadog is configured.") - u.Collector = c + u.Logf("Datadog is configured.") u.setConfigDefaults() var err error From 8b3a8b37ffd98d5e77456a08ddce4ac013856163 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Thu, 27 Oct 2022 16:25:49 -0500 Subject: [PATCH 21/25] golanglint-ci is gone from travis --- integrations/datadogunifi/.travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integrations/datadogunifi/.travis.yml b/integrations/datadogunifi/.travis.yml index eaf8a5eb..dd5ff174 100644 --- a/integrations/datadogunifi/.travis.yml +++ b/integrations/datadogunifi/.travis.yml @@ -1,10 +1,9 @@ language: go go: - 1.14.x -- 1.15.x +- 1.18.x before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest script: - go test ./... -- golangci-lint run --disable errcheck From 5b04503cf9a4a7eb1f4cf0c58698845ad8cbc561 Mon Sep 17 00:00:00 2001 From: Daniel Schauenberg Date: Wed, 9 Nov 2022 11:43:16 +0100 Subject: [PATCH 22/25] move collector initialization up in Run method all logging methods rely on the collector being initialized. When this isn't the case logging anything causes the whole app to crash with a nil pointer dereference. Specifically the datadog plugin causes unpoller to crash when it's disabled because it write a debug log on an uninitialized collector. --- integrations/datadogunifi/datadog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index e5e4e3c7..d074b0e1 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -190,6 +190,7 @@ func (u *DatadogUnifi) setConfigDefaults() { // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { + u.Collector = c if u.Disable { u.LogDebugf("Datadog config is disabled, output is disabled.") return nil @@ -198,7 +199,6 @@ func (u *DatadogUnifi) Run(c poller.Collect) error { u.LogErrorf("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil } - u.Collector = c u.Logf("Datadog is configured.") u.setConfigDefaults() From 2164d6f502dbf1f68d075e5d4296fc7671a62338 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Wed, 23 Nov 2022 18:07:38 -0600 Subject: [PATCH 23/25] nil guard when disabled datadog plugin for logging --- integrations/datadogunifi/logger.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/integrations/datadogunifi/logger.go b/integrations/datadogunifi/logger.go index 29801bc5..eddf5313 100644 --- a/integrations/datadogunifi/logger.go +++ b/integrations/datadogunifi/logger.go @@ -2,15 +2,21 @@ package datadogunifi // Logf logs a message. func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { - u.Collector.Logf(msg, v...) + if u.Collector != nil { + u.Collector.Logf(msg, v...) + } } // LogErrorf logs an error message. func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { - u.Collector.LogErrorf(msg, v...) + if u.Collector != nil { + u.Collector.LogErrorf(msg, v...) + } } // LogDebugf logs a debug message. func (u *DatadogUnifi) LogDebugf(msg string, v ...interface{}) { - u.Collector.LogDebugf(msg, v...) + if u.Collector != nil { + u.Collector.LogDebugf(msg, v...) + } } From 8f3e94758abb5037d1c4f94fad7562ded25feb2f Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Wed, 23 Nov 2022 19:04:01 -0600 Subject: [PATCH 24/25] update unpoller/unifi --- integrations/datadogunifi/go.mod | 2 +- integrations/datadogunifi/go.sum | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/integrations/datadogunifi/go.mod b/integrations/datadogunifi/go.mod index bec4d6f2..4107ab01 100644 --- a/integrations/datadogunifi/go.mod +++ b/integrations/datadogunifi/go.mod @@ -6,7 +6,7 @@ require ( github.com/DataDog/datadog-go v4.0.0+incompatible github.com/kr/pretty v0.1.0 // indirect github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e - github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 + github.com/unpoller/unifi v0.0.0-20221124010147-8d83427af67b golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect golift.io/cnfg v0.0.7 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/integrations/datadogunifi/go.sum b/integrations/datadogunifi/go.sum index e5fb6216..05ad81c6 100644 --- a/integrations/datadogunifi/go.sum +++ b/integrations/datadogunifi/go.sum @@ -21,19 +21,14 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e h1:tNBIBCmtc7whuhkjKyEzpU3OHzYHyGCBy/LERhHxh3A= github.com/unpoller/poller v0.0.0-20210623104748-50161c195d5e/go.mod h1:AbDp60t5WlLSRELAliMJ0RFQpm/0yXpyolVSZqNtero= -github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3 h1:OYfAGqNNevU4ARJL1yE1v7VUvce1gJEsgzAxCH23cYQ= -github.com/unpoller/unifi v0.0.0-20210914213836-fd3c38c905a3/go.mod h1:K9QFFGfZws4gzB+Popix19S/rBKqrtqI+tyPORyg3F0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +github.com/unpoller/unifi v0.0.0-20221124010147-8d83427af67b h1:QMDlntRuc73sVRBMa3VO82p9gDzyub4sgLxaKwK4nHo= +github.com/unpoller/unifi v0.0.0-20221124010147-8d83427af67b/go.mod h1:pJGPtjikPcYO+rZMpgYOj6Zs044Dl4R+u3MsV3TMenk= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -43,7 +38,6 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 47bdfa7bec64057ad766dc5110bcb5eb284add35 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Wed, 23 Nov 2022 19:15:55 -0600 Subject: [PATCH 25/25] disable check --- integrations/datadogunifi/datadog.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/integrations/datadogunifi/datadog.go b/integrations/datadogunifi/datadog.go index d074b0e1..37630cc1 100644 --- a/integrations/datadogunifi/datadog.go +++ b/integrations/datadogunifi/datadog.go @@ -28,7 +28,7 @@ type Config struct { DeadPorts bool `json:"dead_ports,omitempty" toml:"dead_ports,omitempty" xml:"dead_ports,omitempty" yaml:"dead_ports,omitempty"` // Disable when true disables this output plugin - Disable bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"` + Disable *bool `json:"disable" toml:"disable" xml:"disable,attr" yaml:"disable"` // Address determines how to talk to the Datadog agent Address string `json:"address" toml:"address" xml:"address,attr" yaml:"address"` @@ -191,11 +191,12 @@ func (u *DatadogUnifi) setConfigDefaults() { // Run runs a ticker to poll the unifi server and update Datadog. func (u *DatadogUnifi) Run(c poller.Collect) error { u.Collector = c - if u.Disable { + disabled := u.Disable == nil || *u.Disable == true + if disabled { u.LogDebugf("Datadog config is disabled, output is disabled.") return nil } - if u.Config == nil && !u.Disable { + if u.Config == nil && !disabled { u.LogErrorf("DataDog config is missing and is not disabled: Datadog output is disabled!") return nil }