perfmonger 0.10.2 → 0.11.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.
- 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
|
[](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
|
-

|
54
|
-

|
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
|
}
|