summaryrefslogtreecommitdiff
path: root/files/common/openwrt/gpsd_prometheus-node-exporter.lua
blob: b7ed92f114cdc86b321843f4848dbc0d42dee225 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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 }