class HTTP::Features::Logging
HTTP.use(logging: {logger: Logger.new(STDOUT), binary_formatter: :base64})
@example Custom binary formatter
- Proc — calls the proc with the raw binary string
- :base64 — logs BINARY DATA (N bytes)\n<base64>
- :stats (default) — logs BINARY DATA (N bytes)
of being dumped raw. Available formatters:
responses) are formatted using the binary_formatter option instead
Binary bodies (IO/Enumerable request sources and binary-encoded
HTTP.use(logging: {logger: Logger.new(STDOUT)}).get(“example.com/”)
‘debug`. Be sure to specify the logger when enabling the feature:
logged at `info`, and the headers and bodies of both are logged at
Log requests and responses. Request verb and uri, and Response status are
def format_binary(data)
- Api: - private
Returns:
-
(String)-
def format_binary(data) case @binary_formatter when :stats format("BINARY DATA (%d bytes)", data.bytesize) when :base64 format("BINARY DATA (%d bytes)\n%s", data.bytesize, [data].pack("m0")) else @binary_formatter.call(data) # steep:ignore end end
def initialize(logger: NullLogger.new, binary_formatter: :stats)
- Api: - public
Returns:
-
(Logging)-
Parameters:
-
binary_formatter(:stats, :base64, #call) -- how to log binary bodies -
logger(#info, #debug) -- logger instance
Other tags:
- Example: With binary formatter -
def initialize(logger: NullLogger.new, binary_formatter: :stats) super() @logger = logger @binary_formatter = validate_binary_formatter!(binary_formatter) end
def log_request_details(request)
- Api: - private
Returns:
-
(void)-
def log_request_details(request) headers = stringify_headers(request.headers) if request.body.loggable? source = request.body.source body = source.encoding.eql?(Encoding::BINARY) ? format_binary(source) : source logger.debug { "#{headers}\n\n#{body}" } else logger.debug { headers } end end
def log_response_body_inline(response)
- Api: - private
Returns:
-
(HTTP::Response)-
def log_response_body_inline(response) body = response.body headers = stringify_headers(response.headers) if body.respond_to?(:encoding) && body.encoding.eql?(Encoding::BINARY) logger.debug { "#{headers}\n\n#{format_binary(body)}" } # steep:ignore else logger.debug { "#{headers}\n\n#{body}" } end response end
def logged_body(body)
- Api: - private
Returns:
-
(HTTP::Response::Body)-
def logged_body(body) formatter = (method(:format_binary) unless body.loggable?) stream = BodyLogger.new(body.instance_variable_get(:@stream), logger, formatter: formatter) # steep:ignore Response::Body.new(stream, encoding: body.encoding) end
def logged_response_options(response)
- Api: - private
Returns:
-
(Hash)-
def logged_response_options(response) { status: response.status, version: response.version, headers: response.headers, proxy_headers: response.proxy_headers, connection: response.connection, body: logged_body(response.body), request: response.request } end
def stringify_headers(headers)
- Api: - private
Returns:
-
(String)-
def stringify_headers(headers) headers.map { |name, value| "#{name}: #{value}" }.join("\n") end
def validate_binary_formatter!(formatter)
- Api: - private
Raises:
-
(ArgumentError)- if the formatter is not a valid option
Returns:
-
(:stats, :base64, #call)-
def validate_binary_formatter!(formatter) return formatter if formatter.eql?(:stats) || formatter.eql?(:base64) || formatter.respond_to?(:call) raise ArgumentError, "binary_formatter must be :stats, :base64, or a callable " \ "(got #{formatter.inspect})" end
def wrap_request(request)
- Api: - public
Returns:
-
(HTTP::Request)-
Parameters:
-
request(HTTP::Request) --
def wrap_request(request) logger.info { format("> %s %s", String(request.verb).upcase, request.uri) } log_request_details(request) request end
def wrap_response(response)
- Api: - public
Returns:
-
(HTTP::Response)-
Parameters:
-
response(HTTP::Response) --
def wrap_response(response) logger.info { "< #{response.status}" } return log_response_body_inline(response) unless response.body.is_a?(Response::Body) logger.debug { stringify_headers(response.headers) } return response unless logger.debug? Response.new(**logged_response_options(response)) # steep:ignore end