Module: GreenHat::Shell::Log

Defined in:
lib/greenhat/shell/log.rb

Overview

Logs

Class Method Summary collapse

Class Method Details

.auto_complete(list, word) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/greenhat/shell/log.rb', line 6

def self.auto_complete(list, word)
  # Argument Parsing
  files, flags, _args = Args.parse(list)

  # Don't try to autocomplete anything else
  return nil unless word =~ /^-/

  # Clean Up
  word.delete!('-')
  matches = FieldHelper.filter_flags(word)

  if matches.count == 1
    "--#{matches.first}"
  elsif matches.count > 1
    puts "#{'Filter Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
    "--#{Cli.common_substr(matches)}"
    # -----------------------------------
    # TODO: Fix Icky Double Nesting
  elsif files.count.nonzero?
    matches = FieldHelper.fields_find(files, word, flags)

    return nil if matches.nil?

    if matches.count == 1
      "--#{matches.first}"
    elsif matches.count > 1
      puts "#{'Field Options:'.pastel(:bright_blue)} #{matches.join(' ').pastel(:bright_green)}"
      "--#{Cli.common_substr(matches.map(&:to_s))}"
    elsif FieldHelper.field_auto_complete?(word)
      FieldHelper.field_auto_complete(word, files, flags)
    end
    # -----------------------------------
  end
end

.default(raw_list) ⇒ Object

Filter (See Filter Help)



198
199
200
# File 'lib/greenhat/shell/log.rb', line 198

def self.default(raw_list)
  filter(raw_list)
end

.examplesObject

rubocop:disable Layout/LineLength TODO: Add a lot more examples



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/greenhat/shell/log.rb', line 244

def self.examples
  puts 'Find `done` job for sidekiq, sort by duration, only duration, and show longest first'.pastel(:bright_green)
  puts 'log filter sidekiq/current --job_status=done --sort=duration_s,db_duration_s --slice=duration_s,db_duration_s --reverse'
  puts

  puts 'Find 500s only show exceptions'.pastel(:bright_green)
  puts 'log filter --status=500 --slice=exception.message gitlab-rails/production_json.log'
  puts

  puts 'Show unique sidekiq queue namespaces. Exclude Specifics'.pastel(:bright_green)
  puts 'filter sidekiq/current --slice=queue_namespace --uniq=queue_namespace --queue_namespace!=jira_connect --queue_namespace!=hashed_storage'
  puts

  puts 'Show user,ip from API logs where `meta.user` field is present '.pastel(:bright_green)
  puts 'gitlab-rails/api_json.log --slice=meta.user,meta.remote_ip --exists=meta.user'
  puts

  puts 'Count/% occurences for both user and remote ip fields'.pastel(:bright_green)
  puts 'gitlab-rails/api_json.log --stats=meta.user,meta.remote_ip --exists=meta.user'
  puts

  puts 'Sidekiq jobs that took over 5 seconds excluding LdapSyncWorker jobs'.pastel(:bright_green)
  puts 'sidekiq/current --duration_s>=5 --class!=LdapSyncWorker'
  puts

  puts 'Search access logs for runner requests, exclude specific runner version'.pastel(:bright_green)
  puts 'nginx/gitlab_access.log --http_user_agent=gitlab-runner  --http_user_agent!=13.12.0'
  puts

  puts 'Get a list of unique Gitaly error messages for a specific project'.pastel(:bright_green)
  puts 'filter --level=error --grpc.request.glProjectPath=path/to/project  gitaly/current --slice=error --uniq=error'
  puts

  puts 'Show workhorse duration/URI. Filter by duration bounds'.pastel(:bright_green)
  puts 'gitlab-workhorse/current --duration_ms>=30000 --duration_ms<=45000 --slice=duration_ms,uri'
  puts

  puts 'Show runner statistics'.pastel(:bright_green)
  puts 'gitlab-rails/api_json.log --path=/api/v4/jobs/request --percentile --round=2'
  puts
end

.filter(raw) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
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
# File 'lib/greenhat/shell/log.rb', line 202

def self.filter(raw)
  # Print Helper
  if raw == ['help']
    filter_help(raw)
    return true
  end

  ShellHelper::Log.last = raw

  # Argument Parsing
  files, flags, args = Args.parse(raw)

  # Prepare Log List
  files = ShellHelper.prepare_list(files, ShellHelper::Log.list)

  results = Query.start(files, flags, args)

  # Skip and Print Total if set
  if flags[:fields]
    ShellHelper.fields_print(files)
    return true
  end

  # Check Search Results
  if results.empty?
    puts 'No results'.pastel(:red)
    ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
  elsif flags[:pipe]
    Pipe.show(results, flags[:pipe])
  else
    # Allow for array / multiple table outputs
    # This causes the key 'colorized' output to also be included
    ShellHelper.show(results, flags)
  end
rescue StandardError => e
  LogBot.fatal('Filter', message: e.message)
  ap e.backtrace
end

.filter_help(raw = {}) ⇒ Object



78
79
80
81
82
# File 'lib/greenhat/shell/log.rb', line 78

def self.filter_help(raw = {})
  args, flags, _args = Args.parse(raw)

  ShellHelper.show(ShellHelper::Filter.help(args.first), flags)
end

.helpObject



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
# File 'lib/greenhat/shell/log.rb', line 41

def self.help
  puts "\u2500".pastel(:cyan) * 20
  puts "#{'Logs'.pastel(:yellow)} find stuff"
  puts "\u2500".pastel(:cyan) * 20

  puts 'Command Summary'.pastel(:blue)
  puts '  filter'.pastel(:green)
  puts "    Primary way for log searching within greenhat. See #{'filter_help'.pastel(:blue)}"
  puts '    Time, round, slice/except, and/or, stats, uniq, sort'
  puts "    #{'filter_help'.pastel(:blue)} supports filtering Ex: #{'filter_help stats'.pastel(:blue)}"
  puts

  puts '  show'.pastel(:green)
  puts '    Just print selected logs'
  puts

  puts '  search'.pastel(:green)
  puts "    Deprecated! Use the #{'filter --text="search"'.pastel(:blue)} instead"
  puts

  puts '  save'.pastel(:green)
  puts '    Save the last query result into a new searchable object'
  puts

  puts '  write'.pastel(:green)
  puts '    Write the last query result into a local file'
  puts

  puts '  visualize'.pastel(:green)
  puts '    Load web services and formulate last query for the UI'
  puts

  puts ShellHelper::List.help

  puts "See #{'examples'.pastel(:bright_blue)} for query examples"
end

.ls(args = []) ⇒ Object



84
85
86
# File 'lib/greenhat/shell/log.rb', line 84

def self.ls(args = [])
  ShellHelper::List.list(args, ShellHelper::Log.list)
end

.save(raw = []) ⇒ Object



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
128
129
# File 'lib/greenhat/shell/log.rb', line 98

def self.save(raw = [])
  if ShellHelper::Log.last.nil?
    puts 'No previous query found'.pastel(:red)
    puts 'Run a query first then save to store as a new log'
    puts
    puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'save'.pastel(:green)}"
    true
  end

  name = if raw.empty?
           Cli.prompt.ask('Log entry to save the results to? '.pastel(:yellow))
         else
           raw.first
         end

  if name.blank?
    puts 'Name required'.pastel(:red)
    return true
  end

  results = ShellHelper.filter_internal ShellHelper::Log.last

  # Don't save empty results
  if results.empty?
    puts 'No results'.pastel(:red)
    ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
    return false
  end

  Thing.new.query_save(save_greenhat_query_info + results, name)
  puts "#{name.pastel(:green)} Saved!"
end

.save_greenhat_query_infoObject



131
132
133
134
135
136
137
# File 'lib/greenhat/shell/log.rb', line 131

def self.save_greenhat_query_info
  [{
    time: Time.now,
    query: ShellHelper::Log.last,
    msg: 'GreenHat Save/Write'
  }]
end

.show(raw = {}) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/greenhat/shell/log.rb', line 88

def self.show(raw = {})
  # Extract Args
  files_list, flags, _args = Args.parse(raw)

  # Collect Files
  files = ShellHelper.files(files_list, Thing.all, flags)

  ShellHelper.show files.map(&:data).flatten
end

.visualizeObject



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/greenhat/shell/log.rb', line 173

def self.visualize
  if ShellHelper::Log.last.nil?
    puts 'No previous query found'.pastel(:red)
    puts 'Run a query first then visualize to load it in the chart web page'
    puts
    puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'visualize'.pastel(:green)}"
    return true
  end

  # Load Required Files
  require 'greenhat/web'

  unless GreenHat::Web.alive?
    GreenHat::Web.start
    sleep 0.2
  end

  url = "http://localhost:4567/chart/time?query=#{CGI.escape(ShellHelper::Log.last)}"

  GreenHat::Platform.open url
end

.write(raw = []) ⇒ Object



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
# File 'lib/greenhat/shell/log.rb', line 139

def self.write(raw = [])
  if ShellHelper::Log.last.nil?
    puts 'No previous query found'.pastel(:red)
    puts 'Run a query first then write'
    puts
    puts "Try #{'nginx/gitlab_access.log --status!=200'.pastel(:green)} then #{'save'.pastel(:green)}"
    true
  end

  name = if raw.empty?
           Cli.prompt.ask('Filename to save the results to? '.pastel(:yellow))
         else
           raw.first
         end

  if name.blank?
    puts 'Name required'.pastel(:red)
    return true
  end

  results = ShellHelper.filter_internal ShellHelper::Log.last

  # Don't save empty results
  if results.empty?
    puts 'No results'.pastel(:red)
    ShellHelper::Log.no_files_warning(files) if ShellHelper.find_things(files, flags).count.zero?
    return false
  end

  all = (save_greenhat_query_info + results).map { |row| Oj.dump(row) }
  File.write(name, all.join("\n"))
  puts "#{name.pastel(:green)} File Written!"
end