influxdata / telegraf

Agent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.
https://influxdata.com/telegraf
MIT License
14.93k stars 5.6k forks source link

NUT - Network UPS Tools Plug-in #6316

Closed mcindea closed 2 years ago

mcindea commented 5 years ago

Feature Request

Hello guys,

I'm just curious if you have any plans in creating a plugin for NUT ? Similar to what you did for https://github.com/influxdata/telegraf/issues/2877

Proposal:

I volunteer to create it myself, but I'm new to Go, so I would need your support reviewing the code and most possibly also share the procedures you have for this kind of situations? i.e. Best practices or some docs about writing plugins. Thanks!

Current behavior:

Currently only a plugin for APCUPCd exists.

Desired behavior:

Would be nice if a plugin for NUT exists, which offers a broader compatibility with UPS hardware.

Use case:

Currently I use Telegraf for my UnRaid setup, which monitors everything, and built a custom Docker container script which gathers data and sends it to InfluxDB. Another solution is to use an Exec, but that also requires having NUT installed in the Alpine container where Telegraf is. Therefore I would like a plugin, which doesn't have any external dependencies.

danielnelson commented 5 years ago

This would be nice to have. I looked very briefly at the NUT documentation, do you think the plugin would operate similar to the upsc command?

mcindea commented 5 years ago

Yes, as a matter of fact the python script I built uses the same uspc command.

danielnelson commented 5 years ago

Would be nice to get an idea of how some actual data looks, could you show the output of your script?

I believe this is the documentation for connecting to upsd: https://networkupstools.org/docs/developer-guide.chunked/ar01s09.html

mcindea commented 5 years ago

Sure, but it's it's not fully relevant since currently I just adapted a python script that was built for APCUPCd, so currently the fields match what APC would output:

[{'fields': {'STATUS': u'OL', 'WATTS': 90.0, 'TIMELEFT': 3570.0, 'BCHARGE': 100.0, 'LOADPCT': 10.0, 'BATTV': 24.0, 'OUTPUTV': 260.0, 'NOMPOWER': 900.0}, 'tags': {'ups_alias': 'ups', 'host': 'Tower', 'serial': u'CRMJP2000104'}, 'measurement': 'ups_status'}]

Just for reference, BCHARGE is actually battery.charge on UPS Cyberpower and similar BATTV is battery.voltage. Since I can't test other UPS equipments, I would want to make it dynamic, just output the fields it gets. Of course, after proper filtering so we make sure nothing malicious gets stored in the DB.

Thinking about it I think it's better if I just show you the upsc output:

root@Tower:~# upsc ups@localhost
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 20
battery.mfr.date: CPS
battery.runtime: 3720
battery.runtime.low: 300
battery.type: PbAcid
battery.voltage: 24.0
battery.voltage.nominal: 24
device.mfr: CPS
device.model: CP1500EPFCLCD
device.serial: CRMJP2000104
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: no
driver.version: 2.7.4.1
driver.version.data: CyberPower HID 0.5
driver.version.internal: 0.53
driver.version.usb: libusb-1.0.22 (API: 0x1000106)
input.transfer.high: 260
input.transfer.low: 170
input.voltage: 225.0
input.voltage.nominal: 230
output.voltage: 260.0
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.delay.start: 30
ups.load: 10
ups.mfr: CPS
ups.model: CP1500EPFCLCD
ups.productid: 0501
ups.realpower.nominal: 900
ups.serial: CRMJP2000104
ups.status: OL
ups.test.result: No test initiated
ups.timer.shutdown: -60
ups.timer.start: -60
ups.vendorid: 0764
root@Tower:~# 
danielnelson commented 5 years ago

I wonder how standardized these stats are, is there a list of possible stats? Likely we would want a plugin to connect to upsd and list all stats and then for each stat we would check a list of known stats to determine if the stat should be saved as a tag/field.

If a stat is unknown we could either ignore the stat or add it based on the observed type:

If we find the use of a decimal point is not consistent, we may want to always store as float. I would think that the memcached plugin is the closest in style to what we would want here.

mcindea commented 5 years ago

That's a very good idea. I'll have to dig into this a bit more. I found upsrw, which does something like that, but only for config variables that can be changed by the user and not actual log data.

[battery.charge.low]
Remaining battery level when UPS switches to LB (percent)
Type: STRING
Maximum length: 10
Value: 10

[battery.runtime.low]
Remaining battery runtime when UPS switches to LB (seconds)
Type: STRING
Maximum length: 10
Value: 300

[input.transfer.high]
High voltage transfer point (V)
Type: STRING
Maximum length: 10
Value: 260

[input.transfer.low]
Low voltage transfer point (V)
Type: STRING
Maximum length: 10
Value: 170

[ups.delay.shutdown]
Interval to wait after shutdown with delay command (seconds)
Type: STRING
Maximum length: 10
Value: 20

[ups.delay.start]
Interval to wait before (re)starting the load (seconds)
Type: STRING
Maximum length: 10
Value: 30

root@Tower:~#

Also found something we could use to replace upsc which polls every 30 seconds by default, but unfortunately it doesn't say anything about types. The format appears to be universal, so I don't think it's tied to the vendor type. Especially if you look at the last 2 columns, ups.temperature and input.frequency. They're NA because I don't have those sensors.

root@Tower:~# upslog  -s ups@localhost -l - -f "%TIME @Y@m@d @H@M@S% %VAR battery.charge% %VAR battery.runtime% %VAR ups.realpower.nominal% %VAR battery.voltage% %VAR output.voltage% %VAR input.voltage% %VAR ups.load%  [%VAR ups.status%] %VAR ups.temperature% %VAR input.frequency%"
Network UPS Tools upslog 2.7.4.1
logging status of ups@localhost to - (30s intervals)
20190829 073621 100 3480 900 24.0 260.0 225.0 11  [OL] NA NA
20190829 073651 100 3330 900 24.0 260.0 224.0 11  [OL] NA NA

EDIT: I looked into it and they have quite complex documentation about this: https://networkupstools.org/docs/developer-guide.chunked/apas01.html

To be honest there are more than I expected and I'm curious how much of them my UPS actually supports so I can actually test them.

Thanks for the tip about memcached, I''ll look into that.

sjwang90 commented 5 years ago

Hi @kiwimato, just checking if you have any update in looking into referencing thememcached plugin for the NUT plugin you're working on. Just looking into prioritizing plugins for future feature releases. Please respond if you have any questions!

mcindea commented 5 years ago

Hello @sjwang90, unfortunately I didn't enough time to start work on it and my server where I had this setup crashed in the meantime, so I won't be able to work on it until I will fix it. I did however write a python script which I planned to use as PoC before I planned to work on this. If you guys have more time than me or might find it useful you can find it here - it's fully tested and it works. Please keep me updated. I find it really awesome that you are guys are interested in it!

Styx13 commented 4 years ago

Hello @kiwimato , do you still plan to create this nut plugin for telegraf ?

I too am using nut for my UPS management and monitoring, and I would love to be able to send the metrics to influxdb/grafana using telegraf.

mcindea commented 4 years ago

Hey @Styx13, to be honest I didn't have time to yet and for my use case i created a workaround: https://github.com/kiwimato/nut-influxdb-exporter

I still plan to work on it at some point, but don't have an ETA at this point.

lmondoux commented 4 years ago

Just wanted to say it would be great if there was a NUT telegraf input!

donmueang commented 4 years ago

Is there any known update on this? Would like to have Telegram scraping data from the NUT instance running on another server. Not planning to switch over to apcupcd.

cvandesande commented 4 years ago

Is there any known update on this? Would like to have Telegram scraping data from the NUT instance running on another server. Not planning to switch over to apcupcd.

Yeah, you can always use "inputs_exec" and run upsc. It's what I'm currently doing and it works fine.

[[inputs.exec]]
  commands = ["sh -c 'upsc cyberpower@localhost ups.realpower.nominal'"]
  name_override = "ups_power"
  timeout = "5s"
  data_format = "value"
  data_type = "integer"
  [inputs.exec.tags]
    ups = "ups0"

[[inputs.exec]]
  commands = ["sh -c 'upsc cyberpower@localhost ups.load'"]
  name_override = "ups_load"
  timeout = "5s"
  data_format = "value"
  data_type = "integer"
  [inputs.exec.tags]
    ups = "ups0"
samuelkadolph commented 4 years ago

I came across the issue and whipped up a script. Figured I'd share it for others.

#!/bin/sh

if [ $# -lt 1 ]; then
  echo "usage: $0 field [...field]" >&2
  exit 1
fi

fields="$1"
shift

while [ $# -ne 0 ]; do
  fields="$fields|$1"
  shift
done

list=$(upsc -l 2>/dev/null)
safe_fields="$(echo "${fields}" | sed 's/\./\\\./g')"

for name in $list; do
  props=$(upsc "$name" 2>/dev/null | sed -nE "/^($safe_fields):/p" | sed -nE 's/([^0-9])\.([^0-9])/\1_\2/g;s/^(.*): ([0-9.]+)$/\1=\2/p' | tr '\n' ',')
  echo "ups,name=${name} ${props%,}"
done

In my case I have that script at /etc/telegraf/ups and added the following to my config:

[[inputs.exec]]
  commands = ["/etc/telegraf/ups battery.charge battery.runtime battery.voltage battery.voltage.nominal input.voltage output.voltage ups.load ups.realpower.nominal"]
  data_format = "influx"
sjwang90 commented 4 years ago

@kiwimato @samuelkadolph Would either of your scripts be able list as an external plugin. If you would you be willing to submit this plugin as an external plugin that can be used with execd to run seamlessly with Telegraf?

fabriziorizzo commented 3 years ago

collecting the non-numeric ups.status value would also useful. Not entirely sure how to adapt the regexp so it becomes an accepted property for the script above. perhaps even transforming the abbreviated code for full-text status descriptions?

e.g. 'OL': 'Online', 'OB': 'On Battery', 'LB': 'Low Battery', 'HB': 'High Battery', 'RB': 'Battery Needs Replaced', 'CHRG': 'Battery Charging', 'DISCHRG': 'Battery Discharging', 'BYPASS': 'Bypass Active', 'CAL': 'Runtime Calibration', 'OFF': 'Offline', 'OVER': 'Overloaded', 'TRIM': 'Trimming Voltage', 'BOOST': 'Boosting Voltage', 'FSD': 'Forced Shutdown', 'ALARM': 'Alarm'

arrmo commented 3 years ago

Hi,

Sorry if this is a dumb question, but ... as there is an official plugin for apcupsd, why not align with that => meaning, save the same parameter set with NUT?

Thanks!

midzelis commented 3 years ago

I wrote this for myself, but then i found this comment, so I put it up on github/dockerhub -- maybe others will find it useful?

https://github.com/midzelis/nut-ups-logger

This will connect to NUT remotely, list all the UPS, and then send ALL the variables over a remote server. This can be telegraf running with the HTTP Listener plugin.

By default, I send all the variables I find. If there is something you don't want, looks like telegraf can filter things out: https://docs.influxdata.com/telegraf/v1.19/administration/configuration/#measurement-filtering

docker-compose.yml

version: "3"
services:
  nut-ups-logger:
    image: midzelis/nut-ups-logger
    environment:
      - NUT_HOST=${NUT_HOST}
      - NUT_PORT=${NUT_PORT}
      - LOGGING_URL=${LOGGING_URL}
    container_name: nut-ups-logger
    depends_on:
      - telegraf
    restart: always

telegraf.conf snippet

[[inputs.http_listener_v2]]
#   ## Address and port to host HTTP listener on
  service_address = ":10800"
#
#   ## Path to listen to.
    path = "/telegraf"

    data_format = "json"
    json_name_key = "UPS_NAME"
Malinskiy commented 3 years ago

A very quick implementation of NUT client using github.com/robbiet480/go.nut can be found here - https://github.com/Malinskiy/telegraf/tree/feature/upsd/plugins/inputs/upsd

It produces an almost identical set of metrics as apcupsd input with a couple of exceptions. Dashboards that work for apcupsd work almost out of the box: image

grasshide commented 3 years ago

A very quick implementation of NUT client using github.com/robbiet480/go.nut can be found here - https://github.com/Malinskiy/telegraf/tree/feature/upsd/plugins/inputs/upsd

This looks perfect. But how do I use this? I run telegraf as docker container. Will this be adopted as a standard plugin? Right now it is not included.

Malinskiy commented 3 years ago

A very quick implementation of NUT client using github.com/robbiet480/go.nut can be found here - https://github.com/Malinskiy/telegraf/tree/feature/upsd/plugins/inputs/upsd

This looks perfect. But how do I use this? I run telegraf as docker container. Will this be adopted as a standard plugin? Right now it is not included.

I may work on submitting this as a PR to the main repo next month depending on my availability

ostueker commented 2 years ago

Looking forward to the upsd support in the next release.

Thank you @Malinskiy, @AdamLeyshon and @srebhan !