groonga-query-log 1.2.9 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/doc/text/news.md +28 -0
  3. data/lib/groonga-query-log/command/analyzer/reporter/console.rb +1 -1
  4. data/lib/groonga-query-log/command/check-crash.rb +128 -36
  5. data/lib/groonga-query-log/command/extract.rb +12 -2
  6. data/lib/groonga-query-log/command/replay.rb +6 -0
  7. data/lib/groonga-query-log/parser.rb +7 -7
  8. data/lib/groonga-query-log/replayer.rb +3 -0
  9. data/lib/groonga-query-log/statistic.rb +6 -2
  10. data/lib/groonga-query-log/version.rb +2 -2
  11. data/test/command/test-extract.rb +30 -27
  12. data/test/fixtures/multi.expected +7 -7
  13. data/test/fixtures/n_entries.expected +3 -3
  14. data/test/fixtures/no-report-summary.expected +3 -3
  15. data/test/fixtures/order/-elapsed.expected +5 -5
  16. data/test/fixtures/order/-start-time.expected +5 -5
  17. data/test/fixtures/order/elapsed.expected +5 -5
  18. data/test/fixtures/order/start-time.expected +5 -5
  19. data/test/fixtures/query.log +1 -1
  20. data/test/fixtures/reporter/console.expected +5 -5
  21. data/test/fixtures/reporter/html.expected +7 -7
  22. data/test/fixtures/reporter/json-stream.expected +1 -1
  23. data/test/fixtures/reporter/json.expected +1 -1
  24. data/test/fixtures/run-regression-test/db.new/db +0 -0
  25. data/test/fixtures/run-regression-test/db.new/db.0000000 +0 -0
  26. data/test/fixtures/run-regression-test/db.new/db.0000100 +0 -0
  27. data/test/fixtures/run-regression-test/db.new/db.0000101 +0 -0
  28. data/test/fixtures/run-regression-test/db.new/db.0000102 +0 -0
  29. data/test/fixtures/run-regression-test/db.new/db.0000103 +0 -0
  30. data/test/fixtures/run-regression-test/db.new/db.0000103.c +0 -0
  31. data/test/fixtures/run-regression-test/db.new/db.001 +0 -0
  32. data/test/fixtures/run-regression-test/db.new/db.conf +0 -0
  33. data/test/fixtures/run-regression-test/db.new/groonga.log +165 -0
  34. data/test/fixtures/run-regression-test/db.old/db +0 -0
  35. data/test/fixtures/run-regression-test/db.old/db.0000000 +0 -0
  36. data/test/fixtures/run-regression-test/db.old/db.0000100 +0 -0
  37. data/test/fixtures/run-regression-test/db.old/db.0000101 +0 -0
  38. data/test/fixtures/run-regression-test/db.old/db.0000102 +0 -0
  39. data/test/fixtures/run-regression-test/db.old/db.0000103 +0 -0
  40. data/test/fixtures/run-regression-test/db.old/db.0000103.c +0 -0
  41. data/test/fixtures/run-regression-test/db.old/db.001 +0 -0
  42. data/test/fixtures/run-regression-test/db.old/db.conf +0 -0
  43. data/test/fixtures/run-regression-test/db.old/groonga.log +79 -0
  44. data/test/fixtures/run-regression-test/results/query.log +0 -0
  45. data/test/fixtures/target-commands.expected +4 -4
  46. data/test/fixtures/target-tables.expected +3 -3
  47. data/test/run-test.rb +2 -0
  48. data/test/test-replayer.rb +2 -3
  49. metadata +78 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 213e0534e4b93c131e48f76cfe2c6f8c7fea4a44
4
- data.tar.gz: 326a76731faf0f948a8362800748503036dca728
2
+ SHA256:
3
+ metadata.gz: 2bb623843ad5665d8efc011ac13bc1e3a2b5b57deeef9c2af2f8de81e4a5a06c
4
+ data.tar.gz: 2cd63a89d51337d68d449f77ea0dbcf8698fa395c88a37707ce0b95a65c25bab
5
5
  SHA512:
6
- metadata.gz: 55fd3f7d8ed2fa51f94ed333e8afeaaef19ad5230b2a4ab8c0ce9622cde117891e3c26bda0f78a0560dcb0382a3b09c843c09cc474cb62faf3b3607a59d51b44
7
- data.tar.gz: eff099b4e055fc9e6e332a4d8bd8ae1987596ddab11fc842e83d965603147b68270395102cc9860cc09fb13e6004ebaf2a2bf8a949552bb9712e16552ff7bc5f
6
+ metadata.gz: a965a269d6b3f4562e55af72df38b0aaf1354fcdb27c068f9ca6c867997a130811c5386e919abb9410d3ed9895329f3a10551c5ebe01bb90845c3c9eb2cc9a73
7
+ data.tar.gz: dc717453f8f8f7f122eb6202c4825e543102dfd544d1f06a2c722d078e81aefa9a3949f120788f2f91bc469a98637c864a344d5acb348ecb87812509658ca4a9
@@ -1,5 +1,33 @@
1
1
  # News
2
2
 
3
+ ## 1.3.0: 2018-06-11
4
+
5
+ ### Improvements
6
+
7
+ * Added support for filter context.
8
+
9
+ * Added `xterm-256color` as a colorable terminal.
10
+
11
+ * `groonga-query-log-check-crash`:
12
+
13
+ * Added support for multiple process logs.
14
+
15
+ * Added more crash detection patterns.
16
+
17
+ * Added support for showing running queries on crash.
18
+
19
+ * Added support for showing important messages.
20
+
21
+ * `groonga-query-log-extract`:
22
+
23
+ * Added `--no-include-arguments` option.
24
+
25
+ * Improved pipe support.
26
+
27
+ * `groonga-query-log-replay`:
28
+
29
+ * Added `--read-timeout` option.
30
+
3
31
  ## 1.2.9: 2018-02-04
4
32
 
5
33
  ### Improvements
@@ -245,7 +245,7 @@ module GroongaQueryLog
245
245
  def guess_color_availability(output)
246
246
  return false unless output.tty?
247
247
  case ENV["TERM"]
248
- when /term(?:-color)?\z/, "screen"
248
+ when /term(?:-(?:256)?color)?\z/, "screen"
249
249
  true
250
250
  else
251
251
  return true if ENV["EMACS"] == "t"
@@ -70,31 +70,82 @@ module GroongaQueryLog
70
70
  checker.check
71
71
  end
72
72
 
73
+ class GroongaProcess
74
+ attr_reader :pid
75
+ attr_reader :start_time
76
+ attr_reader :log_path
77
+ attr_accessor :last_time
78
+ attr_accessor :n_leaks
79
+ attr_writer :crashed
80
+ attr_reader :important_entries
81
+ def initialize(pid, start_time, log_path)
82
+ @pid = pid
83
+ @start_time = start_time
84
+ @last_time = @start_time
85
+ @log_path = log_path
86
+ @n_leaks = 0
87
+ @crashed = false
88
+ @important_entries = []
89
+ end
90
+
91
+ def crashed?
92
+ @crashed
93
+ end
94
+ end
95
+
73
96
  class Checker
74
97
  def initialize(log_paths)
75
- @general_log_parser = GroongaLog::Parser.new
76
- @query_log_parser = Parser.new
77
98
  split_log_paths(log_paths)
78
-
79
- @running = nil
80
- @crash_sessions = []
81
- @session_start = nil
82
99
  end
83
100
 
84
101
  def check
85
- @general_log_parser.parse_paths(@general_log_paths) do |entry|
86
- check_general_log_entry(@general_log_parser.current_path,
87
- entry)
88
- end
89
- @crash_sessions.each do |start, last|
102
+ processes = ProcessEnumerator.new(@general_log_paths)
103
+ processes.each do |process|
104
+ if process.crashed?
105
+ p [:crashed,
106
+ process.start_time.iso8601,
107
+ process.last_time.iso8601,
108
+ process.pid,
109
+ process.log_path]
110
+ end
111
+
112
+ unless process.important_entries.empty?
113
+ puts("Important entries:")
114
+ process.important_entries.each_with_index do |entry, i|
115
+ puts("#{entry.timestamp.iso8601}: " +
116
+ "#{entry.log_level}: " +
117
+ "#{entry.message}")
118
+ end
119
+ end
120
+
121
+ unless process.n_leaks.zero?
122
+ p [:leak,
123
+ process.n_leaks,
124
+ process.last_time.iso8601,
125
+ process.log_path]
126
+ end
127
+
128
+ next unless process.crashed?
129
+
130
+ start = process.start_time
131
+ last = process.last_time
90
132
  @flushed = nil
91
133
  @unflushed_statistics = []
92
- @query_log_parser.parse_paths(@query_log_paths) do |statistic|
134
+ query_log_parser = Parser.new
135
+ query_log_parser.parse_paths(@query_log_paths) do |statistic|
93
136
  next if statistic.start_time < start
94
137
  break if statistic.start_time > last
95
- check_query_log_statistic(@query_log_parser.current_path,
138
+ check_query_log_statistic(query_log_parser.current_path,
96
139
  statistic)
97
140
  end
141
+ parsing_statistics = query_log_parser.parsing_statistics
142
+ unless parsing_statistics.empty?
143
+ puts("Running queries:")
144
+ parsing_statistics.each do |statistic|
145
+ puts("#{statistic.start_time.iso8601}:")
146
+ puts(statistic.command.to_command_format(pretty_print: true))
147
+ end
148
+ end
98
149
  unless @unflushed_statistics.empty?
99
150
  puts("Unflushed statistics in #{start.iso8601}/#{last.iso8601}")
100
151
  @unflushed_statistics.each do |statistic|
@@ -120,29 +171,6 @@ module GroongaQueryLog
120
171
  end
121
172
  end
122
173
 
123
- def check_general_log_entry(path, entry)
124
- # p [path, entry]
125
- case entry.log_level
126
- when :emergency, :alert, :critical, :error, :warning
127
- # p [entry.log_level, entry.message, entry.timestamp.iso8601]
128
- end
129
-
130
- case entry.message
131
- when /\Agrn_init:/
132
- if @running
133
- @crash_sessions << [@session_start, entry.timestamp]
134
- p [:crashed, entry.timestamp.iso8601, path]
135
- end
136
- @running = true
137
- @session_start = entry.timestamp
138
- when /\Agrn_fin \(\d+\)\z/
139
- n_leaks = $1.to_i
140
- @running = false
141
- @session_start = nil
142
- p [:leak, n_leask, entry.timestamp.iso8601] unless n_leaks.zero?
143
- end
144
- end
145
-
146
174
  def check_query_log_statistic(path, statistic)
147
175
  case statistic.command.command_name
148
176
  when "load"
@@ -164,6 +192,70 @@ module GroongaQueryLog
164
192
  end
165
193
  end
166
194
  end
195
+
196
+ class ProcessEnumerator
197
+ def initialize(general_log_paths)
198
+ @general_log_paths = general_log_paths
199
+ @running_processes = {}
200
+ end
201
+
202
+ def each(&block)
203
+ general_log_parser = GroongaLog::Parser.new
204
+ general_log_parser.parse_paths(@general_log_paths) do |entry|
205
+ check_general_log_entry(general_log_parser.current_path,
206
+ entry,
207
+ &block)
208
+ end
209
+ @running_processes.each_value do |process|
210
+ yield(process)
211
+ end
212
+ end
213
+
214
+ private
215
+ def check_general_log_entry(path, entry, &block)
216
+ # p [path, entry]
217
+ case entry.log_level
218
+ when :emergency, :alert, :critical, :error, :warning
219
+ # p [entry.log_level, entry.message, entry.timestamp.iso8601]
220
+ end
221
+
222
+ case entry.message
223
+ when /\Agrn_init:/
224
+ process = @running_processes[entry.pid]
225
+ if process
226
+ process.crashed = true
227
+ yield(process)
228
+ @running_processes.delete(entry.pid)
229
+ end
230
+ process = GroongaProcess.new(entry.pid, entry.timestamp, path)
231
+ @running_processes[entry.pid] = process
232
+ when /\Agrn_fin \(\d+\)\z/
233
+ n_leaks = $1.to_i
234
+ process = @running_processes[entry.pid]
235
+ process.n_leaks = n_leaks
236
+ yield(process)
237
+ @running_processes.delete(entry.pid)
238
+ else
239
+ @running_processes[entry.pid] ||=
240
+ GroongaProcess.new(entry.pid, Time.at(0), path)
241
+ process = @running_processes[entry.pid]
242
+ case entry.log_level
243
+ when :emergency, :alert, :critical, :error
244
+ process.important_entries << entry
245
+ end
246
+ process.last_time = entry.timestamp
247
+ case entry.message
248
+ when "-- CRASHED!!! --"
249
+ process.crashed = true
250
+ when "----------------"
251
+ if process.crashed?
252
+ yield(process)
253
+ @running_processes.delete(entry.pid)
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
167
259
  end
168
260
  end
169
261
  end
@@ -64,7 +64,7 @@ module GroongaQueryLog
64
64
  else
65
65
  extract(log_paths, $stdout)
66
66
  end
67
- rescue Interrupt
67
+ rescue Interrupt, Errno::EPIPE
68
68
  rescue Error
69
69
  $stderr.puts($!.message)
70
70
  return false
@@ -79,6 +79,7 @@ module GroongaQueryLog
79
79
  @options.unify_format = nil
80
80
  @options.commands = []
81
81
  @options.exclude_commands = []
82
+ @options.include_arguments = true
82
83
  @options.output_path = nil
83
84
  @option_parser = OptionParser.new do |parser|
84
85
  parser.version = VERSION
@@ -121,6 +122,12 @@ module GroongaQueryLog
121
122
  end
122
123
  end
123
124
 
125
+ parser.on("--[no-]include-arguments",
126
+ "Whether include command arguments",
127
+ "[#{@options.include_arguments}]") do |include_arguments|
128
+ @options.include_arguments = include_arguments
129
+ end
130
+
124
131
  parser.on("--output=PATH",
125
132
  "Output to PATH.",
126
133
  "[standard output]") do |path|
@@ -139,6 +146,9 @@ module GroongaQueryLog
139
146
  def extract_command(statistic, output)
140
147
  command = statistic.command
141
148
  return unless target?(command)
149
+ unless @options.include_arguments
150
+ command.arguments.clear
151
+ end
142
152
  command_text = nil
143
153
  case @options.unify_format
144
154
  when "uri"
@@ -146,7 +156,7 @@ module GroongaQueryLog
146
156
  when "command"
147
157
  command_text = command.to_command_format
148
158
  else
149
- command_text = statistic.raw_command
159
+ command_text = command.to_s
150
160
  end
151
161
  output.puts(command_text)
152
162
  end
@@ -67,6 +67,12 @@ module GroongaQueryLog
67
67
  @options.protocol = protocol
68
68
  end
69
69
 
70
+ parser.on("--read-timeout=TIMEOUT", Integer,
71
+ "Read timeout",
72
+ "[#{@options.read_timeout}]") do |read_timeout|
73
+ @options.read_timeout = read_timeout
74
+ end
75
+
70
76
  parser.on("--n-clients=N", Integer,
71
77
  "The max number of concurrency",
72
78
  "[#{@options.n_clients}]") do |n_clients|
@@ -66,13 +66,13 @@ module GroongaQueryLog
66
66
  match_data = PATTERN.match(line)
67
67
  next if match_data.nil?
68
68
 
69
- year = match_data[:year].to_i
70
- month = match_data[:month].to_i
71
- day = match_data[:day].to_i
72
- hour = match_data[:hour].to_i
73
- minute = match_data[:minute].to_i
74
- second = match_data[:second].to_i
75
- microsecond = match_data[:microsecond].to_i
69
+ year = Integer(match_data[:year], 10)
70
+ month = Integer(match_data[:month], 10)
71
+ day = Integer(match_data[:day], 10)
72
+ hour = Integer(match_data[:hour], 10)
73
+ minute = Integer(match_data[:minute], 10)
74
+ second = Integer(match_data[:second], 10)
75
+ microsecond = Integer(match_data[:microsecond], 10)
76
76
  context_id = match_data[:context_id]
77
77
  type = match_data[:type]
78
78
  rest = match_data.post_match.strip
@@ -142,6 +142,7 @@ module GroongaQueryLog
142
142
  attr_accessor :host
143
143
  attr_accessor :port
144
144
  attr_accessor :protocol
145
+ attr_accessor :read_timeout
145
146
  attr_accessor :n_clients
146
147
  attr_writer :request_queue_size
147
148
  attr_writer :disable_cache
@@ -152,6 +153,7 @@ module GroongaQueryLog
152
153
  @host = "127.0.0.1"
153
154
  @port = 10041
154
155
  @protocol = :http
156
+ @read_timeout = Groonga::Client::Default::READ_TIMEOUT
155
157
  @n_clients = 8
156
158
  @request_queue_size = nil
157
159
  @disable_cache = false
@@ -164,6 +166,7 @@ module GroongaQueryLog
164
166
  Groonga::Client.open(:host => @host,
165
167
  :port => @port,
166
168
  :protocol => @protocol,
169
+ :read_timeout => @read_timeout,
167
170
  &block)
168
171
  end
169
172
 
@@ -92,7 +92,7 @@ module GroongaQueryLog
92
92
  :relative_elapsed => relative_elapsed,
93
93
  :relative_elapsed_in_seconds => relative_elapsed_in_seconds,
94
94
  :name => operation[:name],
95
- :context => operation_context(operation[:name],
95
+ :context => operation_context(operation,
96
96
  operation_context_context),
97
97
  :n_records => operation[:n_records],
98
98
  :extra => operation[:extra],
@@ -152,9 +152,13 @@ module GroongaQueryLog
152
152
  nano_seconds / 1000.0 / 1000.0 / 1000.0
153
153
  end
154
154
 
155
- def operation_context(label, context)
155
+ def operation_context(operation, context)
156
156
  return nil if @select_command.nil?
157
157
 
158
+ extra = operation[:extra]
159
+ return extra if extra
160
+
161
+ label = operation[:name]
158
162
  case label
159
163
  when "filter"
160
164
  if @select_command.query and context[:query_used].nil?
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012-2017 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2012-2018 Kouhei Sutou <kou@clear-code.com>
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -15,5 +15,5 @@
15
15
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
  module GroongaQueryLog
18
- VERSION = "1.2.9"
18
+ VERSION = "1.3.0"
19
19
  end
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env ruby
2
- #
3
1
  # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
4
2
  # Copyright (C) 2015-2018 Kouhei Sutou <kou@clear-code.com>
5
3
  #
@@ -37,12 +35,12 @@ class ExtractCommandTest < Test::Unit::TestCase
37
35
  def test_multi
38
36
  other_query_log_path = File.join(@fixtures_path, "other-query.log")
39
37
  actual_commands = run_extractor(@query_log_path, other_query_log_path)
40
- expected_commands = <<-EOC
41
- load --table Video
42
- select --table Users --query follower:@groonga --output_columns _key,name
43
- table_create --name Comments --flags TABLE_HASH_KEY --key_type UInt32
44
- column_create --table Comments --name title --flags COLUMN_SCALAR --type ShortText
45
- EOC
38
+ expected_commands = <<-COMMAND
39
+ load --table "Video"
40
+ select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
41
+ table_create --flags "TABLE_HASH_KEY" --key_type "UInt32" --name "Comments"
42
+ column_create --flags "COLUMN_SCALAR" --name "title" --table "Comments" --type "ShortText"
43
+ COMMAND
46
44
  assert_equal(expected_commands, actual_commands)
47
45
  end
48
46
 
@@ -57,44 +55,47 @@ EOC
57
55
  actual_commands = run_extractor(@query_log_path,
58
56
  "--unify-format", "command")
59
57
 
60
- expected_commands = <<-EOC
58
+ expected_commands = <<-COMMAND
61
59
  load --table "Video"
62
60
  select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
63
- EOC
61
+ COMMAND
64
62
  assert_equal(expected_commands, actual_commands)
65
63
  end
66
64
 
67
65
  def test_uri
68
66
  actual_commands = run_extractor(@query_log_path,
69
67
  "--unify-format", "uri")
70
- expected_commands = <<-EOC
68
+ expected_commands = <<-COMMAND
71
69
  /d/load?table=Video
72
70
  /d/select?output_columns=_key%2Cname&query=follower%3A%40groonga&table=Users
73
- EOC
71
+ COMMAND
74
72
  assert_equal(expected_commands, actual_commands)
75
73
  end
76
74
 
77
75
  def test_not_unify
78
76
  actual_commands = run_extractor(@query_log_path)
79
- expected_commands = <<-EOC
80
- load --table Video
81
- select --table Users --query follower:@groonga --output_columns _key,name
82
- EOC
77
+ expected_commands = <<-COMMAND
78
+ load --table "Video"
79
+ select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
80
+ COMMAND
83
81
  assert_equal(expected_commands, actual_commands)
84
82
  end
85
83
  end
86
84
 
87
85
  def test_command
88
86
  actual_command = run_extractor(@query_log_path, "--command", "load")
89
- expected_command = "load --table Video\n"
87
+ expected_command = <<-COMMAND
88
+ load --table "Video"
89
+ COMMAND
90
90
 
91
91
  assert_equal(expected_command, actual_command)
92
92
  end
93
93
 
94
94
  def test_exclude_command
95
95
  actual_command = run_extractor(@query_log_path, "--exclude-command", "load")
96
- expected_command = "select --table Users --query follower:@groonga" +
97
- " --output_columns _key,name\n"
96
+ expected_command = <<-COMMAND
97
+ select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
98
+ COMMAND
98
99
 
99
100
  assert_equal(expected_command, actual_command)
100
101
  end
@@ -116,20 +117,21 @@ EOC
116
117
  class TestExtract < self
117
118
  def setup
118
119
  super
119
- @log = <<-EOL
120
+ @log = <<-LOG
120
121
  2012-12-12 17:39:17.628846|0x7fff786aa2b0|>select --table Users --query follower:@groonga --output_columns _key,name
121
122
  2012-12-12 17:39:17.629676|0x7fff786aa2b0|:000000000842953 filter(2)
122
123
  2012-12-12 17:39:17.629709|0x7fff786aa2b0|:000000000870900 select(2)
123
124
  2012-12-12 17:39:17.629901|0x7fff786aa2b0|:000000001066752 output(2)
124
125
  2012-12-12 17:39:17.630052|0x7fff786aa2b0|<000000001217140 rc=0
125
- EOL
126
+ LOG
126
127
  end
127
128
 
128
129
  def test_command_format
129
130
  @extract_command.options.unify_format = "command"
130
- expected_formatted_command = "select --output_columns \"_key,name\""+
131
- " --query \"follower:@groonga\"" +
132
- " --table \"Users\"\n"
131
+ expected_formatted_command = <<-COMMAND
132
+ select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
133
+ COMMAND
134
+
133
135
  assert_equal(expected_formatted_command, extract)
134
136
  end
135
137
 
@@ -143,9 +145,10 @@ EOL
143
145
 
144
146
  def test_not_unify
145
147
  @extract_command.options.unify_format = nil
146
- expected_formatted_command = "select --table Users" +
147
- " --query follower:@groonga" +
148
- " --output_columns _key,name\n"
148
+ expected_formatted_command = <<-COMMAND
149
+ select --output_columns "_key,name" --query "follower:@groonga" --table "Users"
150
+ COMMAND
151
+
149
152
  assert_equal(expected_formatted_command, extract)
150
153
  end
151
154