Add support for node_exporter_build_info, node_os_info, and node_os_version to node-exporter-prometheus-lua

So I had some existing dashboards and they depended on some metrics that the lua implementation doesn't support. I suspect there is very little interest in actually contributing this, so I didn't want to make an MR. I was able to just install these in the lua directory, but if someone would like these, I can make an MR to the main repo.

os_info.lua

-- os_info.lua - Exposes OS information as Prometheus metrics
-- Implements similar functionality to the Go os-release collector

local function parse_os_release()
    local os_info = {
        NAME = "",
        ID = "",
        ID_LIKE = "",
        PRETTY_NAME = "",
        VERSION = "",
        VERSION_ID = "",
        VERSION_CODENAME = "",
        BUILD_ID = "",
        IMAGE_ID = "",
        IMAGE_VERSION = "",
        VARIANT = "",
        VARIANT_ID = "",
        SUPPORT_END = ""
    }

    local files = {"/etc/os-release", "/usr/lib/os-release"}
node
    for _, file in ipairs(files) do
        local f = io.open(file, "r")
        if f then
            for line in f:lines() do
                -- Match key=value or key="value" or key='value'
                local key, value = line:match('^([A-Z_]+)=["\']?([^"\']*)["\']?$')
                if key and os_info[key] ~= nil then
                    os_info[key] = value
                end
            end
            f:close()
            break -- Stop after first successful read
        end
    end

    return os_info
end

local function scrape()
    local os_info = parse_os_release()

    -- node_os_info metric with all available labels
    metric(
            "node_os_info",
            "gauge",
            {
                build_id = os_info.BUILD_ID,
                id = os_info.ID,
                id_like = os_info.ID_LIKE,
                image_id = os_info.IMAGE_ID,
                image_version = os_info.IMAGE_VERSION,
                name = os_info.NAME,
                pretty_name = os_info.PRETTY_NAME,
                variant = os_info.VARIANT,
                variant_id = os_info.VARIANT_ID,
                version = os_info.VERSION,
                version_codename = os_info.VERSION_CODENAME,
                version_id = os_info.VERSION_ID
            },
            1
    )

    -- node_os_version metric with simplified labels
    if os_info.VERSION_ID ~= "" then
        local major_minor = string.match(os_info.VERSION_ID, "^%d+%.?%d*")
        if major_minor then
            local version_num = tonumber(major_minor)
            if version_num then
                metric(
                        "node_os_version",
                        "gauge",
                        {
                            id = os_info.ID,
                            id_like = os_info.ID_LIKE,
                            name = os_info.NAME
                        },
                        version_num
                )
            end
        end
    end

end

return { scrape = scrape }

build_info.lua

-- build_info.lua - Exposes build information as Prometheus metrics

local function get_package_version()
    -- Get version using opkg info
    local handle = io.popen("opkg info prometheus-node-exporter-lua 2>/dev/null")
    if handle then
        local output = handle:read("*a")
        handle:close()
        -- Extract version from the "Version: " line
        local version = output:match("Version:%s+([^\n]+)")
        if version then
            return version
        end
    end
    return "unknown"
end

local function get_git_revision()
    -- This would typically be set at build time
    -- For now, we'll return a placeholder
    return "unknown"
end

local function scrape()
    local version = get_package_version()

    -- node_exporter_build_info metric
    metric(
            "node_exporter_build_info",
            "gauge",
            {
                version = version,
                revision = get_git_revision(),
                branch = "HEAD",
                goos = "n/a",
                goarch = "n/a",
                goversion = "n/a",
                tags = ""
            },
            1
    )
end

return { scrape = scrape }

They might need some work, Claude made them kind of adapting the Go source code.