Class: Logical::Naf::LogParser::Base

Inherits:
Object
  • Object
show all
Defined in:
app/models/logical/naf/log_parser/base.rb

Direct Known Subclasses

Job, Machine, Runner

Constant Summary collapse

REGEX_OPTIONS =
{
  'i' => Regexp::IGNORECASE,
  'x' => Regexp::EXTENDED,
  'm' => Regexp::MULTILINE
}
DATE_REGEX =
/((\d){8}_(\d){6})/
UUID_REGEX =
/[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/
LOG_SIZE_CHUNKS =
500

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Base

Returns a new instance of Base.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/models/logical/naf/log_parser/base.rb', line 31

def initialize(params)
  @search_params = params['search_params'].nil? ? '' : params['search_params']
  @regex_options = get_option_value(params['regex_options'])
  @grep = params['grep']
  @search_from_time = params['from_time']
  @search_to_time = params['to_time']
  @jsons = []
  @logs_size = 0
  @log_type = params['log_type']
  @newest_log = params['newest_log']
  @record_id = params['record_id']
  @read_from_s3 = params['read_from_s3']
  @last_file_checked = params['last_file_checked']
  @newest_file_checked = params['newest_file_checked']
end

Instance Attribute Details

#grepObject

Returns the value of attribute grep.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def grep
  @grep
end

#jsonsObject

Returns the value of attribute jsons.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def jsons
  @jsons
end

#last_file_checkedObject

Returns the value of attribute last_file_checked.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def last_file_checked
  @last_file_checked
end

#log_typeObject

Returns the value of attribute log_type.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def log_type
  @log_type
end

#logs_sizeObject

Returns the value of attribute logs_size.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def logs_size
  @logs_size
end

#newest_file_checkedObject

Returns the value of attribute newest_file_checked.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def newest_file_checked
  @newest_file_checked
end

#newest_logObject

Returns the value of attribute newest_log.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def newest_log
  @newest_log
end

#read_from_s3Object

Returns the value of attribute read_from_s3.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def read_from_s3
  @read_from_s3
end

#record_idObject

Returns the value of attribute record_id.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def record_id
  @record_id
end

#regex_optionsObject

Returns the value of attribute regex_options.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def regex_options
  @regex_options
end

#s3_log_readerObject

Returns the value of attribute s3_log_reader.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def s3_log_reader
  @s3_log_reader
end

#search_from_timeObject

Returns the value of attribute search_from_time.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def search_from_time
  @search_from_time
end

#search_paramsObject

Returns the value of attribute search_params.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def search_params
  @search_params
end

#search_to_timeObject

Returns the value of attribute search_to_time.



16
17
18
# File 'app/models/logical/naf/log_parser/base.rb', line 16

def search_to_time
  @search_to_time
end

Instance Method Details

#build_time_string(search_time) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'app/models/logical/naf/log_parser/base.rb', line 215

def build_time_string(search_time)
  # Year
  search_built_time = search_time[0] + "-"
  # Month
  if search_time[1].to_i < 10
    search_built_time << '0' + search_time[1] + '-'
  else
    search_built_time << search_time[1] + '-'
  end
  # Day
  if search_time[2].to_i < 10
    search_built_time << '0' + search_time[2] + ' '
  else
    search_built_time << search_time[2] + ' '
  end
  # Hour
  search_built_time << search_time[3] + ':'
  # Minute
  if search_time[4].to_i < 10
    search_built_time << '0' + search_time[4]
  else
    search_built_time << search_time[4]
  end
  # Second
  search_built_time << ':00 -0500'

  search_built_time
end

#check_repeated_logsObject



66
67
68
69
70
71
72
73
74
75
# File 'app/models/logical/naf/log_parser/base.rb', line 66

def check_repeated_logs
  if log_type == 'new' && newest_log.present?
    @jsons.each_with_index do |elem, index|
      if parse_log(elem) == parse_newest_log
        @jsons = @jsons[(index + 1)..-1]
        return
      end
    end
  end
end

#filter_filesObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/logical/naf/log_parser/base.rb', line 134

def filter_files
  files = get_files
  original_size = files.size

  files.each_with_index do |file, index|
    filename = file.scan(/\d+_\d{8}_\d{6}.*/).first

    if log_type == 'old'
      if filename == last_file_checked
        if files.size == 1
          files = []
        else
          files = files[(index + 1)..-1]
        end
      end

      if files.size == 0 && read_from_s3 != 'true'
        get_s3_files do
          @read_from_s3 = 'true'
          @s3_log_reader = ::Logical::Naf::LogReader.new
          return retrieve_log_files_from_s3
        end
      end
    elsif log_type == 'new'
      if filename == newest_file_checked
        if files.size == 1
          files = []
        else
          files = files[0..(index - 1)]
        end
      end
    end

    break if original_size != files.size
  end

  if files.present?
    if newest_file_checked.blank? || newest_file_checked == 'null'
      @newest_file_checked = files[0].scan(/\d+_\d{8}_\d{6}.*/).first
    else
      if Time.parse(newest_file_checked.scan(DATE_REGEX)[0][0]) < Time.parse(files[0].scan(DATE_REGEX)[0][0])
        @newest_file_checked = files[0].scan(/\d+_\d{8}_\d{6}.*/).first
      end
    end
  end

  return files
end

#filter_log_messages(log) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'app/models/logical/naf/log_parser/base.rb', line 183

def filter_log_messages(log)
  # Check that the message matches the search query. Highlight the matching results
  if search_params.present?
    log['message'].scan(Regexp.new(search_params, regex_options)).each do |match|
      log['message'].gsub!(match, "<span style='background-color:yellow;'>#{match}</span>")
    end
  end

  # Check that the log happened within the time range specified
  if log_within_time_range(log['output_time'])
    # If grep is selected, only show log messages that match the
    # search query. Otherwise, show all log messages.
    if grep == 'false' || log['message'] =~ Regexp.new(search_params, regex_options)
      @jsons << log
      @logs_size += 1
    end
  end
end

#get_json_from_log_file(file) ⇒ Object



126
127
128
129
130
131
132
# File 'app/models/logical/naf/log_parser/base.rb', line 126

def get_json_from_log_file(file)
  if read_from_s3 == 'true' && s3_log_reader.present?
    s3_log_reader.retrieve_file(file)
  else
    File.new(file, 'r')
  end
end

#get_option_value(options) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
# File 'app/models/logical/naf/log_parser/base.rb', line 244

def get_option_value(options)
  return 0 if options.blank?

  options = options.split(//)
  result = 0
  options.each do |opt|
    result |= REGEX_OPTIONS[opt]
  end

  result
end

#get_s3_filesObject



256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'app/models/logical/naf/log_parser/base.rb', line 256

def get_s3_files
  begin
    yield
  rescue
    @jsons << {
      'line_number' => 0,
      'output_time' => Time.zone.now.strftime("%Y-%m-%d %H:%M:%S.%L"),
      'message' => 'AWS S3 Access Denied. Please check your permissions.'
    }

    return []
  end
end

#log_within_time_range(log_time) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
# File 'app/models/logical/naf/log_parser/base.rb', line 202

def log_within_time_range(log_time)
  return true if (search_from_time.join('').blank? && search_to_time.join('').blank?) || log_time.blank?

  if search_from_time.join('').present? && search_to_time.join('').present?
    Time.parse(log_time) <= Time.parse(build_time_string(search_to_time)) &&
    Time.parse(log_time) >= Time.parse(build_time_string(search_from_time))
  elsif search_from_time.join('').present?
    Time.parse(log_time) >= Time.parse(build_time_string(search_from_time))
  elsif search_to_time.join('').present?
    Time.parse(log_time) <= Time.parse(build_time_string(search_to_time))
  end
end

#parse_filesObject



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
# File 'app/models/logical/naf/log_parser/base.rb', line 87

def parse_files
  files = filter_files

  files.each do |file|
    # Use Yajl JSON library to parse the log files, as they contain multiple JSON blocks
    parser = Yajl::Parser.new
    json = get_json_from_log_file(file)
    parser.parse(json) do |log|
      if self.class.to_s == 'Logical::Naf::LogParser::Runner'
        log['id'] = get_invocation_id(file.scan(UUID_REGEX).first)
      elsif self.class.to_s == 'Logical::Naf::LogParser::Machine'
        log['job_id'] = get_job_id(file)
      end
      filter_log_messages(log)
    end

    sort_jsons

    if logs_size >= LOG_SIZE_CHUNKS
      update_last_file_checked(file.scan(/\d+_\d{8}_\d{6}.*/).first)
      break
    end
  end

  if logs_size < LOG_SIZE_CHUNKS && files.present?
     update_last_file_checked(files.last.scan(/\d+_\d{8}_\d{6}.*/).first)
  end
end

#parse_log(log) ⇒ Object



77
78
79
80
81
82
83
84
85
# File 'app/models/logical/naf/log_parser/base.rb', line 77

def parse_log(log)
  if log['message'].scan(/\t/).present?
    message = log['message'].clone
    message.slice!('<top (required)>')
    "#{log['output_time']} #{message}"
  else
    "#{log['output_time']} #{log['message']}"
  end
end

#retrieve_logsObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'app/models/logical/naf/log_parser/base.rb', line 47

def retrieve_logs
  parse_files

  check_repeated_logs

  output = ''
  jsons.reverse_each do |elem|
    output.insert(0, insert_log_line(elem))
  end

  return {
    logs: output.html_safe,
    read_from_s3: read_from_s3,
    last_file_checked: last_file_checked,
    newest_file_checked: newest_file_checked,
    newest_log: newest_log
  }
end

#update_last_file_checked(file) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'app/models/logical/naf/log_parser/base.rb', line 116

def update_last_file_checked(file)
  if file.present? && last_file_checked.present? && last_file_checked != 'null'
    if Time.parse(file.scan(/\d{8}_\d{6}/).first) < Time.parse(last_file_checked.scan(/\d{8}_\d{6}/).first)
      @last_file_checked = file
    end
  elsif file.present?
    @last_file_checked = file
  end
end