perfmonger 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +6 -2
- data/HOWTO.md +0 -1
- data/NEWS +15 -6
- data/README.md +77 -27
- data/Rakefile +18 -9
- data/core/Makefile +2 -18
- data/core/build.sh +1 -1
- data/core/perfmonger-player.go +71 -40
- data/core/perfmonger-plot-formatter.go +18 -4
- data/core/perfmonger-recorder.go +16 -2
- data/core/perfmonger-summarizer.go +19 -13
- data/core/subsystem/usage.go +143 -66
- data/core/subsystem/usage_test.go +62 -32
- data/{bin → exe}/perfmonger +0 -0
- data/lib/perfmonger/command/fingerprint.rb +26 -1
- data/lib/perfmonger/command/live.rb +19 -0
- data/lib/perfmonger/command/play.rb +16 -0
- data/lib/perfmonger/command/plot.rb +16 -10
- data/lib/perfmonger/command/server.rb +1 -1
- data/lib/perfmonger/version.rb +1 -1
- data/misc/werker-box/Dockerfile +35 -0
- data/misc/werker-box/build-push.sh +5 -0
- data/perfmonger.gemspec +2 -1
- data/spec/data/busy100.pgr.played +3 -3
- data/spec/fingerprint_spec.rb +1 -1
- data/spec/live_spec.rb +2 -3
- data/spec/perfmonger_spec.rb +1 -1
- data/spec/play_spec.rb +1 -1
- data/spec/plot_spec.rb +16 -1
- data/spec/record_spec.rb +10 -1
- data/spec/spec_helper.rb +28 -3
- data/spec/stat_spec.rb +2 -2
- data/spec/summary_spec.rb +1 -1
- data/wercker.yml +47 -16
- metadata +25 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e47b0d30a3300a01ae5efcc0bbbe10baf524561
|
4
|
+
data.tar.gz: 88988c5009fcbe62049c7355f3e8374b3c825f5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f767fae2183025478897926d3b79d705fd30937f8c7f7cd6221dd29ad0d9ae03f7940c29be234613f8100f1c9dafb3e8d079075ab2d2d1879b2de33fdc2e482
|
7
|
+
data.tar.gz: e4f1d714cd58d57db382320224d356f919692f25a4552d5649accf7a27c63cac693049972dd994904cdb4d4a54c9f2c19e374b25d928f392e4bffbdb517d5460
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
1
|
language: ruby
|
3
2
|
install:
|
4
3
|
- sudo apt-get update
|
5
4
|
- sudo apt-get install gnuplot
|
6
5
|
- gnuplot -e "set terminal" < /dev/null 2>&1
|
7
6
|
- bundle install
|
8
|
-
- go_version="1.
|
7
|
+
- go_version="1.8.3"
|
9
8
|
- wget http://golang.org/dl/go${go_version}.linux-amd64.tar.gz
|
10
9
|
- sudo tar -C /usr/local -xzf go${go_version}.linux-amd64.tar.gz
|
11
10
|
- export PATH=$PATH:/usr/local/go/bin
|
12
11
|
- export GOPATH="$HOME/go"
|
13
12
|
- export PATH="$PATH:$GOPATH/bin"
|
14
13
|
- mkdir -p "$HOME/go/{src,pkg,bin}"
|
14
|
+
- go get -u github.com/mattn/go-isatty
|
15
|
+
- go get -u github.com/hayamiz/go-projson
|
15
16
|
- go get -u golang.org/x/crypto/ssh/terminal
|
16
17
|
- go get -u github.com/hayamiz/perfmonger/core/subsystem
|
17
18
|
rvm:
|
@@ -22,3 +23,6 @@ rvm:
|
|
22
23
|
script:
|
23
24
|
- rake spec
|
24
25
|
- rake test_core
|
26
|
+
notifications:
|
27
|
+
slack:
|
28
|
+
secure: fH8tRyxWHL60OV6QuJlzig9lCLbjfpHx8E6D2EzgQz7+/wqAxtoTUyiN7mbpEJa4hyQeZfpmMpDTnl2tHD6eI8yqjAsY4Q+jt21tCKyrKMegq9Pypd4eMP4o+DupT2mXm0K3cZ2Kgb+yP8AuJPoTy20j3kpmnDFWdqRnhgpBLC8=
|
data/HOWTO.md
CHANGED
data/NEWS
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
-
##
|
1
|
+
## 2018-05-15: PerfMonger 0.11.0
|
2
|
+
* New features
|
3
|
+
* [play] subcommand:
|
4
|
+
* Add --color, --pretty option for pretty JSON output
|
5
|
+
* [live] subcommand:
|
6
|
+
* Add --color, --pretty option for pretty JSON output
|
7
|
+
* [fingerprint] subcommand:
|
8
|
+
* Collect additional info: numactl, ec2-metadata
|
2
9
|
* Bug fixes
|
3
10
|
* [plot] subcommand:
|
4
|
-
*
|
5
|
-
|
6
|
-
|
7
|
-
|
11
|
+
* Correctly filter out disk usages by --disk-only option
|
12
|
+
* Changes
|
13
|
+
* Dropped support of i386
|
14
|
+
* Use go-projson for JSON output
|
15
|
+
* [plot] subcommand:
|
16
|
+
* Stacked graphs layout in allcpu.pdf
|
8
17
|
|
9
18
|
## 2017-06-19: PerfMonger 0.10.0
|
10
19
|
* New features
|
@@ -204,4 +213,4 @@ PerfMonger is available on yum repository from this release.
|
|
204
213
|
## 2011-12-09: PerfMonger 0.1.0 released
|
205
214
|
|
206
215
|
* New features
|
207
|
-
* I/O performance monitoring
|
216
|
+
* I/O performance monitoring
|
data/README.md
CHANGED
@@ -5,31 +5,97 @@
|
|
5
5
|
|
6
6
|
[![wercker status](https://app.wercker.com/status/44c3ade6a2406d337df6d93097a52fdf/m "wercker status")](https://app.wercker.com/project/bykey/44c3ade6a2406d337df6d93097a52fdf)
|
7
7
|
|
8
|
-
PerfMonger is
|
9
|
-
|
8
|
+
PerfMonger is a system performance monitor which enables high-resolution and holistic performance measurement with the programmer friendly interface.
|
9
|
+
|
10
|
+
* High-resolution: sub-second level monitoring is possible!
|
11
|
+
* Holistic performance measurement: monitoring CPU, Disk I/O, Network all at once.
|
12
|
+
* Programmer friendly: PerfMonger speaks monitoring results in JSON format, which makes later performance analysis much easier (ex. [jq](https://github.com/stedolan/jq)).
|
10
13
|
|
11
14
|
**CAUTION: PerfMonger is still in early stage, so there may be a drastic change in the future. Do not use it for critical jobs**
|
12
15
|
|
13
16
|
## Target platform
|
14
17
|
|
15
18
|
* GNU/Linux
|
19
|
+
* Mac OS X (experimental support)
|
16
20
|
|
17
|
-
##
|
18
|
-
|
19
|
-
* Ruby 1.9.3 or later
|
20
|
-
* gnuplot 4.6.0 or later (optional)
|
21
|
-
|
22
|
-
Note: You need Cutter unit testing framework for building/running tests.
|
23
|
-
|
24
|
-
## How to install
|
21
|
+
## How to installation
|
25
22
|
|
26
23
|
gem install perfmonger
|
27
24
|
|
25
|
+
You need gnuplot 4.6.0 or later build with cairo terminals for plotting measurement data with `perfmonger plot` command.
|
26
|
+
|
28
27
|
### Build from source
|
29
28
|
|
29
|
+
You need Ruby 1.9.3 or later, and Go 1.8 or later to build perfmonger.
|
30
|
+
|
31
|
+
bundle
|
30
32
|
rake build
|
31
33
|
|
32
|
-
##
|
34
|
+
## Getting started
|
35
|
+
|
36
|
+
Basic usage of PerfMonger is:
|
37
|
+
|
38
|
+
* Run `perfmonger record` to record performance information logs
|
39
|
+
* Run `perfmonger play` to show performance information logs in JSON format
|
40
|
+
|
41
|
+
`perfmonger play` repatedly prints records of system performance including CPU
|
42
|
+
usages, disk usages, and network usages. One line includes only one record, so
|
43
|
+
you can easily process output records with `jq`, or any scripting languages like
|
44
|
+
Ruby, Python, and etc.
|
45
|
+
|
46
|
+
Pretty-printed structure of a record is as follows:
|
47
|
+
|
48
|
+
```
|
49
|
+
{"time": 1500043743.504, # timestamp in unix epoch time
|
50
|
+
"cpu": { # CPU usages
|
51
|
+
"num_core": 2, # the number of cores
|
52
|
+
"all": { # aggregated CPU usage (max = num_core * 100%)
|
53
|
+
"usr": 50.0,
|
54
|
+
"sys": 50.0,
|
55
|
+
"idle": 100.0,
|
56
|
+
...
|
57
|
+
},
|
58
|
+
"cores": [ # Usage of each CPU core
|
59
|
+
{
|
60
|
+
"usr": 25.0,
|
61
|
+
"sys": 25.0,
|
62
|
+
"idle": 50.0,
|
63
|
+
...
|
64
|
+
},
|
65
|
+
{
|
66
|
+
"usr": 25.0,
|
67
|
+
"sys": 25.0,
|
68
|
+
"idle": 50.0,
|
69
|
+
...
|
70
|
+
}
|
71
|
+
]
|
72
|
+
},
|
73
|
+
"disk": { # Disk usages
|
74
|
+
"devices": ["sda"], # List of disk devices
|
75
|
+
"sda": { # Usage of device 'sda'
|
76
|
+
"riops": 10.0, # The number of read I/O per second
|
77
|
+
"wiops": 20.0, # The number of write I/O per second
|
78
|
+
"rkbyteps": 80.0, # Read transfer rate in KB/s
|
79
|
+
"wkbyteps": 160.0, # Write transfer rate in KB/s
|
80
|
+
...
|
81
|
+
}
|
82
|
+
"total": { # Aggregated usage of all devices
|
83
|
+
"riops": 10.0,
|
84
|
+
"wiops": 20.0,
|
85
|
+
"rkbyteps": 80.0,
|
86
|
+
"wkbyteps": 160.0,
|
87
|
+
...
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
|
94
|
+
## Typical use cases
|
95
|
+
|
96
|
+
### `perfmonger live`: live performance monitoring
|
97
|
+
|
98
|
+
$ perfmonger live
|
33
99
|
|
34
100
|
### Monitor IO performance of /dev/sda for each 0.1 second
|
35
101
|
|
@@ -42,19 +108,3 @@ Note: You need Cutter unit testing framework for building/running tests.
|
|
42
108
|
### Monitor CPU usage and IO performance of /dev/sda, sdb for each 0.1 second
|
43
109
|
|
44
110
|
$ perfmonger record -i 0.1 -d sda -d sdb
|
45
|
-
|
46
|
-
### Plot CPU and IOPS
|
47
|
-
|
48
|
-
$ perfmonger record -i 0.1 -C -d sda > /tmp/perfmonger.log & sleep 10; pkill perfmonger
|
49
|
-
$ perfmonger plot -o /path/to/output_dir/ -Tpng /tmp/perfmonger.log
|
50
|
-
$ display /path/to/output_dir/read-iops.png
|
51
|
-
$ display /path/to/output_dir/cpu.png
|
52
|
-
|
53
|
-
![Sample image of IOPS graph](https://raw.github.com/hayamiz/perfmonger/master/misc/sample-read-iops.png)
|
54
|
-
![Sample image of CPU usage graph](https://raw.github.com/hayamiz/perfmonger/master/misc/sample-cpu.png)
|
55
|
-
|
56
|
-
## Special Thanks
|
57
|
-
|
58
|
-
Large portion of PerfMonger comes from
|
59
|
-
[SYSSTAT](http://sebastien.godard.pagesperso-orange.fr/) codebase. Thanks for
|
60
|
-
their great work.
|
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ task :default => [:spec, :test_core]
|
|
7
7
|
desc "Run all specs in spec directory"
|
8
8
|
RSpec::Core::RakeTask.new(:spec)
|
9
9
|
|
10
|
-
task :spec => [:
|
10
|
+
task :spec => [:cross_build_core]
|
11
11
|
|
12
12
|
desc "Cross build core recorder/player"
|
13
13
|
task :cross_build_core do
|
@@ -18,20 +18,29 @@ task :cross_build_core do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
desc "Self build core recorder/player"
|
22
|
-
task :self_build_core do
|
23
|
-
Dir.chdir("./core") do
|
24
|
-
sh "./build.sh -"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
21
|
task :build => :cross_build_core
|
29
22
|
|
23
|
+
desc "Install Golang libraries"
|
24
|
+
task :go_get do
|
25
|
+
sh "go get -u github.com/hayamiz/go-projson"
|
26
|
+
sh "go get -u github.com/hayamiz/perfmonger/core/subsystem"
|
27
|
+
sh "go get -u golang.org/x/crypto/ssh/terminal"
|
28
|
+
sh "go get -u github.com/mattn/go-isatty"
|
29
|
+
end
|
30
|
+
|
30
31
|
desc "Run tests of core recorder/player"
|
31
|
-
task :test_core do
|
32
|
+
task :test_core => [:cross_build_core] do
|
32
33
|
Dir.chdir("./core/subsystem") do
|
33
34
|
sh "go test -v -cover"
|
35
|
+
|
36
|
+
# running static analysis
|
37
|
+
sh "go vet *.go"
|
34
38
|
end
|
39
|
+
|
40
|
+
Dir.chdir("./core") do
|
41
|
+
sh "go vet *.go"
|
42
|
+
end
|
43
|
+
|
35
44
|
end
|
36
45
|
|
37
46
|
desc "Removed generated files"
|
data/core/Makefile
CHANGED
@@ -9,22 +9,6 @@ GO_SRC := utils.go
|
|
9
9
|
all: build
|
10
10
|
|
11
11
|
|
12
|
-
../lib/exec/perfmonger-recorder_linux_386: perfmonger-recorder.go $(GO_DEPS)
|
13
|
-
go build -o $@ perfmonger-recorder.go $(GO_SRC)
|
14
|
-
|
15
|
-
|
16
|
-
../lib/exec/perfmonger-player_linux_386: perfmonger-player.go $(GO_DEPS)
|
17
|
-
go build -o $@ perfmonger-player.go $(GO_SRC)
|
18
|
-
|
19
|
-
|
20
|
-
../lib/exec/perfmonger-summarizer_linux_386: perfmonger-summarizer.go $(GO_DEPS)
|
21
|
-
go build -o $@ perfmonger-summarizer.go $(GO_SRC)
|
22
|
-
|
23
|
-
|
24
|
-
../lib/exec/perfmonger-plot-formatter_linux_386: perfmonger-plot-formatter.go $(GO_DEPS)
|
25
|
-
go build -o $@ perfmonger-plot-formatter.go $(GO_SRC)
|
26
|
-
|
27
|
-
|
28
12
|
../lib/exec/perfmonger-recorder_linux_amd64: perfmonger-recorder.go $(GO_DEPS)
|
29
13
|
go build -o $@ perfmonger-recorder.go $(GO_SRC)
|
30
14
|
|
@@ -57,8 +41,8 @@ all: build
|
|
57
41
|
go build -o $@ perfmonger-plot-formatter.go $(GO_SRC)
|
58
42
|
|
59
43
|
|
60
|
-
build: ../lib/exec/perfmonger-
|
44
|
+
build: ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-plot-formatter_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
|
61
45
|
|
62
46
|
clean:
|
63
|
-
rm -f ../lib/exec/perfmonger-
|
47
|
+
rm -f ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-plot-formatter_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
|
64
48
|
|
data/core/build.sh
CHANGED
data/core/perfmonger-player.go
CHANGED
@@ -4,39 +4,38 @@ package main
|
|
4
4
|
|
5
5
|
import (
|
6
6
|
"bufio"
|
7
|
-
"bytes"
|
8
7
|
"encoding/gob"
|
8
|
+
"flag"
|
9
9
|
"fmt"
|
10
10
|
"io"
|
11
11
|
"os"
|
12
12
|
|
13
|
+
projson "github.com/hayamiz/go-projson"
|
13
14
|
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
14
15
|
)
|
15
16
|
|
16
|
-
|
17
|
+
type PlayerOption struct {
|
18
|
+
logfile string
|
19
|
+
color bool
|
20
|
+
pretty bool
|
21
|
+
}
|
22
|
+
|
23
|
+
var option PlayerOption
|
24
|
+
var init_rec ss.StatRecord
|
25
|
+
|
26
|
+
func showCpuStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
17
27
|
cusage, err := ss.GetCpuUsage(prev_rec.Cpu, cur_rec.Cpu)
|
18
28
|
if err != nil {
|
19
29
|
return err
|
20
30
|
}
|
21
|
-
|
22
|
-
|
31
|
+
|
32
|
+
printer.PutKey("cpu")
|
33
|
+
cusage.WriteJsonTo(printer)
|
23
34
|
|
24
35
|
return nil
|
25
36
|
}
|
26
37
|
|
27
|
-
func showInterruptStat(
|
28
|
-
// intr_usage, err := ss.GetInterruptUsage(
|
29
|
-
// prev_rec.Time, prev_rec.Interrupt,
|
30
|
-
// cur_rec.Time, cur_rec.Interrupt)
|
31
|
-
// if err != nil {
|
32
|
-
// return err
|
33
|
-
// }
|
34
|
-
//
|
35
|
-
// buffer.WriteString(`,"intr":`)
|
36
|
-
// intr_usage.WriteJsonTo(buffer)
|
37
|
-
//
|
38
|
-
// return nil
|
39
|
-
|
38
|
+
func showInterruptStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
40
39
|
intr_usage, err := ss.GetInterruptUsage(
|
41
40
|
prev_rec.Time, prev_rec.Interrupt,
|
42
41
|
cur_rec.Time, cur_rec.Interrupt)
|
@@ -44,13 +43,13 @@ func showInterruptStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *s
|
|
44
43
|
return err
|
45
44
|
}
|
46
45
|
|
47
|
-
|
48
|
-
intr_usage.WriteJsonTo(
|
46
|
+
printer.PutKey("intr")
|
47
|
+
intr_usage.WriteJsonTo(printer)
|
49
48
|
|
50
49
|
return nil
|
51
50
|
}
|
52
51
|
|
53
|
-
func showDiskStat(
|
52
|
+
func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
54
53
|
dusage, err := ss.GetDiskUsage(
|
55
54
|
prev_rec.Time, prev_rec.Disk,
|
56
55
|
cur_rec.Time, cur_rec.Disk)
|
@@ -58,13 +57,14 @@ func showDiskStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.Sta
|
|
58
57
|
return err
|
59
58
|
}
|
60
59
|
|
61
|
-
|
62
|
-
|
60
|
+
printer.PutKey("disk")
|
61
|
+
|
62
|
+
dusage.WriteJsonTo(printer)
|
63
63
|
|
64
64
|
return nil
|
65
65
|
}
|
66
66
|
|
67
|
-
func showNetStat(
|
67
|
+
func showNetStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
68
68
|
dusage, err := ss.GetNetUsage(
|
69
69
|
prev_rec.Time, prev_rec.Net,
|
70
70
|
cur_rec.Time, cur_rec.Net,
|
@@ -73,52 +73,77 @@ func showNetStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.Stat
|
|
73
73
|
return err
|
74
74
|
}
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
printer.PutKey("net")
|
77
|
+
|
78
|
+
dusage.WriteJsonTo(printer)
|
78
79
|
|
79
80
|
return nil
|
80
81
|
}
|
81
82
|
|
82
|
-
func showStat(
|
83
|
-
|
83
|
+
func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
84
|
+
printer.Reset()
|
85
|
+
if option.pretty {
|
86
|
+
printer.SetStyle(projson.SmartStyle)
|
87
|
+
}
|
88
|
+
if option.color {
|
89
|
+
printer.SetColor(true)
|
90
|
+
}
|
91
|
+
printer.BeginObject()
|
92
|
+
printer.PutKey("time")
|
93
|
+
printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
|
94
|
+
printer.PutKey("elapsed_time")
|
95
|
+
printer.PutFloatFmt((float64(cur_rec.Time.UnixNano())-float64(init_rec.Time.UnixNano()))/1e9,
|
96
|
+
"%.3f")
|
97
|
+
|
84
98
|
if cur_rec.Cpu != nil {
|
85
|
-
err := showCpuStat(
|
99
|
+
err := showCpuStat(printer, prev_rec, cur_rec)
|
86
100
|
if err != nil {
|
87
101
|
return err
|
88
102
|
}
|
89
103
|
}
|
90
104
|
if cur_rec.Interrupt != nil {
|
91
|
-
err := showInterruptStat(
|
105
|
+
err := showInterruptStat(printer, prev_rec, cur_rec)
|
92
106
|
if err != nil {
|
93
107
|
return err
|
94
108
|
}
|
95
109
|
}
|
96
110
|
if cur_rec.Disk != nil {
|
97
|
-
err := showDiskStat(
|
111
|
+
err := showDiskStat(printer, prev_rec, cur_rec)
|
98
112
|
if err != nil {
|
99
113
|
return err
|
100
114
|
}
|
101
115
|
}
|
102
116
|
if cur_rec.Net != nil {
|
103
|
-
err := showNetStat(
|
117
|
+
err := showNetStat(printer, prev_rec, cur_rec)
|
104
118
|
if err != nil {
|
105
119
|
return err
|
106
120
|
}
|
107
121
|
}
|
108
|
-
|
122
|
+
|
123
|
+
printer.FinishObject()
|
109
124
|
|
110
125
|
return nil
|
111
126
|
}
|
112
127
|
|
128
|
+
func parseArgs() {
|
129
|
+
flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
|
130
|
+
flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
|
131
|
+
|
132
|
+
flag.Parse()
|
133
|
+
|
134
|
+
option.logfile = flag.Arg(0)
|
135
|
+
}
|
136
|
+
|
113
137
|
func main() {
|
114
|
-
args := os.Args
|
115
138
|
var in *os.File
|
116
139
|
var out *bufio.Writer
|
117
140
|
|
118
|
-
|
141
|
+
parseArgs()
|
142
|
+
|
143
|
+
if option.logfile == "" {
|
119
144
|
in = os.Stdin
|
120
145
|
} else {
|
121
|
-
f, err := os.Open(
|
146
|
+
f, err := os.Open(option.logfile)
|
122
147
|
if err != nil {
|
123
148
|
panic(err)
|
124
149
|
}
|
@@ -159,9 +184,10 @@ func main() {
|
|
159
184
|
} else if err != nil {
|
160
185
|
panic(err)
|
161
186
|
}
|
187
|
+
init_rec = records[curr]
|
162
188
|
curr ^= 1
|
163
189
|
|
164
|
-
|
190
|
+
printer := projson.NewPrinter()
|
165
191
|
for {
|
166
192
|
prev_rec := &records[curr^1]
|
167
193
|
cur_rec := &records[curr]
|
@@ -173,21 +199,26 @@ func main() {
|
|
173
199
|
panic(err)
|
174
200
|
}
|
175
201
|
|
176
|
-
err = showStat(
|
202
|
+
err = showStat(printer, prev_rec, cur_rec)
|
177
203
|
if err != nil {
|
178
|
-
|
204
|
+
printer.Reset()
|
179
205
|
fmt.Fprintln(os.Stderr, "skip by err")
|
180
206
|
continue
|
181
207
|
}
|
182
208
|
|
183
|
-
|
209
|
+
if str, err := printer.String(); err != nil {
|
210
|
+
fmt.Println("error", err)
|
211
|
+
fmt.Println(str)
|
212
|
+
} else {
|
213
|
+
_, err = out.WriteString(str + "\n")
|
214
|
+
}
|
184
215
|
err = out.Flush()
|
185
216
|
if err != nil {
|
186
217
|
// stdout is closed
|
187
218
|
break
|
188
219
|
}
|
189
220
|
|
190
|
-
|
221
|
+
printer.Reset()
|
191
222
|
|
192
223
|
curr ^= 1
|
193
224
|
}
|