Class: IuguLogger::RequestLogger

Inherits:
Object
  • Object
show all
Defined in:
lib/iugu_logger/request_logger.rb

Overview

Rack middleware — emits ONE consolidated log per HTTP request:

event.action = http.request.completed (or http.request.failed on raise)

Behavior:

1. On request start: resets thread-local Buffer, populates context with
   trace + iugu (auto-extracted from env via TraceContext / TenantContext).
2. App / controllers call IuguLogger::Buffer.current.push(...) for in-app
   logs throughout the request. (Once Railtie lands in v0.5,
   Rails.logger.X also routes here.)
3. On request end: drains the buffer, emits a single event including
   `logs: [...]` (the buffered entries) plus http status and duration.
4. Always resets the buffer afterward.

Failures: when the downstream app raises, emits ‘http.request.failed` with the partial buffer + exception, then re-raises so other middleware sees the original error.

Insertion: typically right after Rails’ DebugExceptions and before ActionDispatch’s logger so we capture exceptions but bypass Rails’ own request logging.

Spec: IUGU_LOGGING_STANDARD.md §6 (RequestLogger middleware)

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ RequestLogger

Returns a new instance of RequestLogger.



27
28
29
# File 'lib/iugu_logger/request_logger.rb', line 27

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/iugu_logger/request_logger.rb', line 31

def call(env)
  Buffer.reset!
  buffer = Buffer.current

  trace = TraceContext.extract(rack_env: env)
  req   = build_request_block(env)

  # Tenant is best-effort here (covers Rack middleware upstream that may
  # have populated env['iugu.current_*']). The canonical timing is after
  # @app.call — host apps typically populate tenant in a controller
  # before_action, which only runs once Rails has dispatched the action.
  tenant = TenantContext.from_rack(env)
  buffer.add_context(trace: trace, iugu: tenant, request: req)

  start = monotonic_now
  status, headers, body = @app.call(env)
  duration_ms = elapsed_ms(start)

  # Re-read tenant: controllers may have populated env['iugu.current_*']
  # via before_actions during @app.call. The earlier extraction would
  # have missed those — see spec §6.3 (RequestLogger / TenantContext).
  tenant = TenantContext.from_rack(env)

  # Enrich request with Rails dispatch info populated during @app.call
  # (params, format). Pre-call build_request_block couldn't see these.
  req = enrich_request_post_dispatch(req, env)

  emit_completed(req: req, trace: trace, tenant: tenant,
                 status: status, duration_ms: duration_ms,
                 rails: extract_rails_info(env),
                 logs: buffer.drain)

  [status, headers, body]
rescue StandardError => e
  duration_ms = elapsed_ms(start)
  # Same re-read on failure path: if the controller populated tenant
  # before raising, we should still report it.
  tenant = TenantContext.from_rack(env)
  req    = enrich_request_post_dispatch(req, env)
  emit_failed(req: req, trace: trace, tenant: tenant, error: e,
              duration_ms: duration_ms,
              rails: extract_rails_info(env),
              logs: buffer&.drain || [])
  raise
ensure
  Buffer.reset!
end