├── README.md ├── dist.ini └── lib └── resty └── info.lua /README.md: -------------------------------------------------------------------------------- 1 | lua-resty-info 2 | ============== 3 | 4 | This module for OpenResty displays all sorts of information about currently running installation of Nginx and Lua. 5 | It is not unlike the phpinfo() function found in PHP. 6 | 7 | Here is a [sample output](http://www.kembox.com/lua-resty-info.html). 8 | 9 | How to use 10 | ---------- 11 | 12 | This module must be installed in your lua package.path, possibly under the resty/ directory, for example in /usr/local/openresty/lualib/resty/info.lua, but that depends on your installation. 13 | 14 | Then, just add this to your nginx configuration : 15 | 16 | ``` 17 | location /info { 18 | content_by_lua ' 19 | local info = require "resty.info" 20 | info()'; 21 | } 22 | ``` 23 | 24 | Then, just call url **/info** on your server and see useful information. 25 | 26 | It is probably not complete, so please fork and send me pull requests. 27 | 28 | Copyright and license 29 | ===================== 30 | 31 | Copyright (c) 2013 Bertrand Mansion, Mamasam 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in 41 | all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 49 | THE SOFTWARE. 50 | -------------------------------------------------------------------------------- /dist.ini: -------------------------------------------------------------------------------- 1 | name = lua-resty-info 2 | abstract = HTML-rendered information about installation of Nginx with ngx_lua module and OpenResty 3 | author = Bertrand Mansion (golgote) 4 | license = mit 5 | repo_link = https://github.com/golgote/lua-resty-info 6 | is_original = yes 7 | main_module=lib/resty/info.lua 8 | -------------------------------------------------------------------------------- /lib/resty/info.lua: -------------------------------------------------------------------------------- 1 | -- General information about OpenResty installation 2 | -- Copyright (C) 2013 Bertrand Mansion (golgote), Mamasam 3 | -- License MIT 4 | 5 | local M = { 6 | _VERSION = '0.1' 7 | } 8 | 9 | local function htmlspecialchars(str) 10 | local html = { 11 | ["<"] = "<", 12 | [">"] = ">", 13 | ["&"] = "&", 14 | } 15 | return string.gsub(tostring(str), "[<>&]", function(char) 16 | return html[char] or char 17 | end) 18 | end 19 | 20 | local function dump2html(value, field) 21 | local html 22 | 23 | local function isemptytable(t) 24 | return next(t) == nil 25 | end 26 | 27 | local function basicSerialize(o) 28 | local so = tostring(o) 29 | if not o then 30 | return "nil" 31 | elseif type(o) == "function" then 32 | local info = debug.getinfo(o, "S") 33 | -- info.name is nil because o is not a calling level 34 | if info.what == "C" then 35 | return "C function" 36 | else 37 | -- the information is defined through lines 38 | return string.format("%s", so .. ", defined in (" .. 39 | info.linedefined .. "-" .. info.lastlinedefined .. 40 | ")" .. info.source) 41 | end 42 | elseif type(o) == "number" then 43 | return so 44 | elseif type(o) == "boolean" then 45 | return so 46 | else 47 | return htmlspecialchars(so) 48 | end 49 | end 50 | 51 | local function addtohtml(value, field, saved) 52 | local value = value 53 | saved = saved or {} 54 | html[#html+1] = '' .. field .. '' 55 | if type(value) ~= "table" then 56 | html[#html+1] = '' .. basicSerialize(value) .. '' 57 | else 58 | if saved[value] then 59 | html[#html+1] = '' .. saved[value] .. ' (self reference)' .. '' 60 | 61 | else 62 | saved[value] = field 63 | if isemptytable(value) then 64 | html[#html+1] = '{ }' 65 | else 66 | html[#html+1] = '' 67 | html[#html+1] = '' 68 | for k, v in pairs(value) do 69 | k = basicSerialize(k) 70 | addtohtml(v, k, saved) 71 | end 72 | html[#html+1] = '
' 73 | html[#html+1] = '' 74 | end 75 | html[#html+1] = '' 76 | end 77 | end 78 | end 79 | 80 | if type(value) ~= "table" then 81 | return '' .. field .. '' .. basicSerialize(value) .. '' 82 | end 83 | 84 | html = {} 85 | addtohtml(value, field) 86 | return table.concat(html, "\n") 87 | end 88 | 89 | local function package_info() 90 | local ngx = ngx 91 | local modules = {} 92 | local packages = {} 93 | for id, content in pairs(package.loaded) do 94 | packages[id] = content 95 | end 96 | packages["ngx"] = ngx 97 | 98 | for id, content in pairs(packages) do 99 | if id ~= 'package' and id ~= 'preload' and id ~= '_G' and type(content) == 'table' then 100 | modules[id] = {} 101 | local functions = {} 102 | local meta = {} 103 | for its_id, its_c in pairs(content) do 104 | if type(its_c) == 'string' or type(its_c) == 'number' then 105 | meta[its_id] = tostring(its_c) 106 | elseif type(its_c) == 'function' then 107 | functions[#functions+1] = its_id 108 | end 109 | end 110 | modules[id]["meta"] = meta 111 | table.sort(functions) 112 | modules[id]["functions"] = functions 113 | end 114 | end 115 | 116 | local html = {} 117 | -- sorted list of modules 118 | local sorted = {} 119 | for n in pairs(modules) do table.insert(sorted, n) end 120 | table.sort(sorted) 121 | for _,id in ipairs(sorted) do 122 | local values = modules[id] 123 | html[#html+1] = '' 124 | if values["meta"] then 125 | -- sort properties 126 | local meta = values['meta'] 127 | sorted = {} 128 | for n in pairs(meta) do table.insert(sorted, n) end 129 | table.sort(sorted) 130 | for i,n in ipairs(sorted) do 131 | html[#html+1] = '' 132 | end 133 | end 134 | -- functions 135 | if values["functions"] and #values["functions"] > 0 then 136 | html[#html+1] = '' 137 | end 138 | html[#html+1] = '
'.. id ..'
' .. n .. '' .. meta[n] .. '
' .. table.concat(values["functions"], ' ') .. '
' 139 | end 140 | return table.concat(html, "\n") 141 | end 142 | 143 | local function server_configuration() 144 | local ngx = ngx 145 | local html = {''} 146 | html[#html+1] = '' 147 | html[#html+1] = '' 148 | html[#html+1] = '' 149 | 150 | local paths 151 | 152 | -- package.path 153 | paths = {} 154 | for token in string.gmatch(package.path, "[^;]+") do 155 | paths[#paths+1] = htmlspecialchars(token) 156 | end 157 | html[#html+1] = '' 158 | 159 | -- package.cpath 160 | paths = {} 161 | for token in string.gmatch(package.cpath, "[^;]+") do 162 | paths[#paths+1] = htmlspecialchars(token) 163 | end 164 | html[#html+1] = '' 165 | 166 | html[#html+1] = '
DirectiveValue
Nginx version' .. htmlspecialchars(tostring(ngx.config.nginx_version)) .. '
Nginx Lua version' .. htmlspecialchars(tostring(ngx.config.ngx_lua_version)) .. '
Lua version' .. htmlspecialchars(tostring(_VERSION)) .. '
package.path' .. table.concat(paths, "
") .. '
package.cpath' .. table.concat(paths, "
") .. '
' 167 | return table.concat(html, "\n") 168 | end 169 | 170 | local function server_info() 171 | local ngx = ngx 172 | -- from http://wiki.nginx.org/NginxHttpCoreModule#.24arg_PARAMETER 173 | local vars = { 174 | "args", 175 | "body_bytes_sent", 176 | "content_length", 177 | "content_type", 178 | "cookie_test", -- cookie_COOKIE 179 | "document_root", 180 | "document_uri", 181 | "headers_in", 182 | "headers_out", 183 | "host", 184 | "hostname", 185 | "http_user_agent", -- http_HEADER 186 | "http_referer", -- http_HEADER 187 | "is_args", 188 | "limit_rate", 189 | "nginx_version", 190 | "query_string", 191 | "remote_addr", 192 | "remote_port", 193 | "remote_user", 194 | "request_filename", 195 | "request_body", 196 | "request_body_file", 197 | "request_completion", 198 | "request_method", 199 | "request_uri", 200 | "scheme", 201 | "server_addr", 202 | "server_name", 203 | "server_port", 204 | "server_protocol", 205 | "uri", 206 | } 207 | local html = {''} 208 | for i,v in ipairs(vars) do 209 | if ngx.var[v] then 210 | html[#html+1] = '' 211 | end 212 | end 213 | html[#html+1] = '' 214 | html[#html+1] = '' 215 | html[#html+1] = '' 216 | html[#html+1] = dump2html(ngx.ctx, 'ngx.ctx') 217 | 218 | html[#html+1] = '
VariableValue
ngx.var.' .. v .. '' .. htmlspecialchars(tostring(ngx.var[v])) .. '
ngx.header_sent' .. htmlspecialchars(tostring(ngx.header_sent)) .. '
ngx.status' .. htmlspecialchars(tostring(ngx.status)) .. '
ngx.is_subrequest' .. htmlspecialchars(tostring(ngx.is_subrequest)) .. '
' 219 | return table.concat(html, "\n") 220 | end 221 | 222 | local function server_functions() 223 | local html = {} 224 | local result = {} 225 | local ngx = ngx 226 | 227 | result['ngx.req.get_headers()'] = ngx.req.get_headers() 228 | result['ngx.req.get_uri_args()'] = ngx.req.get_uri_args() 229 | result['ngx.today()'] = ngx.today() 230 | result['ngx.time()'] = ngx.time() 231 | result['ngx.now()'] = ngx.now() 232 | result['ngx.localtime()'] = ngx.localtime() 233 | result['ngx.utctime()'] = ngx.utctime() 234 | result['ngx.get_phase()'] = ngx.get_phase() 235 | 236 | local html = {''} 237 | for id, content in pairs(result) do 238 | html[#html+1] = dump2html(content, id) 239 | end 240 | html[#html+1] = '
FunctionResult
' 241 | return table.concat(html, "\n") 242 | end 243 | 244 | M.info = function() 245 | local template = [[Lua resty info 246 | 262 | 263 |

Nginx OpenResty version %s

264 |

Server configuration

265 | %s 266 |

Modules

267 | %s 268 |

Server variables

269 | %s 270 |

Resty functions

271 | %s 272 | ]] 273 | 274 | local html = string.format(template, ngx.var.nginx_version, server_configuration(), package_info(), server_info(), server_functions()) 275 | ngx.header.content_type = 'text/html' 276 | ngx.print(html) 277 | end 278 | 279 | local mt = {} 280 | mt.__call = function(...) 281 | return M.info(...) 282 | end 283 | setmetatable(M, mt) 284 | 285 | return M 286 | --------------------------------------------------------------------------------