-- General information about OpenResty installation
-- Copyright (C) 2013 Bertrand Mansion (golgote), Mamasam
-- License MIT
local M = {
_VERSION = '0.1'
}
local function htmlspecialchars(str)
local html = {
["<"] = "<",
[">"] = ">",
["&"] = "&",
}
return string.gsub(tostring(str), "[<>&]", function(char)
return html[char] or char
end)
end
local function dump2html(value, field)
local html
local function isemptytable(t)
return next(t) == nil
end
local function basicSerialize(o)
local so = tostring(o)
if not o then
return "nil"
elseif type(o) == "function" then
local info = debug.getinfo(o, "S")
-- info.name is nil because o is not a calling level
if info.what == "C" then
return "C function"
else
-- the information is defined through lines
return string.format("%s", so .. ", defined in (" ..
info.linedefined .. "-" .. info.lastlinedefined ..
")" .. info.source)
end
elseif type(o) == "number" then
return so
elseif type(o) == "boolean" then
return so
else
return htmlspecialchars(so)
end
end
local function addtohtml(value, field, saved)
local value = value
saved = saved or {}
html[#html+1] = '
| ' .. field .. ' | '
if type(value) ~= "table" then
html[#html+1] = '' .. basicSerialize(value) .. ' |
'
else
if saved[value] then
html[#html+1] = '' .. saved[value] .. ' (self reference)' .. ' | '
else
saved[value] = field
if isemptytable(value) then
html[#html+1] = '{ } | '
else
html[#html+1] = ''
html[#html+1] = ''
for k, v in pairs(value) do
k = basicSerialize(k)
addtohtml(v, k, saved)
end
html[#html+1] = ' '
html[#html+1] = ' | '
end
html[#html+1] = ''
end
end
end
if type(value) ~= "table" then
return '| ' .. field .. ' | ' .. basicSerialize(value) .. ' |
'
end
html = {}
addtohtml(value, field)
return table.concat(html, "\n")
end
local function package_info()
local ngx = ngx
local modules = {}
local packages = {}
for id, content in pairs(package.loaded) do
packages[id] = content
end
packages["ngx"] = ngx
for id, content in pairs(packages) do
if id ~= 'package' and id ~= 'preload' and id ~= '_G' and type(content) == 'table' then
modules[id] = {}
local functions = {}
local meta = {}
for its_id, its_c in pairs(content) do
if type(its_c) == 'string' or type(its_c) == 'number' then
meta[its_id] = tostring(its_c)
elseif type(its_c) == 'function' then
functions[#functions+1] = its_id
end
end
modules[id]["meta"] = meta
table.sort(functions)
modules[id]["functions"] = functions
end
end
local html = {}
-- sorted list of modules
local sorted = {}
for n in pairs(modules) do table.insert(sorted, n) end
table.sort(sorted)
for _,id in ipairs(sorted) do
local values = modules[id]
html[#html+1] = '| '.. id ..' |
'
if values["meta"] then
-- sort properties
local meta = values['meta']
sorted = {}
for n in pairs(meta) do table.insert(sorted, n) end
table.sort(sorted)
for i,n in ipairs(sorted) do
html[#html+1] = '| ' .. n .. ' | ' .. meta[n] .. ' |
'
end
end
-- functions
if values["functions"] and #values["functions"] > 0 then
html[#html+1] = '| ' .. table.concat(values["functions"], ' ') .. ' |
'
end
html[#html+1] = '
'
end
return table.concat(html, "\n")
end
local function server_configuration()
local ngx = ngx
local html = {'| Directive | Value |
'}
html[#html+1] = '| Nginx version | ' .. htmlspecialchars(tostring(ngx.config.nginx_version)) .. ' |
'
html[#html+1] = '| Nginx Lua version | ' .. htmlspecialchars(tostring(ngx.config.ngx_lua_version)) .. ' |
'
html[#html+1] = '| Lua version | ' .. htmlspecialchars(tostring(_VERSION)) .. ' |
'
local paths
-- package.path
paths = {}
for token in string.gmatch(package.path, "[^;]+") do
paths[#paths+1] = htmlspecialchars(token)
end
html[#html+1] = '| package.path | ' .. table.concat(paths, " ") .. ' |
'
-- package.cpath
paths = {}
for token in string.gmatch(package.cpath, "[^;]+") do
paths[#paths+1] = htmlspecialchars(token)
end
html[#html+1] = '| package.cpath | ' .. table.concat(paths, " ") .. ' |
'
html[#html+1] = '
'
return table.concat(html, "\n")
end
local function server_info()
local ngx = ngx
-- from http://wiki.nginx.org/NginxHttpCoreModule#.24arg_PARAMETER
local vars = {
"args",
"body_bytes_sent",
"content_length",
"content_type",
"cookie_test", -- cookie_COOKIE
"document_root",
"document_uri",
"headers_in",
"headers_out",
"host",
"hostname",
"http_user_agent", -- http_HEADER
"http_referer", -- http_HEADER
"is_args",
"limit_rate",
"nginx_version",
"query_string",
"remote_addr",
"remote_port",
"remote_user",
"request_filename",
"request_body",
"request_body_file",
"request_completion",
"request_method",
"request_uri",
"scheme",
"server_addr",
"server_name",
"server_port",
"server_protocol",
"uri",
}
local html = {'| Variable | Value |
'}
for i,v in ipairs(vars) do
if ngx.var[v] then
html[#html+1] = '| ngx.var.' .. v .. ' | ' .. htmlspecialchars(tostring(ngx.var[v])) .. ' |
'
end
end
html[#html+1] = '| ngx.header_sent | ' .. htmlspecialchars(tostring(ngx.header_sent)) .. ' |
'
html[#html+1] = '| ngx.status | ' .. htmlspecialchars(tostring(ngx.status)) .. ' |
'
html[#html+1] = '| ngx.is_subrequest | ' .. htmlspecialchars(tostring(ngx.is_subrequest)) .. ' |
'
html[#html+1] = dump2html(ngx.ctx, 'ngx.ctx')
html[#html+1] = '
'
return table.concat(html, "\n")
end
local function server_functions()
local html = {}
local result = {}
local ngx = ngx
result['ngx.req.get_headers()'] = ngx.req.get_headers()
result['ngx.req.get_uri_args()'] = ngx.req.get_uri_args()
result['ngx.today()'] = ngx.today()
result['ngx.time()'] = ngx.time()
result['ngx.now()'] = ngx.now()
result['ngx.localtime()'] = ngx.localtime()
result['ngx.utctime()'] = ngx.utctime()
result['ngx.get_phase()'] = ngx.get_phase()
local html = {'| Function | Result |
'}
for id, content in pairs(result) do
html[#html+1] = dump2html(content, id)
end
html[#html+1] = '
'
return table.concat(html, "\n")
end
M.info = function()
local template = [[Lua resty info
Nginx OpenResty version %s
Server configuration
%s
Modules
%s
Server variables
%s
Resty functions
%s
]]
local html = string.format(template, ngx.var.nginx_version, server_configuration(), package_info(), server_info(), server_functions())
ngx.header.content_type = 'text/html'
ngx.print(html)
end
local mt = {}
mt.__call = function(...)
return M.info(...)
end
setmetatable(M, mt)
return M