Class: Dynowatch::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/dynowatch/parser.rb

Constant Summary collapse

ENDPOINTS =

A list of endpoints to be analyzed as specified by the problem statement

{
  users: {
    count_pending_messages: { 'GET': 'count_pending_messages' },
    get_messages: { 'GET': 'get_messages' },
    get_friends_progress: { 'GET': 'get_friends_progress' },
    get_friends_score: { 'GET': 'get_friends_score' },
    blank: {
      'POST': 'create_user',
      'GET': 'get_user'
    }
  }
}
VALID_LOG_LINE =

Regular expressions for testing routes

/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\ heroku\[router\]\:/
REQUEST_METHOD =
/method\=([A-Z]+)/
API_RESOURCE =
/path\=\/api\/(\w+)\/.+/
API_ENDPOINT =
/path\=\/api\/\w+\/\d+\/(\w+)/
CONNECT_TIME =

Regular expressions for obtaining request times

/connect\=(\d+)\w+/
SERVICE_TIME =
/service\=(\d+)\w+/
DYNO =

Regular expression to fetch responding dyno

/dyno\=([a-z.0-9]+)/

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



30
31
32
# File 'lib/dynowatch/parser.rb', line 30

def initialize

end

Class Method Details

.get_dyno(log) ⇒ Object

Get the responding dyno for the request in the log



74
75
76
# File 'lib/dynowatch/parser.rb', line 74

def self.get_dyno(log)
  log.match(DYNO)[1]
end

.get_route_name(log, valid_resource) ⇒ Object

Check if the log file contains a request to a route listed in ENDPOINTS



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/dynowatch/parser.rb', line 44

def self.get_route_name(log, valid_resource)
  # Get the request method
  method = log.match(REQUEST_METHOD).to_a.dig(1)
  # Get API resource
  resource = log.match(API_RESOURCE).to_a.dig(1)
  # Get API endpoint
  endpoint = log.match(API_ENDPOINT).to_a.dig(1) || 'blank'

  # Check if the log should be processed
  # - Ensure a method exists
  # - Ensure the resource in the route matches the ones to be analyzed. For
  # example, the current resource to be analyzed is 'users' so the route
  # must match /api/users
  # - Ensure the endpoint is listed in the ENDPOINTS object
  if method && (resource == valid_resource) && (ENDPOINTS[valid_resource.to_sym].keys().include? endpoint.to_sym)
    ENDPOINTS[resource.to_sym][endpoint.to_sym][method.to_sym]
  else
    false
  end
end

.get_time(log) ⇒ Object

Obtain the response time for the request in the log



66
67
68
69
70
71
# File 'lib/dynowatch/parser.rb', line 66

def self.get_time(log)
  connect_time = log.match(CONNECT_TIME)[1].to_i
  service_time = log.match(SERVICE_TIME)[1].to_i

  connect_time + service_time
end

.is_valid_log(log) ⇒ Object

A valid Heroku log has the form: time hostname heroku: <log-details> Example: 2014-01-09T06:16:53.742892+00:00 heroku: at=info method=GET path=/api/users/100002266342173/count_pending_messages host=services.pocketplaylab.com fwd=“94.66.255.106” dyno=web.8 connect=9ms service=9ms status=304 bytes=0 We’re only concerned with the format at the beginning.



39
40
41
# File 'lib/dynowatch/parser.rb', line 39

def self.is_valid_log(log)
  !!(log =~ VALID_LOG_LINE)
end

.parse_log_file(log_file_path, valid_resource, log_file_info) ⇒ Object

Read information from a log file and update the log data



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/dynowatch/parser.rb', line 93

def self.parse_log_file(log_file_path, valid_resource, log_file_info)
  # Resource path
  resc = valid_resource.to_sym

  # Read log file
  File.open(log_file_path, 'r') do |infile|
    while line = infile.gets
      log_info = parse_log_line(line, valid_resource)

      if log_info
        log_url = log_info[:route].to_sym

        # Increment count for the file
        log_file_info[resc][log_url][:count] += 1
        log_file_info[resc][log_url][:times] << log_info[:time]
        log_file_info[resc][log_url][:dynos] << log_info[:dyno]
      end
    end
  end

  log_file_info
end

.parse_log_line(log, valid_resource) ⇒ Object

Get route, response time and dyno details from a log line



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/dynowatch/parser.rb', line 79

def self.parse_log_line(log, valid_resource)
  if is_valid_log(log)
    route_name = get_route_name(log, valid_resource)
    if route_name
      {
        route: route_name,
        time: get_time(log),
        dyno: get_dyno(log)
      }
    end
  end
end