Class: Pliny::Middleware::CanonicalLogLine

Inherits:
Object
  • Object
show all
Defined in:
lib/pliny/middleware/canonical_log_line.rb

Overview

Emits a “canonical log line”, i.e. a single log line that contains as much relevant information about a request as possible and which makes for a single convenient reference point to understand all the vitals of any single request.

This default implementation contains some useful data to get a project started, but it’s usually recommended to vendor this middleware into your project and start adding some custom fields. Some examples of those might be:

* ID and email of an authenticated user.
* ID of API key used, OAuth application and scope.
* Remaining and total rate limits.
* Name of the service, HEAD revision, release number.
* Name of the internal system that initiated the request.

Defined Under Namespace

Classes: LogLine

Instance Method Summary collapse

Constructor Details

#initialize(app, options) ⇒ CanonicalLogLine

Returns a new instance of CanonicalLogLine.



61
62
63
64
# File 'lib/pliny/middleware/canonical_log_line.rb', line 61

def initialize(app, options)
  @app = app
  @emitter = options.fetch(:emitter)
end

Instance Method Details

#call(env) ⇒ Object



66
67
68
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/pliny/middleware/canonical_log_line.rb', line 66

def call(env)
  begin
    start = Time.now
    status, headers, response = @app.call(env)
  ensure
    begin
      line = LogLine.new

      #
      # error
      #

      if error = env["pliny.error"]
        line.error_class = error.class.name
        line.error_message = error.message
        if error.is_a?(Pliny::Errors::Error)
          line.error_id = error.id.to_s
        end
      end

      #
      # request
      #

      request = Rack::Request.new(env)
      line.request_id = env["REQUEST_ID"]
      line.request_ip = request.ip
      line.request_method = request.request_method
      line.request_path = request.path_info
      line.request_user_agent = request.user_agent
      if route = env["sinatra.route"]
        line.request_route_signature = route.split(" ").last
      end

      #
      # response
      #

      if length = headers["Content-Length"]
        line.response_length = length.to_i
      end
      line.response_status = status
      line.serializer_arity = env["pliny.serializer_arity"]

      #
      # timing
      #

      line.timing_total_elapsed = (Time.now - start).to_f
      line.timing_serializer = env["pliny.serializer_timing"]

      @emitter.call(line.to_h)
    rescue => e
      # We hope that a canonical log line never fails, but in case it
      # does, do not fail the request because it did.
      Pliny.log(message: "Failed to emit canonical log line")
      Pliny::ErrorReporters.notify(e, rack_env: env)
    end
  end

  [status, headers, response]
end