groonga-query-log 1.7.8 → 1.7.9
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 +4 -4
- data/README.md +7 -4
- data/doc/text/check-crash.md +152 -0
- data/doc/text/news.md +22 -0
- data/groonga-query-log.gemspec +4 -2
- data/lib/groonga-query-log/command/check-crash.rb +233 -74
- data/lib/groonga-query-log/command/show-running-queries.rb +1 -1
- data/lib/groonga-query-log/version.rb +1 -1
- data/test/command/test-check-crash.rb +584 -0
- data/test/command/test-format-regression-test-logs.rb +4 -4
- data/test/fixtures/check-crash/process/crash.log +29 -0
- data/test/fixtures/check-crash/process/leak.log +27 -0
- data/test/fixtures/check-crash/process/normal.log +27 -0
- data/test/fixtures/check-crash/query/column_create/flushed/only-opened.log +8 -0
- data/test/fixtures/check-crash/query/column_create/flushed/recursive-yes.log +8 -0
- data/test/fixtures/check-crash/query/column_create/flushed/target-name-recursive-dependent.log +8 -0
- data/test/fixtures/check-crash/query/column_create/unfinished.log +2 -0
- data/test/fixtures/check-crash/query/column_create/unflushed/no-flush.log +3 -0
- data/test/fixtures/check-crash/query/column_create/unflushed/only-opened.log +7 -0
- data/test/fixtures/check-crash/query/column_create/unflushed/recursive-no.log +11 -0
- data/test/fixtures/check-crash/query/column_create/unflushed/target-name-recursive-no.log +7 -0
- data/test/fixtures/check-crash/query/column_create/unflushed/target-name-recursive-yes.log +7 -0
- data/test/fixtures/check-crash/query/delete/flushed/only-opened.log +9 -0
- data/test/fixtures/check-crash/query/delete/flushed/recursive-yes.log +8 -0
- data/test/fixtures/check-crash/query/delete/flushed/target-name-recursive-dependent.log +8 -0
- data/test/fixtures/check-crash/query/delete/unfinished.log +3 -0
- data/test/fixtures/check-crash/query/delete/unflushed/no-flush.log +4 -0
- data/test/fixtures/check-crash/query/delete/unflushed/only-opened.log +8 -0
- data/test/fixtures/check-crash/query/delete/unflushed/recursive-no.log +12 -0
- data/test/fixtures/check-crash/query/delete/unflushed/target-name-recursive-no.log +8 -0
- data/test/fixtures/check-crash/query/delete/unflushed/target-name-recursive-yes.log +8 -0
- data/test/fixtures/check-crash/query/load/flushed/columns-only-opened.log +9 -0
- data/test/fixtures/check-crash/query/load/flushed/columns-target-name-recursive-dependent.log +9 -0
- data/test/fixtures/check-crash/query/load/flushed/only-opened.log +9 -0
- data/test/fixtures/check-crash/query/load/flushed/recursive-yes.log +8 -0
- data/test/fixtures/check-crash/query/load/flushed/target-name-recursive-dependent.log +8 -0
- data/test/fixtures/check-crash/query/load/unfinished.log +3 -0
- data/test/fixtures/check-crash/query/load/unflushed/columns-only-opened.log +8 -0
- data/test/fixtures/check-crash/query/load/unflushed/columns-target-name-recursive-dependent.log +8 -0
- data/test/fixtures/check-crash/query/load/unflushed/no-flush.log +4 -0
- data/test/fixtures/check-crash/query/load/unflushed/only-opened.log +8 -0
- data/test/fixtures/check-crash/query/load/unflushed/recursive-no.log +12 -0
- data/test/fixtures/check-crash/query/load/unflushed/target-name-recursive-no.log +8 -0
- data/test/fixtures/check-crash/query/load/unflushed/target-name-recursive-yes.log +8 -0
- data/test/fixtures/check-crash/query/select/flushed/only-opened.log +12 -0
- data/test/fixtures/check-crash/query/select/flushed/recursive-yes.log +11 -0
- data/test/fixtures/check-crash/query/select/flushed/target-name-recursive-dependent.log +11 -0
- data/test/fixtures/check-crash/query/select/unfinished.log +5 -0
- data/test/fixtures/check-crash/query/select/unflushed/no-flush.log +6 -0
- data/test/fixtures/check-crash/query/select/unflushed/no-load.log +5 -0
- data/test/fixtures/check-crash/query/select/unflushed/only-opened.log +10 -0
- data/test/fixtures/check-crash/query/select/unflushed/recursive-no.log +14 -0
- data/test/fixtures/check-crash/query/select/unflushed/target-name-recursive-no.log +10 -0
- data/test/fixtures/check-crash/query/select/unflushed/target-name-recursive-yes.log +10 -0
- data/test/fixtures/check-crash/query/table_create/flushed/only-opened.log +8 -0
- data/test/fixtures/check-crash/query/table_create/flushed/recursive-yes.log +7 -0
- data/test/fixtures/check-crash/query/table_create/flushed/target-name-recursive-dependent.log +7 -0
- data/test/fixtures/check-crash/query/table_create/unflushed/no-flush.log +4 -0
- data/test/fixtures/check-crash/query/table_create/unflushed/only-opened.log +7 -0
- data/test/fixtures/check-crash/query/table_create/unflushed/recursive-no.log +11 -0
- data/test/fixtures/check-crash/query/table_create/unflushed/target-name-recursive-no.log +7 -0
- data/test/fixtures/check-crash/query/table_create/unflushed/target-name-recursive-yes.log +7 -0
- data/test/fixtures/check-crash/query/truncate/flushed/only-opened.log +8 -0
- data/test/fixtures/check-crash/query/truncate/flushed/recursive-yes.log +7 -0
- data/test/fixtures/check-crash/query/truncate/flushed/target-name-recursive-dependent.log +7 -0
- data/test/fixtures/check-crash/query/truncate/unflushed/no-flush.log +3 -0
- data/test/fixtures/check-crash/query/truncate/unflushed/only-opened.log +7 -0
- data/test/fixtures/check-crash/query/truncate/unflushed/recursive-no.log +11 -0
- data/test/fixtures/check-crash/query/truncate/unflushed/target-name-recursive-no.log +7 -0
- data/test/fixtures/check-crash/query/truncate/unflushed/target-name-recursive-yes.log +7 -0
- data/test/fixtures/reporter/json-stream.expected +1 -1
- data/test/fixtures/reporter/json.expected +1 -1
- data/test/helper.rb +1 -2
- metadata +160 -11
- data/test/fixtures/run-regression-test/results/query.log.log +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d37a2e35f6eb1b0002f81d5d3e5e3f1cbb3115816da95d0d2fba95e40d4602ac
|
|
4
|
+
data.tar.gz: f790ad37a5cb6748181588534a8ce6fc06979921e0c5eb68e016c56b2df8f906
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 61c8927fe0bc65eeeb763694af65e2988047264dd1f05a3daf6b2c7fa702f7793e1a9466e5c7764a9f2f48f804a5927093fd62e09414f7ed88184bcee659dbf7
|
|
7
|
+
data.tar.gz: a7aee9d119a6e1569320bf3e4b2abf2b78e8eccb69c694fcc3850ac37fb3848d8fc01e62c2bbd8e845bb2435f13e7e10c2104f1b01bc2275095ee9f9a8ae134d
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# README
|
|
2
2
|
|
|
3
|
-
[](https://github.com/groonga/groonga-query-log/actions/workflows/test.yml)
|
|
4
4
|
|
|
5
5
|
## Name
|
|
6
6
|
|
|
@@ -24,6 +24,10 @@ by using groonga-query-log as a tool.
|
|
|
24
24
|
|
|
25
25
|
TODO...
|
|
26
26
|
|
|
27
|
+
### groonga-query-log-check-crash
|
|
28
|
+
|
|
29
|
+
* [doc/text/check-crash.md](doc/text/check-crash.md)
|
|
30
|
+
|
|
27
31
|
### groonga-query-log-detect-memory-leak
|
|
28
32
|
|
|
29
33
|
TODO...
|
|
@@ -54,10 +58,9 @@ TODO...
|
|
|
54
58
|
* [groonga-command-parser](http://rubygems.org/gems/groonga-command-parser)
|
|
55
59
|
* [groonga-client](http://rubygems.org/gems/groonga-client)
|
|
56
60
|
|
|
57
|
-
##
|
|
61
|
+
## Community
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
* Japanese: [groonga-dev@lists.sourceforge.jp](http://lists.sourceforge.jp/mailman/listinfo/groonga-dev)
|
|
63
|
+
See [the community documentation](https://groonga.org/docs/community.html) for details.
|
|
61
64
|
|
|
62
65
|
## Thanks
|
|
63
66
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# `groonga-query-log-check-crash`
|
|
2
|
+
|
|
3
|
+
`groonga-query-log-check-crash` is a tool that supports recovery when Groonga crashes.
|
|
4
|
+
|
|
5
|
+
If Groonga crashes while updating a database, the database may become corrupted.
|
|
6
|
+
It shows tables, columns, and indexes that require recovery, so you can use it when checking what needs to be recovered.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
This section describes how to use `groonga-query-log-check-crash`.
|
|
11
|
+
|
|
12
|
+
You need both the process log and the query log to run `groonga-query-log-check-crash`.
|
|
13
|
+
For log output settings and content, see the Groonga documentation: https://groonga.org/docs/reference/log.html
|
|
14
|
+
|
|
15
|
+
Specify the process log and query log. There is no fixed order for specifying them, so specify all logs.
|
|
16
|
+
|
|
17
|
+
Command example:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
groonga-query-log-check-crash \
|
|
21
|
+
path/to/process-log-2025-* \
|
|
22
|
+
path/to/query-log-2025-* \
|
|
23
|
+
path/to/process-log-2026-* \
|
|
24
|
+
path/to/query-log-2026-*
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Options
|
|
28
|
+
|
|
29
|
+
#### `--command-format`
|
|
30
|
+
|
|
31
|
+
This script displays any Groonga commands that terminated abnormally.
|
|
32
|
+
Specify the format of that command.
|
|
33
|
+
|
|
34
|
+
You can specify `command` or `uri`, and output will be as follows.
|
|
35
|
+
|
|
36
|
+
`--command-format=command`:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
===
|
|
40
|
+
[unflushed] 2000-01-01T00:00:01+09:00:
|
|
41
|
+
load \
|
|
42
|
+
--table "Data"
|
|
43
|
+
===
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`--command-format=uri`:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
===
|
|
50
|
+
[unflushed] 2000-01-01T00:00:01+09:00: /d/load?table=Data
|
|
51
|
+
===
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The default is `command`.
|
|
55
|
+
When using it as HTTP server, specifying `uri` makes it easier to use when re-running.
|
|
56
|
+
|
|
57
|
+
#### `--pretty-print`
|
|
58
|
+
|
|
59
|
+
This is only available when `command` is specified in `--command-format`.
|
|
60
|
+
|
|
61
|
+
By default, `--pretty-print` is enabled. Disabling it will output Groonga commands on a single line.
|
|
62
|
+
|
|
63
|
+
`--no-pretty-print`:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
[unflushed] 2000-01-01T00:00:01+09:00: load --table "Data"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### `--output-level`
|
|
70
|
+
|
|
71
|
+
You can specify `info` or `debug`. The default value is `info`.
|
|
72
|
+
Please use `info` as the default. `debug` provides more detailed output for developers.
|
|
73
|
+
|
|
74
|
+
## Reading the Output
|
|
75
|
+
|
|
76
|
+
### Summary
|
|
77
|
+
|
|
78
|
+
The `Summary` includes the following items.
|
|
79
|
+
|
|
80
|
+
* `crashed`
|
|
81
|
+
* In the case of `yes`, Groonga has crashed.
|
|
82
|
+
* Please report it with the logs.
|
|
83
|
+
* `unflushed`
|
|
84
|
+
* In the case of `yes`, data in memory (non-persistent data) may not have been written to disk (persistent data).
|
|
85
|
+
* Please re-run the target command.
|
|
86
|
+
* `unfinished`
|
|
87
|
+
* In the case of `yes`, the target table, column, or index may be broken.
|
|
88
|
+
* Please rebuild the target table, column, or index.
|
|
89
|
+
* `leak`
|
|
90
|
+
* In the case of `yes`, Groonga is leaking memory.
|
|
91
|
+
* Please report it with the logs.
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Summary:
|
|
97
|
+
crashed:yes, unflushed:yes, unfinished:no, leak:no
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Unflushed
|
|
101
|
+
|
|
102
|
+
If the target command exists, the following output is displayed.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
!!!
|
|
106
|
+
!!! [unflushed] Recovery information
|
|
107
|
+
!!!
|
|
108
|
+
There may be commands that were not flushed between 2000-01-01T00:00:00+09:00 and 2000-01-01T12:00:00+09:00.
|
|
109
|
+
These commands may not have been written to the database files, so please re-run them.
|
|
110
|
+
===
|
|
111
|
+
[unflushed] 2000-01-01T00:00:01+09:00: load --table "Data"
|
|
112
|
+
===
|
|
113
|
+
|
|
114
|
+
Summary:
|
|
115
|
+
crashed:yes, unflushed:yes, unfinished:no, leak:no
|
|
116
|
+
NG: Please check the display and logs.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Lines beginning with `[unflushed]` are commands that may not have been flushed.
|
|
120
|
+
Since it may not have been flushed, please re-run that command.
|
|
121
|
+
|
|
122
|
+
### Unfinished
|
|
123
|
+
|
|
124
|
+
If the target command exists, the following output is displayed.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
!!!
|
|
128
|
+
!!! [unfinished] Recovery information
|
|
129
|
+
!!!
|
|
130
|
+
Unfinished commands were found due to abnormal termination or other issues.
|
|
131
|
+
It is safer to rebuild the target tables, columns, and indexes because the data may be corrupted.
|
|
132
|
+
===
|
|
133
|
+
[unfinished] 2000-01-01T00:00:01+09:00: load --table "Data"
|
|
134
|
+
===
|
|
135
|
+
|
|
136
|
+
Summary:
|
|
137
|
+
crashed:yes, unflushed:no, unfinished:yes, leak:no
|
|
138
|
+
NG: Please check the display and logs.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Lines beginning with `[unfinished]` are commands that did not complete normally due to abnormal termination or other issues.
|
|
142
|
+
In this case, `Data` and any dependent columns or indexes may be broken and need to be rebuilt.
|
|
143
|
+
|
|
144
|
+
### Others
|
|
145
|
+
|
|
146
|
+
If any output other than `unflushed` or `unfinished` was displayed, there might have been an issue with Groonga.
|
|
147
|
+
Please report the problem to the Groonga team using the links below, and include the logs used for the check if possible.
|
|
148
|
+
|
|
149
|
+
* [Groonga issues](https://github.com/groonga/groonga/issues)
|
|
150
|
+
* [Groonga discussions](https://github.com/groonga/groonga/discussions)
|
|
151
|
+
|
|
152
|
+
This will help with investigating the issue.
|
data/doc/text/news.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# News
|
|
2
2
|
|
|
3
|
+
## 1.7.9: 2026-01-27
|
|
4
|
+
|
|
5
|
+
### Improvements
|
|
6
|
+
|
|
7
|
+
* `check-crash`: Improved the output. Made it easier to use for recovery.
|
|
8
|
+
|
|
9
|
+
* Check the [documentation](check-crash.md) as some options have been added.
|
|
10
|
+
|
|
11
|
+
* `check-crash`: Improved the accuracy of unflushed checks.
|
|
12
|
+
|
|
13
|
+
* Improved detection accuracy when no `target_name` is specified for `io_flush`.
|
|
14
|
+
|
|
15
|
+
* Added a `select` command with `--load_table` option specified as the check target for unflushed.
|
|
16
|
+
|
|
17
|
+
* `check-crash`: Showed PID and thread ID
|
|
18
|
+
|
|
19
|
+
* Added support for Ruby 3.4
|
|
20
|
+
|
|
21
|
+
### Fixes
|
|
22
|
+
|
|
23
|
+
* `show-running-queries`: Fixed running query condition
|
|
24
|
+
|
|
3
25
|
## 1.7.8: 2024-04-10
|
|
4
26
|
|
|
5
27
|
### Improvements
|
data/groonga-query-log.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- ruby -*-
|
|
2
2
|
#
|
|
3
|
-
# Copyright (C) 2012-
|
|
3
|
+
# Copyright (C) 2012-2025 Sutou Kouhei <kou@clear-code.com>
|
|
4
4
|
#
|
|
5
5
|
# This library is free software; you can redistribute it and/or
|
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
|
@@ -52,11 +52,13 @@ Gem::Specification.new do |spec|
|
|
|
52
52
|
spec.licenses = ["LGPLv2.1+"]
|
|
53
53
|
spec.require_paths = ["lib"]
|
|
54
54
|
|
|
55
|
+
spec.add_runtime_dependency("base64")
|
|
55
56
|
spec.add_runtime_dependency("charty")
|
|
56
57
|
spec.add_runtime_dependency("diff-lcs")
|
|
57
|
-
spec.add_runtime_dependency("net-smtp")
|
|
58
58
|
spec.add_runtime_dependency("groonga-client", ">= 0.6.2")
|
|
59
59
|
spec.add_runtime_dependency("groonga-log", ">= 0.1.2")
|
|
60
|
+
spec.add_runtime_dependency("net-smtp")
|
|
61
|
+
spec.add_runtime_dependency("ostruct")
|
|
60
62
|
|
|
61
63
|
spec.add_development_dependency("test-unit")
|
|
62
64
|
spec.add_development_dependency("test-unit-rr")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (C) 2018 Kouhei
|
|
1
|
+
# Copyright (C) 2018-2025 Sutou Kouhei <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
|
|
@@ -34,6 +34,11 @@ module GroongaQueryLog
|
|
|
34
34
|
return false
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
if log_paths.empty?
|
|
38
|
+
puts(@option_parser.help)
|
|
39
|
+
return false
|
|
40
|
+
end
|
|
41
|
+
|
|
37
42
|
begin
|
|
38
43
|
check(log_paths)
|
|
39
44
|
rescue Interrupt
|
|
@@ -47,11 +52,35 @@ module GroongaQueryLog
|
|
|
47
52
|
|
|
48
53
|
private
|
|
49
54
|
def setup_options
|
|
50
|
-
|
|
55
|
+
available_command_format = [:command, :uri]
|
|
56
|
+
available_output_levels = [:info, :debug]
|
|
57
|
+
@options = {
|
|
58
|
+
command_format: :command,
|
|
59
|
+
output_level: :info,
|
|
60
|
+
pretty_print: true
|
|
61
|
+
}
|
|
51
62
|
|
|
52
63
|
@option_parser = OptionParser.new do |parser|
|
|
53
64
|
parser.version = VERSION
|
|
54
65
|
parser.banner += " LOG1 ..."
|
|
66
|
+
parser.on("--command-format=FORMAT",
|
|
67
|
+
available_command_format,
|
|
68
|
+
"Specify the output format of the Groonga command that had a problem. [#{@options[:command_format]}]",
|
|
69
|
+
"(#{available_command_format.join(", ")})") do |format|
|
|
70
|
+
@options[:command_format] = format
|
|
71
|
+
end
|
|
72
|
+
parser.on("--[no-]pretty-print",
|
|
73
|
+
"Specify to make command output easier to read. [#{@options[:pretty_print]}]",
|
|
74
|
+
"Only available when `--command-format=command` is specified.") do |boolean|
|
|
75
|
+
@options[:pretty_print] = boolean
|
|
76
|
+
end
|
|
77
|
+
parser.on("--output-level=LEVEL",
|
|
78
|
+
available_output_levels,
|
|
79
|
+
"Specify the output level. [#{@options[:output_level]}]",
|
|
80
|
+
"Specifying 'debug' displays detailed information.",
|
|
81
|
+
"(#{available_output_levels.join(", ")})") do |output_level|
|
|
82
|
+
@options[:output_level] = output_level
|
|
83
|
+
end
|
|
55
84
|
end
|
|
56
85
|
end
|
|
57
86
|
|
|
@@ -66,7 +95,7 @@ module GroongaQueryLog
|
|
|
66
95
|
end
|
|
67
96
|
|
|
68
97
|
def check(log_paths)
|
|
69
|
-
checker = Checker.new(log_paths)
|
|
98
|
+
checker = Checker.new(log_paths, @options)
|
|
70
99
|
checker.check
|
|
71
100
|
end
|
|
72
101
|
|
|
@@ -111,58 +140,62 @@ module GroongaQueryLog
|
|
|
111
140
|
end
|
|
112
141
|
|
|
113
142
|
class Checker
|
|
114
|
-
def initialize(log_paths)
|
|
143
|
+
def initialize(log_paths, options)
|
|
115
144
|
split_log_paths(log_paths)
|
|
145
|
+
@options = options
|
|
116
146
|
end
|
|
117
147
|
|
|
118
148
|
def check
|
|
149
|
+
summary = {
|
|
150
|
+
crashed: false,
|
|
151
|
+
unflushed: false,
|
|
152
|
+
unfinished: false,
|
|
153
|
+
leak: false,
|
|
154
|
+
}
|
|
119
155
|
processes = ProcessEnumerator.new(@general_log_paths)
|
|
120
156
|
processes.each do |process|
|
|
121
157
|
need_query_log_parsing = true
|
|
122
158
|
if process.successfully_finished?
|
|
123
159
|
need_query_log_parsing = false
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
160
|
+
debug([:process,
|
|
161
|
+
:success,
|
|
162
|
+
process.version,
|
|
163
|
+
process.start_time.iso8601,
|
|
164
|
+
process.end_time.iso8601,
|
|
165
|
+
process.pid,
|
|
166
|
+
process.start_log_path,
|
|
167
|
+
process.end_log_path].inspect)
|
|
132
168
|
elsif process.crashed?
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
169
|
+
debug([:process,
|
|
170
|
+
:crashed,
|
|
171
|
+
process.version,
|
|
172
|
+
process.start_time.iso8601,
|
|
173
|
+
process.end_time.iso8601,
|
|
174
|
+
process.pid,
|
|
175
|
+
process.start_log_path,
|
|
176
|
+
process.end_log_path].inspect)
|
|
177
|
+
summary[:crashed] = true
|
|
141
178
|
else
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
179
|
+
debug([:process,
|
|
180
|
+
:unfinished,
|
|
181
|
+
process.version,
|
|
182
|
+
process.start_time.iso8601,
|
|
183
|
+
process.pid,
|
|
184
|
+
process.start_log_path].inspect)
|
|
148
185
|
end
|
|
149
186
|
|
|
150
187
|
unless process.n_leaks.zero?
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
188
|
+
debug([:leak,
|
|
189
|
+
process.version,
|
|
190
|
+
process.n_leaks,
|
|
191
|
+
process.end_time.iso8601,
|
|
192
|
+
process.pid,
|
|
193
|
+
process.end_log_path].inspect)
|
|
194
|
+
summary[:leak] = true
|
|
157
195
|
end
|
|
158
196
|
|
|
159
197
|
unless process.important_entries.empty?
|
|
160
|
-
|
|
161
|
-
process.important_entries.each_with_index do |entry, i|
|
|
162
|
-
puts("#{entry.timestamp.iso8601}: " +
|
|
163
|
-
"#{entry.log_level}: " +
|
|
164
|
-
"#{entry.message}")
|
|
165
|
-
end
|
|
198
|
+
output_important_entries_info(process.important_entries)
|
|
166
199
|
end
|
|
167
200
|
|
|
168
201
|
next unless need_query_log_parsing
|
|
@@ -183,20 +216,22 @@ module GroongaQueryLog
|
|
|
183
216
|
statistic.start_time < start_time
|
|
184
217
|
end
|
|
185
218
|
unless target_parsing_statistics.empty?
|
|
186
|
-
|
|
187
|
-
target_parsing_statistics
|
|
188
|
-
puts("#{statistic.start_time.iso8601}:")
|
|
189
|
-
puts(statistic.command.to_command_format(pretty_print: true))
|
|
190
|
-
end
|
|
219
|
+
summary[:unfinished] = true
|
|
220
|
+
output_unfinished_info(target_parsing_statistics)
|
|
191
221
|
end
|
|
192
222
|
unless @unflushed_statistics.empty?
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
@unflushed_statistics.each do |statistic|
|
|
196
|
-
puts("#{statistic.start_time.iso8601}: #{statistic.raw_command}")
|
|
197
|
-
end
|
|
223
|
+
summary[:unflushed] = true
|
|
224
|
+
output_unflushed_info(start_time, end_time)
|
|
198
225
|
end
|
|
199
226
|
end
|
|
227
|
+
info("",
|
|
228
|
+
"Summary:",
|
|
229
|
+
summary.map {|k, v| "#{k}:#{v ? "yes" : "no"}" }.join(", "))
|
|
230
|
+
if summary.value?(true)
|
|
231
|
+
info("NG: Please check the display and logs.")
|
|
232
|
+
else
|
|
233
|
+
info("OK: no problems.")
|
|
234
|
+
end
|
|
200
235
|
end
|
|
201
236
|
|
|
202
237
|
private
|
|
@@ -215,6 +250,21 @@ module GroongaQueryLog
|
|
|
215
250
|
end
|
|
216
251
|
end
|
|
217
252
|
|
|
253
|
+
def formated_command(command)
|
|
254
|
+
if @options[:command_format] == :uri
|
|
255
|
+
command.to_uri_format
|
|
256
|
+
else
|
|
257
|
+
(@options[:pretty_print] ? "\n" : "") +
|
|
258
|
+
command.to_command_format(pretty_print: @options[:pretty_print])
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def with_load?(statistic)
|
|
263
|
+
statistic.operations.any? do |operation|
|
|
264
|
+
operation[:name] == "load"
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
218
268
|
def check_query_log_statistic(path, statistic)
|
|
219
269
|
command = statistic.command
|
|
220
270
|
return if command.nil?
|
|
@@ -230,7 +280,7 @@ module GroongaQueryLog
|
|
|
230
280
|
@flushed = false
|
|
231
281
|
@unflushed_statistics << statistic
|
|
232
282
|
when "io_flush"
|
|
233
|
-
check_io_flush(
|
|
283
|
+
check_io_flush(statistic)
|
|
234
284
|
when "database_unmap"
|
|
235
285
|
@unflushed_statistics.reject! do |statistic|
|
|
236
286
|
command.name == "load"
|
|
@@ -246,33 +296,65 @@ module GroongaQueryLog
|
|
|
246
296
|
when "plugin_register", "plugin_unregister"
|
|
247
297
|
@flushed = false
|
|
248
298
|
@unflushed_statistics << statistic
|
|
299
|
+
when "select"
|
|
300
|
+
if with_load?(statistic)
|
|
301
|
+
@flushed = false
|
|
302
|
+
@unflushed_statistics << statistic
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def flushed_objects(statistic)
|
|
308
|
+
objects = {}
|
|
309
|
+
statistic.operations.each do |operation|
|
|
310
|
+
object = operation[:name][/\Aflush\[(.+)\]/, 1]
|
|
311
|
+
objects[object] = true unless object.nil?
|
|
312
|
+
end
|
|
313
|
+
objects
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def load_check_keys(statistic)
|
|
317
|
+
case statistic.command.command_name
|
|
318
|
+
when "load"
|
|
319
|
+
[:table, :columns]
|
|
320
|
+
when "select"
|
|
321
|
+
[:load_table, :load_columns]
|
|
322
|
+
else
|
|
323
|
+
raise "Unsupported command name"
|
|
249
324
|
end
|
|
250
325
|
end
|
|
251
326
|
|
|
252
|
-
def
|
|
253
|
-
|
|
327
|
+
def flushed_load?(statistic, flushed)
|
|
328
|
+
table_key, columns_key = load_check_keys(statistic)
|
|
329
|
+
|
|
330
|
+
table_name = statistic.command.arguments[table_key]
|
|
331
|
+
return false unless flushed.key?(table_name)
|
|
332
|
+
columns = statistic.command.arguments[columns_key]
|
|
333
|
+
return true unless columns
|
|
334
|
+
columns.split(",").each do |name|
|
|
335
|
+
name.strip!
|
|
336
|
+
next if name == "_key"
|
|
337
|
+
return false unless flushed["#{table_name}.#{name}"]
|
|
338
|
+
end
|
|
339
|
+
true
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def check_io_flush(io_flush_statistic)
|
|
343
|
+
io_flush = io_flush_statistic.command
|
|
254
344
|
if io_flush.target_name
|
|
255
|
-
if io_flush.
|
|
345
|
+
if io_flush.recursive_dependent?
|
|
256
346
|
@unflushed_statistics.reject! do |statistic|
|
|
257
347
|
case statistic.command.command_name
|
|
258
|
-
when "load"
|
|
259
|
-
|
|
260
|
-
statistic.command.table == io_flush.target_name
|
|
348
|
+
when "load", "select"
|
|
349
|
+
flushed_load?(statistic, flushed_objects(io_flush_statistic))
|
|
261
350
|
when "delete"
|
|
262
|
-
# TODO: Not enough
|
|
263
351
|
statistic.command.table == io_flush.target_name
|
|
264
352
|
when "truncate"
|
|
265
|
-
# TODO: Not enough
|
|
266
353
|
statistic.command.target_name == io_flush.target_name
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
else
|
|
272
|
-
@unflushed_statistics.reject! do |statistic|
|
|
273
|
-
case statistic.command.command_name
|
|
274
|
-
when /_create/
|
|
275
|
-
true # TODO: Need io_flush for database
|
|
354
|
+
when "table_create"
|
|
355
|
+
statistic.command.name == io_flush.target_name
|
|
356
|
+
when "column_create"
|
|
357
|
+
"#{statistic.command.table}.#{statistic.command.name}" == io_flush.target_name
|
|
276
358
|
else
|
|
277
359
|
false
|
|
278
360
|
end
|
|
@@ -280,24 +362,101 @@ module GroongaQueryLog
|
|
|
280
362
|
end
|
|
281
363
|
else
|
|
282
364
|
if io_flush.recursive?
|
|
283
|
-
|
|
284
|
-
else
|
|
365
|
+
flushed = flushed_objects(io_flush_statistic)
|
|
285
366
|
@unflushed_statistics.reject! do |statistic|
|
|
286
367
|
case statistic.command.command_name
|
|
287
|
-
when
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
368
|
+
when "load", "select"
|
|
369
|
+
# TODO: Not enough
|
|
370
|
+
flushed_load?(statistic, flushed_objects(io_flush_statistic))
|
|
371
|
+
when "delete"
|
|
372
|
+
# TODO: Not enough
|
|
373
|
+
flushed.key?(statistic.command.table)
|
|
374
|
+
when "truncate"
|
|
375
|
+
# TODO: Not enough
|
|
376
|
+
flushed.key?(statistic.command.target_name)
|
|
377
|
+
when "table_create"
|
|
378
|
+
# TODO: Not enough
|
|
379
|
+
flushed.key?(statistic.command.name)
|
|
380
|
+
when "column_create"
|
|
381
|
+
# TODO: Not enough
|
|
382
|
+
flushed.key?("#{statistic.command.table}.#{statistic.command.name}")
|
|
293
383
|
else
|
|
294
384
|
false
|
|
295
385
|
end
|
|
296
386
|
end
|
|
297
387
|
end
|
|
388
|
+
@unflushed_statistics.reject! do |statistic|
|
|
389
|
+
case statistic.command.command_name
|
|
390
|
+
when /_remove\z/, /_rename\z/
|
|
391
|
+
true
|
|
392
|
+
when "plugin_register", "plugin_unregister"
|
|
393
|
+
true
|
|
394
|
+
else
|
|
395
|
+
false
|
|
396
|
+
end
|
|
397
|
+
end
|
|
298
398
|
end
|
|
299
399
|
@flushed = @unflushed_statistics.empty?
|
|
300
400
|
end
|
|
401
|
+
|
|
402
|
+
def debug(*messages)
|
|
403
|
+
return unless @options[:output_level] == :debug
|
|
404
|
+
puts(*messages)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def info(*messages)
|
|
408
|
+
puts(*messages)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def output_important_entries_info(entries)
|
|
412
|
+
info("",
|
|
413
|
+
"!!!",
|
|
414
|
+
"!!! Important entries",
|
|
415
|
+
"!!!",
|
|
416
|
+
"It contained logs that require checking.",
|
|
417
|
+
"If you need help, please feel free to contact the community: https://groonga.org/docs/community.html",
|
|
418
|
+
"===")
|
|
419
|
+
entries.each do |entry|
|
|
420
|
+
info("#{entry.timestamp.iso8601}: " +
|
|
421
|
+
"#{entry.pid}: " +
|
|
422
|
+
"#{entry.thread_id}: " +
|
|
423
|
+
"#{entry.log_level}: " +
|
|
424
|
+
"#{entry.message}")
|
|
425
|
+
end
|
|
426
|
+
info("===")
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def output_statistics_info(message, tag, statistics)
|
|
430
|
+
info(message, "===")
|
|
431
|
+
statistics.each do |statistic|
|
|
432
|
+
info("[#{tag}] #{statistic.start_time.iso8601}: #{formated_command(statistic.command)}")
|
|
433
|
+
end
|
|
434
|
+
info("===")
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def output_unfinished_info(statistics)
|
|
438
|
+
message = <<-MESSAGE
|
|
439
|
+
|
|
440
|
+
!!!
|
|
441
|
+
!!! [unfinished] Recovery information
|
|
442
|
+
!!!
|
|
443
|
+
Unfinished commands were found due to abnormal termination or other issues.
|
|
444
|
+
It is safer to rebuild the target tables, columns, and indexes because the data may be corrupted.
|
|
445
|
+
MESSAGE
|
|
446
|
+
output_statistics_info(message, "unfinished", statistics)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def output_unflushed_info(start_time, end_time)
|
|
450
|
+
message = <<-MESSAGE
|
|
451
|
+
|
|
452
|
+
!!!
|
|
453
|
+
!!! [unflushed] Recovery information
|
|
454
|
+
!!!
|
|
455
|
+
There may be commands that were not flushed between #{start_time.iso8601} and #{end_time.iso8601}.
|
|
456
|
+
These commands may not have been written to the database files, so please re-run them.
|
|
457
|
+
MESSAGE
|
|
458
|
+
output_statistics_info(message, "unflushed", @unflushed_statistics)
|
|
459
|
+
end
|
|
301
460
|
end
|
|
302
461
|
|
|
303
462
|
class ProcessEnumerator
|