Skip to content

Commit

Permalink
Merge pull request #297 from riemann/hwmon
Browse files Browse the repository at this point in the history
Add a new `riemann-hwmon` tool for harware monitors
  • Loading branch information
jamtur01 committed Jun 29, 2024
2 parents d2b38d7 + 7a653ba commit 100b59c
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 2 deletions.
8 changes: 8 additions & 0 deletions bin/riemann-hwmon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

Process.setproctitle($PROGRAM_NAME)

require 'riemann/tools/hwmon'

Riemann::Tools::Hwmon.run
131 changes: 131 additions & 0 deletions lib/riemann/tools/hwmon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# frozen_string_literal: true

require 'riemann/tools'

# See https://www.kernel.org/doc/html/latest/hwmon/index.html
module Riemann
module Tools
class Hwmon
include Riemann::Tools

class Device
attr_reader :hwmon, :type, :number, :crit, :lcrit, :label, :name

def initialize(hwmon, type, number)
@hwmon = hwmon
@type = type
@number = number

@crit = scale(read_hwmon_i('crit'))
@lcrit = scale(read_hwmon_i('lcrit'))
@label = read_hwmon_s('label')
@name = read_hwmon_file('name')
end

def input
read_hwmon_i('input')
end

def report
value = scale(input)

state = :ok
state = :critical if crit && value >= crit
state = :critical if lcrit && value <= lcrit
{
service: "hwmon #{name} #{label}",
state: state,
metric: value,
description: fromat_input(value),
}
end

private

def scale(value)
return nil if value.nil?

case type
when :fan then value.to_i # rpm
when :in, :temp, :curr then value.to_f / 1000 # mV, m°C, mA
when :humidity then value.to_f / 100 # %H
when :power, :energy then value.to_f / 1_000_000 # uW, uJ
end
end

def fromat_input(value)
case type
when :in then format('%<value>.3f V', { value: value })
when :fan then "#{value} RPM"
when :temp then format('%<value>.3f °C', { value: value })
when :curr then format('%<value>.3f A', { value: value })
when :power then format('%<value>.3f W', { value: value })
when :energy then format('%<value>.3f J', { value: value })
when :humidity then format('%<value>d %H', { value: (value * 100).to_i })
end
end

def read_hwmon_i(file)
s = read_hwmon_s(file)
return nil if s.nil?

s.to_i
end

def read_hwmon_s(file)
read_hwmon_file("#{type}#{number}_#{file}")
end

def read_hwmon_file(file)
File.read("/sys/class/hwmon/hwmon#{hwmon}/#{file}").chomp
rescue Errno::ENOENT
nil
end
end

FIRST_NUMBER = {
in: 0,
fan: 1,
temp: 1,
curr: 1,
power: 1,
energy: 1,
humidity: 1,
}.freeze

attr_reader :devices

def initialize
super

@devices = poll_devices
end

def poll_devices
res = []

hwmon = 0
while File.exist?("/sys/class/hwmon/hwmon#{hwmon}")
%i[in fan temp curr power energy humidity].each do |type|
number = FIRST_NUMBER[type]
while File.exist?("/sys/class/hwmon/hwmon#{hwmon}/#{type}#{number}_input")
res << Device.new(hwmon, type, number)

number += 1
end
end

hwmon += 1
end

res
end

def tick
devices.each do |device|
report(device.report)
end
end
end
end
end
6 changes: 4 additions & 2 deletions spec/riemann/tools/http_check_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
require 'openssl'
begin
require 'rackup/handler/webrick'
RACK_HANDLER = Rackup::Handler::WEBrick
rescue LoadError
# XXX: Needed for Ruby 2.6 compatibility
# Moved to the rackup gem in recent versions
require 'rack/handler/webrick'
RACK_HANDLER = Rack::Handler::WEBrick
end
require 'sinatra/base'
require 'webrick'
Expand Down Expand Up @@ -108,7 +110,7 @@ def protected!
Logger: WEBrick::Log.new(File.open(File::NULL, 'w')),
}
@server = WEBrick::HTTPServer.new(server_options)
@server.mount('/', Rack::Handler::WEBrick, TestWebserver)
@server.mount('/', RACK_HANDLER, TestWebserver)
@started = false
Thread.new { @server.start }
Timeout.timeout(1) { sleep(0.1) until @started }
Expand Down Expand Up @@ -260,7 +262,7 @@ def protected!
SSLCertName: '/CN=example.com',
}
@server = WEBrick::HTTPServer.new(server_options)
@server.mount('/', Rack::Handler::WEBrick, TestWebserver)
@server.mount('/', RACK_HANDLER, TestWebserver)
@started = false
Thread.new { @server.start }
Timeout.timeout(1) { sleep(0.1) until @started }
Expand Down
29 changes: 29 additions & 0 deletions spec/riemann/tools/hwmon/device_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

require 'riemann/tools/hwmon'

RSpec.describe Riemann::Tools::Hwmon::Device do
subject { described_class.new(1, :temp, 2) }

before do
allow(File).to receive(:read).with('/sys/class/hwmon/hwmon1/name').and_return("i350bb\n")
allow(File).to receive(:read).with('/sys/class/hwmon/hwmon1/temp2_input').and_return("#{input}\n")
allow(File).to receive(:read).with('/sys/class/hwmon/hwmon1/temp2_crit').and_return("96000\n")
allow(File).to receive(:read).with('/sys/class/hwmon/hwmon1/temp2_lcrit').and_raise(Errno::ENOENT)
allow(File).to receive(:read).with('/sys/class/hwmon/hwmon1/temp2_label').and_return("loc1\n")
end

describe '#report' do
context 'when temperature is ok' do
let(:input) { 31_000 }

it { expect(subject.report).to eq({ service: 'hwmon i350bb loc1', state: :ok, metric: 31.0, description: '31.000 °C' }) }
end

context 'when temperature is critical' do
let(:input) { 96_000 }

it { expect(subject.report).to eq({ service: 'hwmon i350bb loc1', state: :critical, metric: 96.0, description: '96.000 °C' }) }
end
end
end

0 comments on commit 100b59c

Please sign in to comment.