├── 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] = ''.. id ..' |
'
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] = '' .. n .. ' | ' .. meta[n] .. ' |
'
132 | end
133 | end
134 | -- functions
135 | if values["functions"] and #values["functions"] > 0 then
136 | html[#html+1] = '' .. table.concat(values["functions"], ' ') .. ' |
'
137 | end
138 | html[#html+1] = '
'
139 | end
140 | return table.concat(html, "\n")
141 | end
142 |
143 | local function server_configuration()
144 | local ngx = ngx
145 | local html = {'Directive | Value |
'}
146 | html[#html+1] = 'Nginx version | ' .. htmlspecialchars(tostring(ngx.config.nginx_version)) .. ' |
'
147 | html[#html+1] = 'Nginx Lua version | ' .. htmlspecialchars(tostring(ngx.config.ngx_lua_version)) .. ' |
'
148 | html[#html+1] = 'Lua version | ' .. htmlspecialchars(tostring(_VERSION)) .. ' |
'
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] = 'package.path | ' .. table.concat(paths, " ") .. ' |
'
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] = 'package.cpath | ' .. table.concat(paths, " ") .. ' |
'
165 |
166 | html[#html+1] = '
'
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 = {'Variable | Value |
'}
208 | for i,v in ipairs(vars) do
209 | if ngx.var[v] then
210 | html[#html+1] = 'ngx.var.' .. v .. ' | ' .. htmlspecialchars(tostring(ngx.var[v])) .. ' |
'
211 | end
212 | end
213 | html[#html+1] = 'ngx.header_sent | ' .. htmlspecialchars(tostring(ngx.header_sent)) .. ' |
'
214 | html[#html+1] = 'ngx.status | ' .. htmlspecialchars(tostring(ngx.status)) .. ' |
'
215 | html[#html+1] = 'ngx.is_subrequest | ' .. htmlspecialchars(tostring(ngx.is_subrequest)) .. ' |
'
216 | html[#html+1] = dump2html(ngx.ctx, 'ngx.ctx')
217 |
218 | html[#html+1] = '
'
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 = {'Function | Result |
'}
237 | for id, content in pairs(result) do
238 | html[#html+1] = dump2html(content, id)
239 | end
240 | html[#html+1] = '
'
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 |
--------------------------------------------------------------------------------