local socket = require "socket" local cjson = require "cjson.safe" local last_error_msg = {} local last_watch_msg = {} local last_devices_msg = {} function gpsd_setup() local s, err = socket.tcp4() if err ~= nil then return nil, err end s:settimeout(1) _, err = s:connect('127.0.0.1', 2947) if err ~= nil then return nil, err end local msg_json, err = s:receive('*l') if err ~= nil then s:close() return nil, err end local msg, err = cjson.decode(msg_json) if err ~= nil then s:close() return nil, err end if msg['class'] ~= 'VERSION' then s:close() return nil, "got unexpected message class from GPSD: " .. tostring(msg['class']) end _, err = s:send('?WATCH={"enable":"true"}') if err ~= nil then s:close() return nil, err end return s, msg end function gpsd_poll(s) _, err = s:send('?DEVICES;') if err ~= nil then s:close() return nil, err end _, err = s:send('?POLL;') if err ~= nil then s:close() return nil, err end while true do local msg_json, err = s:receive('*l') if err ~= nil then s:close() return nil, err end local msg, err = cjson.decode(msg_json) if err ~= nil then s:close() return nil, err end if msg['class'] == 'ERROR' then last_error_msg = msg elseif msg['class'] == 'WATCH' then last_watch_msg = msg elseif msg['class'] == 'DEVICES' then last_devices_msg = msg elseif msg['class'] == 'POLL' then return s, msg else print("ignoring unknown message class from GPSD: " .. tostring(msg['class'])) end end end function metric_version_info(version_info) local labels = {} labels['rev'] = version_info['rev'] labels['release'] = version_info['release'] labels['proto_major'] = version_info['proto_major'] labels['proto_minor'] = version_info['proto_minor'] metric("gpsd_version_info", "gauge", labels, 1) end function metric_devices(devices_msg) if devices_msg['devices'] == nil then return end for _, dev in ipairs(devices_msg['devices']) do local labels = {} labels['device'] = dev['path'] labels['driver'] = dev['driver'] labels['subtype'] = dev['subtype'] labels['subtype1'] = dev['subtype1'] metric("gpsd_device_info", "gauge", labels, 1) end end function metric_poll(poll_msg) for _, tpv in ipairs(poll_msg['tpv']) do local labels = {} labels['device'] = tpv['device'] metric("gpsd_tpv_mode", "gauge", labels, tpv['mode']) if tpv['alt'] ~= nil then metric("gpsd_tpv_altitude_meters", "gauge", labels, tpv['alt']) end if tpv['lat'] ~= nil then metric("gpsd_tpv_latitude_degrees", "gauge", labels, tpv['lat']) end if tpv['lon'] ~= nil then metric("gpsd_tpv_longitude_degrees", "gauge", labels, tpv['lon']) end end end local s, version_info = gpsd_setup() local function scrape() if s == nil then print("lost connection to gpsd, reconncting...") s, version_info = gpsd_setup() if s == nil then return s, version_info end end metric_version_info(version_info) s, poll_msg = gpsd_poll(s) if s == nil then return s, poll end metric_devices(last_devices_msg) metric_poll(poll_msg) end return { scrape = scrape }