From ae49aeee039b871b794844cfdea64e6bc4a9884f Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Sat, 3 Dec 2022 16:10:54 -0600 Subject: [PATCH] mark as moved --- README.md | 81 +----------- alarms.go | 88 ------------- clients.go | 189 ---------------------------- datadog.go | 361 ----------------------------------------------------- events.go | 143 --------------------- go.mod | 13 -- go.sum | 55 -------- logger.go | 22 ---- points.go | 49 -------- report.go | 138 -------------------- site.go | 80 ------------ uap.go | 235 ---------------------------------- udm.go | 196 ----------------------------- usg.go | 155 ----------------------- usw.go | 136 -------------------- uxg.go | 83 ------------ 16 files changed, 1 insertion(+), 2023 deletions(-) delete mode 100644 alarms.go delete mode 100644 clients.go delete mode 100644 datadog.go delete mode 100644 events.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 logger.go delete mode 100644 points.go delete mode 100644 report.go delete mode 100644 site.go delete mode 100644 uap.go delete mode 100644 udm.go delete mode 100644 usg.go delete mode 100644 usw.go delete mode 100644 uxg.go diff --git a/README.md b/README.md index a375528..9b9e4da 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,4 @@ # datadogunifi -UniFi Poller Output Plugin for DataDog +Moved to https://github.com/unpoller/unpoller/tree/master/pkg/datadogunifi -## 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/alarms.go b/alarms.go deleted file mode 100644 index 7db18b9..0000000 --- a/alarms.go +++ /dev/null @@ -1,88 +0,0 @@ -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{ - "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) - - 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 - %s", event.Datetime.Unix(), title, event.Msg, tagMapToSimpleStrings(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 - %s", event.Datetime.Unix(), title, event.Anomaly, tagMapToSimpleStrings(tagMap))) -} diff --git a/clients.go b/clients.go deleted file mode 100644 index 8c2ef50..0000000 --- a/clients.go +++ /dev/null @@ -1,189 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// 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_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 { - 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), - } - - metricName := metricNamespace("clients") - - 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) 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 := 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("client_dpi") - - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} - -// fillDPIMapTotals fills in totals for categories and applications. maybe clients too. -// 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) - } - - 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 := 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("client_dpi") - - reportGaugeForFloat64Map(r, metricName, data, tags) - } - } - } - } -} diff --git a/datadog.go b/datadog.go deleted file mode 100644 index 37630cc..0000000 --- a/datadog.go +++ /dev/null @@ -1,361 +0,0 @@ -// Package datadogunifi provides the methods to turn UniFi measurements into Datadog -// data points with appropriate tags and fields. -package datadogunifi - -import ( - "reflect" - "time" - - "github.com/DataDog/datadog-go/statsd" - "github.com/unpoller/poller" - "github.com/unpoller/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"` - - // 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 - 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 *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 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. - 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"` -} - -// 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 // nolint -} - -// DatadogUnifi is returned by New() after you provide a Config. -type DatadogUnifi struct { - Collector poller.Collect - datadog statsd.ClientInterface - LastCheck time.Time - *Datadog -} - -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, 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 { - u.Collector = c - disabled := u.Disable == nil || *u.Disable == true - if disabled { - u.LogDebugf("Datadog config is disabled, output is disabled.") - return nil - } - if u.Config == nil && !disabled { - u.LogErrorf("DataDog config is missing and is not disabled: Datadog output is disabled!") - return nil - } - u.Logf("Datadog is configured.") - u.setConfigDefaults() - - var err error - u.datadog, err = statsd.New(u.Address, u.options...) - if err != nil { - u.LogErrorf("Error configuration Datadog agent reporting: %+v", err) - return err - } - - u.PollController() - - return nil -} - -// 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) - ticker := time.NewTicker(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.LogErrorf("metric fetch for Datadog failed: %v", err) - continue - } - - events, err := u.Collector.Events(&poller.Filter{Name: "unifi", Dur: interval}) - if err != nil { - u.LogErrorf("event fetch for Datadog failed", err) - continue - } - - report, err := u.ReportMetrics(metrics, events) - if err != nil { - // Is the agent down? - u.LogErrorf("unable to report metrics and events", err) - report.reportCount("unifi.collect.errors", 1, []string{}) - continue - } - report.reportCount("unifi.collect.success", 1, []string{}) - 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, e *poller.Events) (*Report, error) { - r := &Report{ - 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) - r.End = time.Now() - r.Elapsed = r.End.Sub(r.Start) - r.reportTiming("unifi.collector_timing", r.Elapsed, []string{}) - return r, nil -} - -// loopPoints collects all the data to immediately report to Datadog. -func (u *DatadogUnifi) loopPoints(r report) { - m := r.metrics() - - for _, s := range m.RogueAPs { - u.switchExport(r, s) - } - - for _, s := range m.Sites { - 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.batchClientDPI(r, s, appTotal, catTotal) - } - - reportClientDPItotals(r, appTotal, catTotal) -} - -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.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.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/events.go b/events.go deleted file mode 100644 index ce0b0c4..0000000 --- a/events.go +++ /dev/null @@ -1,143 +0,0 @@ -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, - "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) - - 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 - %s", i.Datetime.Unix(), title, i.Msg, tagMapToSimpleStrings(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), - "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) - - 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 - %s", i.Datetime.Unix(), title, i.Msg, tagMapToSimpleStrings(tagMap))) -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 4107ab0..0000000 --- a/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module github.com/unpoller/datadogunifi - -go 1.16 - -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-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/go.sum b/go.sum deleted file mode 100644 index 05ad81c..0000000 --- a/go.sum +++ /dev/null @@ -1,55 +0,0 @@ -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/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/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/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.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/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-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-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-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.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 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.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= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/logger.go b/logger.go deleted file mode 100644 index eddf531..0000000 --- a/logger.go +++ /dev/null @@ -1,22 +0,0 @@ -package datadogunifi - -// Logf logs a message. -func (u *DatadogUnifi) Logf(msg string, v ...interface{}) { - if u.Collector != nil { - u.Collector.Logf(msg, v...) - } -} - -// LogErrorf logs an error message. -func (u *DatadogUnifi) LogErrorf(msg string, v ...interface{}) { - if u.Collector != nil { - u.Collector.LogErrorf(msg, v...) - } -} - -// LogDebugf logs a debug message. -func (u *DatadogUnifi) LogDebugf(msg string, v ...interface{}) { - if u.Collector != nil { - u.Collector.LogDebugf(msg, v...) - } -} diff --git a/points.go b/points.go deleted file mode 100644 index 8c6832e..0000000 --- a/points.go +++ /dev/null @@ -1,49 +0,0 @@ -package datadogunifi - -import ( - "fmt" - "strings" -) - -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 tagMapToSimpleStrings(tagMap map[string]string) string { - result := "" - for k, v := range tagMap { - result = fmt.Sprintf("%s%s=\"%v\", ", result, k, v) - } - return strings.TrimRight(result, ", ") -} - -func metricNamespace(namespace string) func(string) string { - return func(name string) string { - return fmt.Sprintf("unifi.%s.%s", namespace, name) - } -} - -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, 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 -} diff --git a/report.go b/report.go deleted file mode 100644 index f86a1cf..0000000 --- a/report.go +++ /dev/null @@ -1,138 +0,0 @@ -package datadogunifi - -import ( - "sync" - "time" - - "github.com/DataDog/datadog-go/statsd" - "github.com/unpoller/poller" -) - -// Report is a will report the current collection run data. -type Report struct { - Metrics *poller.Metrics - Events *poller.Events - Errors []error - Counts *Counts - Start time.Time - End time.Time - Elapsed time.Duration - - Collector poller.Collect - - 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, 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) - } -} - -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, 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: date, - Tags: tags, - }) -} - -func (r *Report) reportInfoLog(message string, f ...interface{}) { - r.Collector.Logf(message, f) -} - -func (r *Report) reportWarnLog(message string, f ...interface{}) { - r.Collector.Logf(message, f) -} - -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/site.go b/site.go deleted file mode 100644 index f21dbc8..0000000 --- a/site.go +++ /dev/null @@ -1,80 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// 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/uap.go b/uap.go deleted file mode 100644 index 62ebe3a..0000000 --- a/uap.go +++ /dev/null @@ -1,235 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// 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 := 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") - - reportGaugeForFloat64Map(r, metricName, data, tags) - - u.processVAPTable(r, tags, s.VapTable) - u.batchPortTable(r, tags, s.PortTable) -} - -func (u *DatadogUnifi) processUAPstats(ap *unifi.Ap) map[string]float64 { - if ap == nil { - return map[string]float64{} - } - - // Accumulative Statistics. - return 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, - } -} - -// 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 := 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), - "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") - - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} - -func (u *DatadogUnifi) processRadTable(r report, t map[string]string, rt unifi.RadioTable, rts unifi.RadioTableStats) { - for _, p := range rt { - 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, - "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["ext_channel"] = 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") - - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} diff --git a/udm.go b/udm.go deleted file mode 100644 index 796beb9..0000000 --- a/udm.go +++ /dev/null @@ -1,196 +0,0 @@ -package datadogunifi - -import ( - "strconv" - "strings" - - "github.com/unpoller/unifi" -) - -// 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, - "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 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) batchUDMtemps(temps []unifi.Temperature) map[string]float64 { - output := make(map[string]float64) - - for _, t := range temps { - output["temp_"+t.Name] = t.Value - } - - return output -} - -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) - - 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. - - if s.Stat.Ap == nil { - return // we're done now. the following code process UDM (non-pro) UAP data. - } - - 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") - reportGaugeForFloat64Map(r, metricName, data, tags) - - u.processRadTable(r, tags, *s.RadioTable, *s.RadioTableStats) - u.processVAPTable(r, tags, *s.VapTable) -} diff --git a/usg.go b/usg.go deleted file mode 100644 index 95065e2..0000000 --- a/usg.go +++ /dev/null @@ -1,155 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// 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) batchUSG(r report, s *unifi.USG) { - if !s.Adopted.Val || s.Locating.Val { - return - } - - 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") - reportGaugeForFloat64Map(r, metricName, data, tags) - - u.batchNetTable(r, tags, s.NetworkTable) - u.batchUSGwans(r, tags, s.Wan1, s.Wan2) -} - -func (u *DatadogUnifi) batchUSGstats(ss unifi.SpeedtestStatus, gw *unifi.Gw, ul unifi.Uplink) map[string]float64 { - if gw == nil { - return map[string]float64{} - } - - 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, - } -} - -func (u *DatadogUnifi) batchUSGwans(r report, tags map[string]string, wans ...unifi.Wan) { - for _, wan := range wans { - if !wan.Up.Val { - continue - } - - 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, - "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") - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} - -func (u *DatadogUnifi) batchNetTable(r report, tags map[string]string, nt unifi.NetworkTable) { - for _, p := range nt { - 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, - "rx_packets": p.RxPackets.Val, - "tx_bytes": p.TxBytes.Val, - "tx_packets": p.TxPackets.Val, - } - - metricName := metricNamespace("usg.networks") - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} diff --git a/usw.go b/usw.go deleted file mode 100644 index aac3ae0..0000000 --- a/usw.go +++ /dev/null @@ -1,136 +0,0 @@ -package datadogunifi - -import ( - "github.com/unpoller/unifi" -) - -// 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) batchUSW(r report, s *unifi.USW) { - if !s.Adopted.Val || s.Locating.Val { - return - } - - 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, - "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) batchUSWstat(sw *unifi.Sw) map[string]float64 { - if sw == nil { - return map[string]float64{} - } - - return 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, - } -} - -//nolint:funlen -func (u *DatadogUnifi) batchPortTable(r report, t map[string]string, pt []unifi.Port) { - for _, p := range pt { - if !u.DeadPorts && (!p.Up.Val || !p.Enable.Val) { - continue // only record UP ports. - } - - 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, - "flow_ctrl_rx": p.FlowctrlRx.Txt, - "flow_ctrl_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{ - "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 { - data["poe_current"] = p.PoeCurrent.Val - data["poe_power"] = p.PoePower.Val - data["poe_voltage"] = p.PoeVoltage.Val - } - - if p.SFPFound.Val { - data["sfp_current"] = p.SFPCurrent.Val - data["sfp_voltage"] = p.SFPVoltage.Val - data["sfp_temperature"] = p.SFPTemperature.Val - data["sfp_tx_power"] = p.SFPTxpower.Val - data["sfp_rx_power"] = p.SFPRxpower.Val - } - - metricName := metricNamespace("usw.ports") - reportGaugeForFloat64Map(r, metricName, data, tags) - } -} diff --git a/uxg.go b/uxg.go deleted file mode 100644 index c79f5e0..0000000 --- a/uxg.go +++ /dev/null @@ -1,83 +0,0 @@ -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. -}