groonga-query-log 1.3.3 → 1.3.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b787d986aa85a124beec78ff3b1da09915dacfb9012c1619120d6a1ff3526603
4
- data.tar.gz: 13f736d7fd43e6fa1f87ab5de39600ed71b17baf4a53bfa21e9f4ecca74753a6
3
+ metadata.gz: e09cac93999ccbd46a1521afa9ccae705d47795575d275d086a1cc15e16ed8f1
4
+ data.tar.gz: e39350cad4042ef656afc00e133db5913664e50ff9102ac7e11afb26a1fc7143
5
5
  SHA512:
6
- metadata.gz: 8e5fdcda766d04c1b57b391f0ebec4d86f986e441869aa884c6378494198dc60bdc731ef04d07199b5d0be9e41ec48b07b61b78c2657b2eac3d10ca8cecbfd5a
7
- data.tar.gz: cd6c5e20f7d73f8ef02ccc75b384178dbd3614179f797a19bad266ed16c8c7a6f0c792a46d899371d1bca7b382751d5b571e0af22d3244444d43be49b44ca986
6
+ metadata.gz: d06425f98da9e4d9402211298bf9b7e9baceb1735b37fb37fc0e634f8a71dae7c31bbd576682177650d72affaee9e0dbac953e0e0de26a000a121b4d15791684
7
+ data.tar.gz: 4a88d239858bd5e61ef0261c566039207cb95f36e2fad05ef0f847a967935765ee54128afe326c6a0e2989d071f2feb5f267f99e5136e4d15cee6b70dcab02f4
data/doc/text/news.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # News
2
2
 
3
+ ## 1.3.4: 2018-08-22
4
+
5
+ ### Improvements
6
+
7
+ * `groonga-query-log-check-crash`:
8
+
9
+ * Added support for logs generated by Mroonga.
10
+
11
+ * Added support for reporting unfinished processes.
12
+
13
+ * Added support for reporting successfully finished processes.
14
+
15
+ * Added support for reporting path that includes the last entry.
16
+
17
+ * `groonga-query-log-extract`:
18
+
19
+ * Added `--inspect-query` option.
20
+
21
+ * `groonga-query-log-analyze`:
22
+
23
+ * Added support conditions report for `range_filter`,
24
+ `logical_select` and `logical_range_filter`.
25
+
26
+ ### Fixes
27
+
28
+ * `groonga-query-log-check-crash`:
29
+
30
+ * Fixed memory leak detection logic.
31
+
3
32
  ## 1.3.3: 2018-07-05
4
33
 
5
34
  ### Improvements
@@ -143,7 +143,7 @@ module GroongaQueryLog
143
143
  return unless @collect_slow_statistics
144
144
  if statistic.slow?
145
145
  @n_slow_responses += 1
146
- if statistic.select_command?
146
+ if statistic.select_family_command?
147
147
  statistic.each_operation do |operation|
148
148
  next unless operation[:slow?]
149
149
  @n_slow_operations += 1
@@ -73,24 +73,39 @@ module GroongaQueryLog
73
73
  class GroongaProcess
74
74
  attr_reader :pid
75
75
  attr_reader :start_time
76
- attr_reader :log_path
76
+ attr_reader :start_log_path
77
77
  attr_accessor :last_time
78
+ attr_accessor :last_log_path
78
79
  attr_accessor :n_leaks
79
80
  attr_writer :crashed
81
+ attr_writer :finished
80
82
  attr_reader :important_entries
81
- def initialize(pid, start_time, log_path)
83
+ def initialize(pid, start_time, start_log_path)
82
84
  @pid = pid
83
85
  @start_time = start_time
84
86
  @last_time = @start_time
85
- @log_path = log_path
87
+ @start_log_path = start_log_path
88
+ @last_log_path = @start_log_path
86
89
  @n_leaks = 0
87
90
  @crashed = false
91
+ @finished = false
88
92
  @important_entries = []
89
93
  end
90
94
 
91
95
  def crashed?
92
96
  @crashed
93
97
  end
98
+
99
+ def finished?
100
+ @finished
101
+ end
102
+
103
+ def successfully_finished?
104
+ return false if crashed?
105
+ return false unless finished?
106
+
107
+ true
108
+ end
94
109
  end
95
110
 
96
111
  class Checker
@@ -101,12 +116,38 @@ module GroongaQueryLog
101
116
  def check
102
117
  processes = ProcessEnumerator.new(@general_log_paths)
103
118
  processes.each do |process|
104
- if process.crashed?
105
- p [:crashed,
119
+ need_query_log_parsing = true
120
+ if process.successfully_finished?
121
+ need_query_log_parsing = false
122
+ p [:process,
123
+ :success,
106
124
  process.start_time.iso8601,
107
125
  process.last_time.iso8601,
108
126
  process.pid,
109
- process.log_path]
127
+ process.start_log_path,
128
+ process.last_log_path]
129
+ elsif process.crashed?
130
+ p [:process,
131
+ :crashed,
132
+ process.start_time.iso8601,
133
+ process.last_time.iso8601,
134
+ process.pid,
135
+ process.start_log_path,
136
+ process.last_log_path]
137
+ else
138
+ p [:process,
139
+ :unfinished,
140
+ process.start_time.iso8601,
141
+ process.pid,
142
+ process.start_log_path]
143
+ end
144
+
145
+ unless process.n_leaks.zero?
146
+ p [:leak,
147
+ process.n_leaks,
148
+ process.last_time.iso8601,
149
+ process.pid,
150
+ process.last_log_path]
110
151
  end
111
152
 
112
153
  unless process.important_entries.empty?
@@ -118,14 +159,7 @@ module GroongaQueryLog
118
159
  end
119
160
  end
120
161
 
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?
162
+ next unless need_query_log_parsing
129
163
 
130
164
  start = process.start_time
131
165
  last = process.last_time
@@ -139,9 +173,12 @@ module GroongaQueryLog
139
173
  statistic)
140
174
  end
141
175
  parsing_statistics = query_log_parser.parsing_statistics
142
- unless parsing_statistics.empty?
176
+ target_parsing_statistics = parsing_statistics.reject do |statistic|
177
+ statistic.start_time < start
178
+ end
179
+ unless target_parsing_statistics.empty?
143
180
  puts("Running queries:")
144
- parsing_statistics.each do |statistic|
181
+ target_parsing_statistics.each do |statistic|
145
182
  puts("#{statistic.start_time.iso8601}:")
146
183
  puts(statistic.command.to_command_format(pretty_print: true))
147
184
  end
@@ -226,19 +263,23 @@ module GroongaQueryLog
226
263
  end
227
264
 
228
265
  case entry.message
229
- when /\Agrn_init:/
266
+ when /\Agrn_init:/, /\Amroonga \d+\.\d+ started\.\z/
230
267
  process = @running_processes[entry.pid]
231
268
  if process
269
+ process.finished = true
232
270
  process.crashed = true
233
271
  yield(process)
234
272
  @running_processes.delete(entry.pid)
235
273
  end
236
274
  process = GroongaProcess.new(entry.pid, entry.timestamp, path)
237
275
  @running_processes[entry.pid] = process
238
- when /\Agrn_fin \(\d+\)\z/
276
+ when /\Agrn_fin \((\d+)\)\z/
239
277
  n_leaks = $1.to_i
240
278
  process = @running_processes[entry.pid]
241
279
  process.n_leaks = n_leaks
280
+ process.last_time = entry.timestamp
281
+ process.last_log_path = path
282
+ process.finished = true
242
283
  yield(process)
243
284
  @running_processes.delete(entry.pid)
244
285
  else
@@ -250,9 +291,11 @@ module GroongaQueryLog
250
291
  process.important_entries << entry
251
292
  end
252
293
  process.last_time = entry.timestamp
294
+ process.last_log_path = path
253
295
  case entry.message
254
296
  when "-- CRASHED!!! --"
255
297
  process.crashed = true
298
+ process.finished = true
256
299
  when "----------------"
257
300
  if process.crashed?
258
301
  yield(process)
@@ -14,168 +14,239 @@
14
14
  # License along with this library; if not, write to the Free Software
15
15
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
16
 
17
- require "ostruct"
17
+ require "json"
18
18
  require "optparse"
19
+ require "ostruct"
19
20
  require "pathname"
20
21
 
21
22
  require "groonga-query-log"
22
23
  require "groonga-query-log/command-line"
23
24
 
24
25
  module GroongaQueryLog
25
- module Command
26
- class Extract < CommandLine
27
- attr_accessor :options
28
- attr_reader :option_parser
29
-
30
- def initialize
31
- @options = nil
32
- @option_parser = nil
33
- setup_options
34
- end
35
-
36
- # Executes extractor for Groonga's query logs.
37
- # "groonga-query-log-extract" command runs this method.
38
- #
39
- # @example
40
- # extractor = GroongaQueryLog::Command::Extract.new
41
- # extractor.run("--output", "commands.output",
42
- # "--command", "select",
43
- # "query.log")
44
- #
45
- # If only paths of query log files are specified,
46
- # this method prints command(s) of them to console.
47
- #
48
- # @param [Array<String>] arguments arguments for
49
- # groonga-query-log-extract. Please execute
50
- # "groonga-query-log-extract --help" or see #setup_options.
51
- def run(arguments)
52
- begin
53
- log_paths = @option_parser.parse!(arguments)
54
- rescue OptionParser::ParseError
55
- $stderr.puts($!.message)
56
- return false
57
- end
26
+ module Command
27
+ class Extract < CommandLine
28
+ attr_accessor :options
29
+ attr_reader :option_parser
30
+
31
+ def initialize
32
+ @options = nil
33
+ @option_parser = nil
34
+ setup_options
35
+ end
36
+
37
+ # Executes extractor for Groonga's query logs.
38
+ # "groonga-query-log-extract" command runs this method.
39
+ #
40
+ # @example
41
+ # extractor = GroongaQueryLog::Command::Extract.new
42
+ # extractor.run("--output", "commands.output",
43
+ # "--command", "select",
44
+ # "query.log")
45
+ #
46
+ # If only paths of query log files are specified,
47
+ # this method prints command(s) of them to console.
48
+ #
49
+ # @param [Array<String>] arguments arguments for
50
+ # groonga-query-log-extract. Please execute
51
+ # "groonga-query-log-extract --help" or see #setup_options.
52
+ def run(arguments)
53
+ begin
54
+ log_paths = @option_parser.parse!(arguments)
55
+ rescue OptionParser::ParseError
56
+ $stderr.puts($!.message)
57
+ return false
58
+ end
58
59
 
59
- begin
60
- if @options.output_path
61
- File.open(@options.output_path, "w") do |output|
62
- extract(log_paths, output)
63
- end
64
- else
65
- extract(log_paths, $stdout)
60
+ begin
61
+ if @options.output
62
+ File.open(@options.output, "w") do |output|
63
+ extract(log_paths, output)
66
64
  end
67
- rescue Interrupt, Errno::EPIPE
68
- rescue Error
69
- $stderr.puts($!.message)
70
- return false
65
+ else
66
+ extract(log_paths, $stdout)
71
67
  end
68
+ rescue Interrupt, Errno::EPIPE
69
+ rescue Error
70
+ $stderr.puts($!.message)
71
+ return false
72
+ end
72
73
 
73
- true
74
- end
75
-
76
- private
77
- def setup_options
78
- @options = OpenStruct.new
79
- @options.unify_format = nil
80
- @options.commands = []
81
- @options.exclude_commands = []
82
- @options.include_arguments = true
83
- @options.output_path = nil
84
- @option_parser = OptionParser.new do |parser|
85
- parser.version = VERSION
86
- parser.banner += " QUERY_LOG1 ..."
87
-
88
- available_formats = ["uri", "command"]
89
- parser.on("--unify-format=FORMAT",
90
- available_formats,
91
- "Unify command format to FORMAT.",
92
- "(#{available_formats.join(', ')})",
93
- "[not unify]") do |format|
94
- @options.unify_format = format
95
- end
74
+ true
75
+ end
96
76
 
97
- parser.on("--command=COMMAND",
98
- "Extract only COMMAND.",
99
- "To extract one or more commands,",
100
- "specify this command a number of times.",
101
- "Use /.../ as COMMAND to match command with regular expression.",
102
- "[all commands]") do |command|
103
- case command
104
- when /\A\/(.*)\/(i)?\z/
105
- @options.commands << Regexp.new($1, $2 == "i")
106
- when
107
- @options.commands << command
108
- end
109
- end
77
+ private
78
+ def setup_options
79
+ @options = OpenStruct.new
80
+ @options.unify_format = nil
81
+ @options.commands = []
82
+ @options.exclude_commands = []
83
+ @options.include_arguments = true
84
+ @options.output = nil
85
+ @options.inspect_query = false
86
+ @option_parser = OptionParser.new do |parser|
87
+ parser.version = VERSION
88
+ parser.banner += " QUERY_LOG1 ..."
89
+
90
+ available_formats = ["uri", "command"]
91
+ parser.on("--unify-format=FORMAT",
92
+ available_formats,
93
+ "Unify command format to FORMAT.",
94
+ "(#{available_formats.join(', ')})",
95
+ "[not unify]") do |format|
96
+ @options.unify_format = format
97
+ end
110
98
 
111
- parser.on("--exclude-command=COMMAND",
112
- "Don't extract COMMAND.",
113
- "To ignore one or more commands,",
114
- "specify this command a number of times.",
115
- "Use /.../ as COMMAND to match command with regular expression.",
116
- "[no commands]") do |command|
117
- case command
118
- when /\A\/(.*)\/(i)?\z/
119
- @options.exclude_commands << Regexp.new($1, $2 == "i")
120
- when
121
- @options.exclude_commands << command
122
- end
99
+ parser.on("--command=COMMAND",
100
+ "Extract only COMMAND.",
101
+ "To extract one or more commands,",
102
+ "specify this command a number of times.",
103
+ "Use /.../ as COMMAND to match command with regular expression.",
104
+ "[all commands]") do |command|
105
+ case command
106
+ when /\A\/(.*)\/(i)?\z/
107
+ @options.commands << Regexp.new($1, $2 == "i")
108
+ when
109
+ @options.commands << command
123
110
  end
111
+ end
124
112
 
125
- parser.on("--[no-]include-arguments",
126
- "Whether include command arguments",
127
- "[#{@options.include_arguments}]") do |include_arguments|
128
- @options.include_arguments = include_arguments
113
+ parser.on("--exclude-command=COMMAND",
114
+ "Don't extract COMMAND.",
115
+ "To ignore one or more commands,",
116
+ "specify this command a number of times.",
117
+ "Use /.../ as COMMAND to match command with regular expression.",
118
+ "[no commands]") do |command|
119
+ case command
120
+ when /\A\/(.*)\/(i)?\z/
121
+ @options.exclude_commands << Regexp.new($1, $2 == "i")
122
+ when
123
+ @options.exclude_commands << command
129
124
  end
125
+ end
130
126
 
131
- parser.on("--output=PATH",
132
- "Output to PATH.",
133
- "[standard output]") do |path|
134
- @options.output_path = path
135
- end
127
+ parser.on("--[no-]include-arguments",
128
+ "Whether include command arguments",
129
+ "[#{@options.include_arguments}]") do |include_arguments|
130
+ @options.include_arguments = include_arguments
136
131
  end
137
- end
138
132
 
139
- def extract(log_paths, output)
140
- parser = Parser.new
141
- parse_log(parser, log_paths) do |statistic|
142
- extract_command(statistic, output)
133
+ parser.on("--output=OUTPUT",
134
+ "If you specify path as OUTPUT,",
135
+ "executed commands are printed to the path.",
136
+ "If you specify a URL like",
137
+ "http://localhost:10041/?table=QueryLogEntries,",
138
+ "each entry are stored to QueryLogEntries Groonga table",
139
+ "running at localhost on port 10041.",
140
+ "[standard output]") do |output|
141
+ @options.output = output
143
142
  end
144
- end
145
143
 
146
- def extract_command(statistic, output)
147
- command = statistic.command
148
- return unless target?(command)
149
- unless @options.include_arguments
150
- command.arguments.clear
144
+ parser.on("--[no-]inspect-query",
145
+ "Inspect query.",
146
+ "[#{@options.inspect_query}]") do |boolean|
147
+ @options.inspect_query = boolean
151
148
  end
152
- command_text = nil
153
- case @options.unify_format
154
- when "uri"
155
- command_text = command.to_uri_format
156
- when "command"
157
- command_text = command.to_command_format
149
+ end
150
+ end
151
+
152
+ def extract(log_paths, output)
153
+ if @options.inspect_query
154
+ formatter = InspectFormatter.new(output)
155
+ else
156
+ formatter = DumpFormatter.new(output)
157
+ end
158
+ formatter.start
159
+ parser = Parser.new
160
+ parse_log(parser, log_paths) do |statistic|
161
+ extract_command(statistic, formatter)
162
+ end
163
+ formatter.finish
164
+ end
165
+
166
+ def extract_command(statistic, formatter)
167
+ command = statistic.command
168
+ return unless target?(command)
169
+ unless @options.include_arguments
170
+ command.arguments.clear
171
+ end
172
+ command_text = nil
173
+ case @options.unify_format
174
+ when "uri"
175
+ command_text = command.to_uri_format
176
+ when "command"
177
+ command_text = command.to_command_format
178
+ else
179
+ command_text = command.to_s
180
+ end
181
+ formatter.command(statistic, command_text)
182
+ end
183
+
184
+ def target?(command)
185
+ name = command.command_name
186
+ target_commands = @options.commands
187
+ exclude_commands = @options.exclude_commands
188
+
189
+ unless target_commands.empty?
190
+ return target_commands.any? {|target_command| target_command === name}
191
+ end
192
+
193
+ unless exclude_commands.empty?
194
+ return (not exclude_commands.any? {|exclude_command| exclude_command === name})
195
+ end
196
+
197
+ true
198
+ end
199
+
200
+ class InspectFormatter
201
+ def initialize(output)
202
+ @output = output
203
+ @first_comand = false
204
+ end
205
+
206
+ def start
207
+ @output.puts("[")
208
+ end
209
+
210
+ def command(statistic, command_text)
211
+ if @first_command
212
+ @first_command = false
158
213
  else
159
- command_text = command.to_s
214
+ @output.puts(",")
160
215
  end
161
- output.puts(command_text)
216
+ record = {
217
+ "start_time" => statistic.start_time,
218
+ "elapsed_time" => statistic.elapsed_in_seconds,
219
+ "last_time" => statistic.last_time,
220
+ "return_code" => statistic.return_code,
221
+ "command" => command_text,
222
+ }
223
+ statistic.command.arguments.each do |name, value|
224
+ record["argument_#{name}"] = value
225
+ end
226
+ @output.print(record.to_json)
227
+ end
228
+
229
+ def finish
230
+ @output.puts("") unless @first_comand
231
+ @output.puts("]")
162
232
  end
233
+ end
163
234
 
164
- def target?(command)
165
- name = command.command_name
166
- target_commands = @options.commands
167
- exclude_commands = @options.exclude_commands
235
+ class DumpFormatter
236
+ def initialize(output)
237
+ @output = output
238
+ end
168
239
 
169
- unless target_commands.empty?
170
- return target_commands.any? {|target_command| target_command === name}
171
- end
240
+ def start
241
+ end
172
242
 
173
- unless exclude_commands.empty?
174
- return (not exclude_commands.any? {|exclude_command| exclude_command === name})
175
- end
243
+ def command(statistic, command_text)
244
+ @output.puts(command_text)
245
+ end
176
246
 
177
- true
247
+ def finish
178
248
  end
179
249
  end
180
250
  end
251
+ end
181
252
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2011-2017 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2011-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
@@ -27,8 +27,6 @@ module GroongaQueryLog
27
27
  def initialize(context_id)
28
28
  @context_id = context_id
29
29
  @start_time = nil
30
- @command = nil
31
- @select_command = nil
32
30
  @raw_command = nil
33
31
  @operations = []
34
32
  @elapsed = nil
@@ -48,16 +46,7 @@ module GroongaQueryLog
48
46
  end
49
47
 
50
48
  def command
51
- Groonga::Command::Parser.parse(@raw_command) do |status, command|
52
- case status
53
- when :on_load_start
54
- @loading = false
55
- @command ||= command
56
- when :on_command
57
- @command ||= command
58
- end
59
- end
60
- @command
49
+ @command ||= parse_command
61
50
  end
62
51
 
63
52
  def elapsed_in_seconds
@@ -76,7 +65,6 @@ module GroongaQueryLog
76
65
  return to_enum(__method__) unless block_given?
77
66
 
78
67
  previous_elapsed = 0
79
- ensure_parse_command
80
68
  operation_context_context = {
81
69
  :filter_index => 0,
82
70
  :drilldown_index => 0,
@@ -114,8 +102,15 @@ module GroongaQueryLog
114
102
  _operations
115
103
  end
116
104
 
117
- def select_command?
118
- command.name == "select"
105
+ def select_family_command?
106
+ case command.command_name
107
+ when "select", "range_filter"
108
+ true
109
+ when "logical_select", "logical_range_filter"
110
+ true
111
+ else
112
+ false
113
+ end
119
114
  end
120
115
 
121
116
  def to_hash
@@ -148,12 +143,20 @@ module GroongaQueryLog
148
143
  end
149
144
 
150
145
  private
146
+ def parse_command
147
+ command = nil
148
+ Groonga::Command::Parser.parse(@raw_command) do |_status, _command|
149
+ command = _command
150
+ end
151
+ command
152
+ end
153
+
151
154
  def nano_seconds_to_seconds(nano_seconds)
152
155
  nano_seconds / 1000.0 / 1000.0 / 1000.0
153
156
  end
154
157
 
155
158
  def operation_context(operation, context)
156
- return nil if @select_command.nil?
159
+ return nil unless select_family_command?
157
160
 
158
161
  extra = operation[:extra]
159
162
  return extra if extra
@@ -161,34 +164,29 @@ module GroongaQueryLog
161
164
  label = operation[:name]
162
165
  case label
163
166
  when "filter"
164
- if @select_command.query and context[:query_used].nil?
167
+ if command.query and context[:query_used].nil?
165
168
  context[:query_used] = true
166
- "query: #{@select_command.query}"
169
+ "query: #{command.query}"
167
170
  else
168
171
  index = context[:filter_index]
169
172
  context[:filter_index] += 1
170
- @select_command.conditions[index]
173
+ command.conditions[index]
171
174
  end
172
175
  when "sort"
173
- @select_command.sortby
176
+ command.sortby
174
177
  when "score"
175
- @select_command.scorer
178
+ command.scorer
176
179
  when "output"
177
- @select_command.output_columns
180
+ command.output_columns
178
181
  when "drilldown"
179
182
  index = context[:drilldown_index]
180
183
  context[:drilldown_index] += 1
181
- @select_command.drilldowns[index]
184
+ command.drilldowns[index]
182
185
  else
183
186
  nil
184
187
  end
185
188
  end
186
189
 
187
- def ensure_parse_command
188
- return unless select_command?
189
- @select_command = Groonga::Command::Parser.parse(@raw_command)
190
- end
191
-
192
190
  def slow_operation?(elapsed)
193
191
  elapsed >= @slow_operation_threshold
194
192
  end
@@ -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.3.3"
18
+ VERSION = "1.3.4"
19
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groonga-query-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kouhei Sutou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-06 00:00:00.000000000 Z
11
+ date: 2018-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: groonga-command-parser