Class: Fbe::Middleware::Formatter

Inherits:
Faraday::Logging::Formatter
  • Object
show all
Defined in:
lib/fbe/middleware/formatter.rb

Overview

Custom Faraday formatter that logs only error responses (4xx/5xx).

This formatter reduces log noise by only outputting details when HTTP requests fail. For 403 errors with JSON responses, it shows a compact warning with the error message. For other errors, it logs the full request/response details including headers and bodies.

Author

Yegor Bugayenko (yegor256@gmail.com)

Copyright

Copyright © 2024-2026 Zerocracy

License

MIT

Examples:

Usage in Faraday middleware

connection = Faraday.new do |f|
  f.response :logger, nil, formatter: Fbe::Middleware::Formatter
end

Log output for 403 error

# GET https://api.github.com/repos/private/repo -> 403 / Repository access denied

Log output for other errors (500, 404, etc)

# GET https://api.example.com/endpoint HTTP/1.1
#   Content-Type: "application/json"
#   Authorization: "Bearer [FILTERED]"
#
#   {"query": "data"}
# HTTP/1.1 500
#   Content-Type: "text/html"
#
#   Internal Server Error

Instance Method Summary collapse

Constructor Details

#initialize(logger:, options:) ⇒ Formatter

Registers a filter that masks the credential portion of an ‘Authorization` header so live tokens never reach the log. Matches any auth scheme: `Authorization: “Bearer xxx”`, `Authorization: “Basic yyy”`, etc. The scheme is preserved, the credential is replaced with `[FILTERED]`.

Parameters:

  • logger (Logger)

    The Faraday-supplied logger

  • options (Hash)

    Faraday formatter options



50
51
52
53
# File 'lib/fbe/middleware/formatter.rb', line 50

def initialize(logger:, options:)
  super
  filter(/(Authorization:\s*"?\s*\S+\s+)[^"\s]+/i, '\1[FILTERED]')
end

Instance Method Details

#request(http) ⇒ void

This method returns an undefined value.

Captures HTTP request details for later use in error logging.

Parameters:

  • http (Hash)

    Request data including method, url, headers, and body



59
60
61
# File 'lib/fbe/middleware/formatter.rb', line 59

def request(http)
  @req = http
end

#response(http) ⇒ void

Note:

Only logs when status >= 400

Note:

Special handling for 403 JSON responses to show compact error message

This method returns an undefined value.

Logs HTTP response details only for error responses (4xx/5xx).

Parameters:

  • http (Hash)

    Response data including status, headers, and body



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/fbe/middleware/formatter.rb', line 69

def response(http) # rubocop:disable Metrics/AbcSize
  return if http.status < 400
  if http.status == 403 && http.response_headers['content-type'].start_with?('application/json')
    warn(
      [
        "#{@req.method.upcase} #{apply_filters(@req.url.to_s)}",
        '->',
        http.status,
        '/',
        JSON.parse(http.response_body)['message']
      ].join(' ')
    )
    return
  end
  if http.status >= 500 && http.response_headers['content-type']&.start_with?('text')
    error(
      [
        "#{@req.method.upcase} #{apply_filters(@req.url.to_s)} HTTP/1.1",
        shifted(apply_filters(dump_headers(@req.request_headers))),
        '',
        shifted(apply_filters(@req.request_body)),
        "HTTP/1.1 #{http.status}",
        shifted(apply_filters(dump_headers(http.response_headers))),
        '',
        shifted(apply_filters(http.response_body&.ellipsized(100, :right)))
      ].join("\n")
    )
    return
  end
  error(
    [
      "#{@req.method.upcase} #{apply_filters(@req.url.to_s)} HTTP/1.1",
      shifted(apply_filters(dump_headers(@req.request_headers))),
      '',
      shifted(apply_filters(@req.request_body)),
      "HTTP/1.1 #{http.status}",
      shifted(apply_filters(dump_headers(http.response_headers))),
      '',
      shifted(apply_filters(http.response_body))
    ].join("\n")
  )
end