diff --git a/CHANGELOG.md b/CHANGELOG.md index a17e276..32b085d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added +- `log_requests` option into `roles.httpd`. + ### Changed ### Fixed diff --git a/README.md b/README.md index 95c2ea4..1d90ceb 100644 --- a/README.md +++ b/README.md @@ -536,11 +536,16 @@ roles_cfg: listen: 8081 additional: listen: '127.0.0.1:8082' + log_requests: 'verbose' ``` Server address should be provided either as a URI or as a single port (in this case, `0.0.0.0` address is used). +You can configure HTTP request logging level using `log_requests` parameter (e.g. "verbose"). +Supported values are "debug", "verbose", "info", "warn" and "error". +By default, requests are logged at "info" level. + User can access every working HTTP server from the configuration by name, using `require('roles.httpd').get_server(name)` method. If the `name` argument is `nil`, the default server is returned diff --git a/roles/httpd.lua b/roles/httpd.lua index 3415323..49ce049 100644 --- a/roles/httpd.lua +++ b/roles/httpd.lua @@ -1,5 +1,6 @@ local checks = require('checks') local urilib = require('uri') +local log = require('log') local http_server = require('http.server') local M = { @@ -75,7 +76,28 @@ end -- parse_params returns table with set options from config to pass -- it into new() function. local function parse_params(node) + local log_requests = node.log_requests + if type(log_requests) == "string" then + local level = log_requests:lower() + if level == "error" then + log_requests = log.error + elseif level == "warn" then + log_requests = log.warn + elseif level == "info" then + log_requests = log.info + elseif level == "verbose" then + log_requests = log.verbose + elseif level == "debug" then + log_requests = log.debug + else + error("invalid log_requests: " .. log_requests) + end + elseif log_requests ~= nil then + error("log_requests option should be a string") + end + return { + log_requests = log_requests, ssl_cert_file = node.ssl_cert_file, ssl_key_file = node.ssl_key_file, ssl_password = node.ssl_password, diff --git a/test/integration/httpd_role_test.lua b/test/integration/httpd_role_test.lua index 35b17cd..dcfa865 100644 --- a/test/integration/httpd_role_test.lua +++ b/test/integration/httpd_role_test.lua @@ -9,7 +9,20 @@ local http_client = require('http.client').new() local helpers = require('test.helpers') -local g = t.group(nil, t.helpers.matrix({use_tls = {true, false}})) +local LOG_LEVEL = { + INFO = 5, + VERBOSE = 6, + DEBUG = 7, +} + +local g = t.group(nil, t.helpers.matrix({ + use_tls = {true, false}, + log_level = { + LOG_LEVEL.INFO, + LOG_LEVEL.VERBOSE, + LOG_LEVEL.DEBUG, + }, +})) local ssl_data_dir = fio.abspath(fio.pathjoin(helpers.get_testdir_path(), "ssl_data")) @@ -36,10 +49,16 @@ local config = { ['roles.httpd'] = { default = { listen = 13000, + log_requests = 'info', }, additional = { listen = 13001, - } + log_requests = 'verbose', + }, + additional_debug = { + listen = 13002, + log_requests = 'debug', + }, }, ['test.mocks.mock_role'] = { { @@ -49,6 +68,10 @@ local config = { id = 2, name = 'additional', }, + { + id = 3, + name = 'additional_debug', + } }, }, instances = { @@ -75,6 +98,8 @@ g.before_each(function(cg) local dir = treegen.prepare_directory({}, {}) + os.setenv('TT_LOG_LEVEL', tostring(cg.params.log_level)) + local cfg = config if cg.params.use_tls then cfg = tls_config @@ -146,3 +171,32 @@ g.test_change_server_addr_on_the_run = function(cg) t.assert_equals(resp.status, 200, 'response not 200') t.assert_equals(resp.body, 'pong') end + +g.test_log_requests = function(cg) + t.skip_if(cg.params.use_tls) + + local function make_request(port) + local resp = http_client:get(string.format('http://localhost:%d/ping', port)) + t.assert_equals(resp.status, 200, 'response not 200') + end + + local function assert_should_log(expected) + local grep_res = cg.server:grep_log('GET /ping', math.huge) + if expected then + t.assert(grep_res) + else + t.assert_not(grep_res) + end + end + + local log_level = tonumber(cg.params.log_level) + + make_request(13002) + assert_should_log(log_level >= LOG_LEVEL.DEBUG) + + make_request(13001) + assert_should_log(log_level >= LOG_LEVEL.VERBOSE) + + make_request(13000) + assert_should_log(log_level >= LOG_LEVEL.INFO) +end diff --git a/test/unit/httpd_role_test.lua b/test/unit/httpd_role_test.lua index 075565a..48cf837 100644 --- a/test/unit/httpd_role_test.lua +++ b/test/unit/httpd_role_test.lua @@ -209,6 +209,24 @@ local validation_cases = { }, err = "ssl_key_file and ssl_cert_file must be set to enable TLS", }, + ["log_requests_invalid_string"] = { + cfg = { + server = { + listen = "localhost:123", + log_requests = "yes", + }, + }, + err = "invalid log_requests", + }, + ["log_requests_invalid_type"] = { + cfg = { + server = { + listen = "localhost:123", + log_requests = 42, + }, + }, + err = "log_requests option should be a string", + } } for name, case in pairs(validation_cases) do @@ -311,3 +329,26 @@ g.test_edit_server_address = function() t.assert(result) t.assert_equals(result.port, cfg[httpd_role.DEFAULT_SERVER_NAME].listen) end + +g.test_log_requests = function() + local cfg = { + server1 = { + listen = 13002, + log_requests = 'info', + }, + server2 = { + listen = 13003, + log_requests = 'verbose', + }, + } + + httpd_role.apply(cfg) + + local server1 = httpd_role.get_server('server1') + t.assert(server1) + t.assert_type(server1.options.log_requests, 'function') + + local server2 = httpd_role.get_server('server2') + t.assert(server2) + t.assert_type(server2.options.log_requests, 'function') +end