perfmonger 0.10.1 → 0.12.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 (45) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +9 -8
  4. data/HOWTO.md +0 -1
  5. data/NEWS +47 -3
  6. data/README.md +77 -27
  7. data/Rakefile +20 -9
  8. data/core/Makefile +10 -18
  9. data/core/build.sh +2 -2
  10. data/core/perfmonger-player.go +90 -40
  11. data/core/perfmonger-plot-formatter.go +18 -4
  12. data/core/perfmonger-recorder.go +22 -2
  13. data/core/perfmonger-summarizer.go +20 -14
  14. data/core/perfmonger-viewer.go +164 -0
  15. data/core/subsystem/Makefile +4 -0
  16. data/core/subsystem/perfmonger_linux.go +95 -0
  17. data/core/subsystem/perfmonger_linux_test.go +40 -0
  18. data/core/subsystem/stat.go +70 -0
  19. data/core/subsystem/stat_test.go +9 -0
  20. data/core/subsystem/usage.go +223 -66
  21. data/core/subsystem/usage_test.go +62 -32
  22. data/{bin → exe}/perfmonger +0 -0
  23. data/lib/perfmonger/command/fingerprint.rb +26 -1
  24. data/lib/perfmonger/command/live.rb +19 -0
  25. data/lib/perfmonger/command/play.rb +16 -0
  26. data/lib/perfmonger/command/plot.rb +25 -9
  27. data/lib/perfmonger/command/record.rb +1 -1
  28. data/lib/perfmonger/command/record_option.rb +16 -0
  29. data/lib/perfmonger/command/server.rb +1 -1
  30. data/lib/perfmonger/version.rb +1 -1
  31. data/misc/werker-box/Dockerfile +34 -0
  32. data/misc/werker-box/build-push.sh +7 -0
  33. data/perfmonger.gemspec +2 -1
  34. data/spec/data/busy100.pgr.played +3 -3
  35. data/spec/fingerprint_spec.rb +1 -1
  36. data/spec/live_spec.rb +2 -3
  37. data/spec/perfmonger_spec.rb +1 -1
  38. data/spec/play_spec.rb +1 -1
  39. data/spec/plot_spec.rb +16 -1
  40. data/spec/record_spec.rb +10 -1
  41. data/spec/spec_helper.rb +28 -3
  42. data/spec/stat_spec.rb +2 -2
  43. data/spec/summary_spec.rb +1 -1
  44. data/wercker.yml +29 -16
  45. metadata +28 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 72618bf530f76c6135a455979b3a1c19ae3cda6d
4
- data.tar.gz: af7dc56800edacccc3ee3821c011694a1f801bb3
2
+ SHA256:
3
+ metadata.gz: d54380ef057091f9d6829d3a792c0c4a91789b56077ff7a59b4a1bf063ec883e
4
+ data.tar.gz: c01127d30de0978a88bf1481357d3e20cde8193dd16e6bde9e0f2030d6423710
5
5
  SHA512:
6
- metadata.gz: 0beb12d9c14f4749076dcc27378bd9835f5447687e22ba7e0905dea390fc48b2177a7470204ebbbbf1284adf7a0207b02dd04573897687faa2f0ba52b0f923cb
7
- data.tar.gz: 1a3d334f6c02ee779bd498004f09f4f92ff217f7231adea71aee3c42c01e667939547e74c0c0acd33b29c9b5ddf60d0f9fa6f9857032465c6e71c337df15833d
6
+ metadata.gz: 8ae9ded1f5d4c5157902ccfa23a12910866834480f7b82e1464f4c2d5e767cbf2d5752118f1aa666f445d2f61a0e5cfbc7198c3ad9cf098539c0cd96a25b12f3
7
+ data.tar.gz: 3c507d05cec5b3b28e49367379846009b1848ac75d23227d22a019203190b9adeaf201a25805b3746d518d221a46399580d49899f6205f236980c70b3b73a7e5
data/.gitignore CHANGED
@@ -11,3 +11,6 @@
11
11
  /cpu.dat
12
12
  /disk.dat
13
13
  /perfmonger.pgr
14
+ /.wercker/
15
+ /spec/examples.txt
16
+ /perfmonger.pgr.gz
data/.travis.yml CHANGED
@@ -1,24 +1,25 @@
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.4.2"
7
+ - go_version="1.14.1"
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}"
15
- - go get -u golang.org/x/crypto/ssh/terminal
16
- - go get -u github.com/hayamiz/perfmonger/core/subsystem
17
14
  rvm:
18
- - 1.9.3
19
- - 2.0.0
20
- - 2.1.5
21
- - 2.2.0
15
+ - 2.4.9
16
+ - 2.5.7
17
+ - 2.6.5
18
+ - 2.7.0
22
19
  script:
20
+ - rake go_get
23
21
  - rake spec
24
22
  - rake test_core
23
+ notifications:
24
+ slack:
25
+ secure: fH8tRyxWHL60OV6QuJlzig9lCLbjfpHx8E6D2EzgQz7+/wqAxtoTUyiN7mbpEJa4hyQeZfpmMpDTnl2tHD6eI8yqjAsY4Q+jt21tCKyrKMegq9Pypd4eMP4o+DupT2mXm0K3cZ2Kgb+yP8AuJPoTy20j3kpmnDFWdqRnhgpBLC8=
data/HOWTO.md CHANGED
@@ -3,7 +3,6 @@
3
3
  ## TODO in release
4
4
 
5
5
  1. Make a commit for changing version number
6
- * Update version number in configure.ac
7
6
  * Add a new version number and release date to NEWS
8
7
  2. Tag the commit with name `v<VERSION>` ex) `v0.3.0`
9
8
  3. Push tags to the github repository
data/NEWS CHANGED
@@ -1,5 +1,49 @@
1
- ## 2017-09-08: PerfMonger 0.10.1
2
- * Yanked wrongly shipped v0.10.0 and pushed up-to-date code
1
+ ## 20XX-XX-XX: PerfMonger 0.13.0
2
+
3
+ ## 2021-05-10: PerfMonger 0.12.0
4
+ * New features
5
+ * [record] subcommand:
6
+ * Add memory usage collection
7
+
8
+ ## 2021-02-10: PerfMonger 0.11.3
9
+ * Bug fixes
10
+ * [plot] subcommand:
11
+ * Fall back to available gnuplot terminal
12
+ * Changes
13
+ * [plot] subcommand:
14
+ * Added --with-gnuplot option for specifying gnuplot binary
15
+
16
+ ## 2020-03-31: PerfMonger 0.11.2
17
+ * Bug fixes
18
+ * [plot] subcommand:
19
+ * Remove temporary directory correctly
20
+ * Changes
21
+ * CI environment
22
+ * Changed golang version to 1.14
23
+ * Dropped support of ruby older than 2.4
24
+ * Added ruby 2.6 and 2.7
25
+
26
+ ## 2018-05-15: PerfMonger 0.11.1
27
+ * Bug fixes
28
+ * [record] subcommand:
29
+ * Fixed session detection mechanism (did not worked for execution under sudo)
30
+
31
+ ## 2018-05-15: PerfMonger 0.11.0
32
+ * New features
33
+ * [play] subcommand:
34
+ * Add --color, --pretty option for pretty JSON output
35
+ * [live] subcommand:
36
+ * Add --color, --pretty option for pretty JSON output
37
+ * [fingerprint] subcommand:
38
+ * Collect additional info: numactl, ec2-metadata
39
+ * Bug fixes
40
+ * [plot] subcommand:
41
+ * Correctly filter out disk usages by --disk-only option
42
+ * Changes
43
+ * Dropped support of i386
44
+ * Use go-projson for JSON output
45
+ * [plot] subcommand:
46
+ * Stacked graphs layout in allcpu.pdf
3
47
 
4
48
  ## 2017-06-19: PerfMonger 0.10.0
5
49
  * New features
@@ -199,4 +243,4 @@ PerfMonger is available on yum repository from this release.
199
243
  ## 2011-12-09: PerfMonger 0.1.0 released
200
244
 
201
245
  * New features
202
- * I/O performance monitoring
246
+ * 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 an yet anothor performance measurement/monitoring tool
9
- speaking JSON.
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
- ## Prerequisites
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 2.2 or later, and Go 1.8 or later to build perfmonger.
30
+
31
+ bundle
30
32
  rake build
31
33
 
32
- ## How to use: case study
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 => [:self_build_core]
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,31 @@ 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
+ sh "go get -u github.com/nsf/termbox-go"
30
+ sh "go get -u github.com/jroimartin/gocui"
31
+ end
32
+
30
33
  desc "Run tests of core recorder/player"
31
- task :test_core do
34
+ task :test_core => [:cross_build_core] do
32
35
  Dir.chdir("./core/subsystem") do
33
36
  sh "go test -v -cover"
37
+
38
+ # running static analysis
39
+ sh "go vet *.go"
34
40
  end
41
+
42
+ Dir.chdir("./core") do
43
+ sh "go vet *.go"
44
+ end
45
+
35
46
  end
36
47
 
37
48
  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
 
@@ -33,6 +17,10 @@ all: build
33
17
  go build -o $@ perfmonger-player.go $(GO_SRC)
34
18
 
35
19
 
20
+ ../lib/exec/perfmonger-viewer_linux_amd64: perfmonger-viewer.go $(GO_DEPS)
21
+ go build -o $@ perfmonger-viewer.go $(GO_SRC)
22
+
23
+
36
24
  ../lib/exec/perfmonger-summarizer_linux_amd64: perfmonger-summarizer.go $(GO_DEPS)
37
25
  go build -o $@ perfmonger-summarizer.go $(GO_SRC)
38
26
 
@@ -49,6 +37,10 @@ all: build
49
37
  go build -o $@ perfmonger-player.go $(GO_SRC)
50
38
 
51
39
 
40
+ ../lib/exec/perfmonger-viewer_darwin_amd64: perfmonger-viewer.go $(GO_DEPS)
41
+ go build -o $@ perfmonger-viewer.go $(GO_SRC)
42
+
43
+
52
44
  ../lib/exec/perfmonger-summarizer_darwin_amd64: perfmonger-summarizer.go $(GO_DEPS)
53
45
  go build -o $@ perfmonger-summarizer.go $(GO_SRC)
54
46
 
@@ -57,8 +49,8 @@ all: build
57
49
  go build -o $@ perfmonger-plot-formatter.go $(GO_SRC)
58
50
 
59
51
 
60
- build: ../lib/exec/perfmonger-recorder_linux_386 ../lib/exec/perfmonger-player_linux_386 ../lib/exec/perfmonger-summarizer_linux_386 ../lib/exec/perfmonger-plot-formatter_linux_386 ../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
52
+ build: ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-viewer_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-viewer_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
61
53
 
62
54
  clean:
63
- rm -f ../lib/exec/perfmonger-recorder_linux_386 ../lib/exec/perfmonger-player_linux_386 ../lib/exec/perfmonger-summarizer_linux_386 ../lib/exec/perfmonger-plot-formatter_linux_386 ../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
55
+ rm -f ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-viewer_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-viewer_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
64
56
 
data/core/build.sh CHANGED
@@ -28,7 +28,7 @@ if [[ $1 = "-" ]]; then
28
28
  TARGET=("${os} ${arch}")
29
29
  else
30
30
  # cross build
31
- TARGET=("linux 386" "linux amd64" "darwin amd64")
31
+ TARGET=("linux amd64" "darwin amd64")
32
32
  fi
33
33
 
34
34
  set -e
@@ -57,7 +57,7 @@ for idx in $(seq 0 $((${#TARGET[@]}-1))); do
57
57
  export var_GOOS=$1
58
58
  export var_GOARCH=$2
59
59
 
60
- for subcmd in recorder player summarizer plot-formatter; do
60
+ for subcmd in recorder player viewer summarizer plot-formatter; do
61
61
  TARGETS+=(../lib/exec/perfmonger-${subcmd}_${var_GOOS}_${var_GOARCH})
62
62
 
63
63
  cat <<EOF >> $makefile
@@ -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
- func showCpuStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
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
- buffer.WriteString(`,"cpu":`)
22
- cusage.WriteJsonTo(buffer)
31
+
32
+ printer.PutKey("cpu")
33
+ cusage.WriteJsonTo(printer)
23
34
 
24
35
  return nil
25
36
  }
26
37
 
27
- func showInterruptStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
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
- buffer.WriteString(`,"intr":`)
48
- intr_usage.WriteJsonTo(buffer)
46
+ printer.PutKey("intr")
47
+ intr_usage.WriteJsonTo(printer)
49
48
 
50
49
  return nil
51
50
  }
52
51
 
53
- func showDiskStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
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
- buffer.WriteString(`,"disk":`)
62
- dusage.WriteJsonTo(buffer)
60
+ printer.PutKey("disk")
61
+
62
+ dusage.WriteJsonTo(printer)
63
63
 
64
64
  return nil
65
65
  }
66
66
 
67
- func showNetStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
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,96 @@ func showNetStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.Stat
73
73
  return err
74
74
  }
75
75
 
76
- buffer.WriteString(`,"net":`)
77
- dusage.WriteJsonTo(buffer)
76
+ printer.PutKey("net")
77
+
78
+ dusage.WriteJsonTo(printer)
79
+
80
+ return nil
81
+ }
82
+
83
+ func showMemStat(printer *projson.JsonPrinter, cur_rec *ss.StatRecord) error {
84
+ musage, err := ss.GetMemUsage(cur_rec.Mem)
85
+ if err != nil {
86
+ return err
87
+ }
88
+
89
+ printer.PutKey("mem")
90
+
91
+ musage.WriteJsonTo(printer)
78
92
 
79
93
  return nil
80
94
  }
81
95
 
82
- func showStat(buffer *bytes.Buffer, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
83
- buffer.WriteString(fmt.Sprintf(`{"time":%.3f`, float64(cur_rec.Time.UnixNano())/1e9))
96
+ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
97
+ printer.Reset()
98
+ if option.pretty {
99
+ printer.SetStyle(projson.SmartStyle)
100
+ }
101
+ if option.color {
102
+ printer.SetColor(true)
103
+ }
104
+ printer.BeginObject()
105
+ printer.PutKey("time")
106
+ printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
107
+ printer.PutKey("elapsed_time")
108
+ printer.PutFloatFmt((float64(cur_rec.Time.UnixNano())-float64(init_rec.Time.UnixNano()))/1e9,
109
+ "%.3f")
110
+
84
111
  if cur_rec.Cpu != nil {
85
- err := showCpuStat(buffer, prev_rec, cur_rec)
112
+ err := showCpuStat(printer, prev_rec, cur_rec)
86
113
  if err != nil {
87
114
  return err
88
115
  }
89
116
  }
90
117
  if cur_rec.Interrupt != nil {
91
- err := showInterruptStat(buffer, prev_rec, cur_rec)
118
+ err := showInterruptStat(printer, prev_rec, cur_rec)
92
119
  if err != nil {
93
120
  return err
94
121
  }
95
122
  }
96
123
  if cur_rec.Disk != nil {
97
- err := showDiskStat(buffer, prev_rec, cur_rec)
124
+ err := showDiskStat(printer, prev_rec, cur_rec)
98
125
  if err != nil {
99
126
  return err
100
127
  }
101
128
  }
102
129
  if cur_rec.Net != nil {
103
- err := showNetStat(buffer, prev_rec, cur_rec)
130
+ err := showNetStat(printer, prev_rec, cur_rec)
131
+ if err != nil {
132
+ return err
133
+ }
134
+ }
135
+ if cur_rec.Mem != nil {
136
+ err := showMemStat(printer, cur_rec)
104
137
  if err != nil {
105
138
  return err
106
139
  }
107
140
  }
108
- buffer.WriteString("}\n")
141
+
142
+ printer.FinishObject()
109
143
 
110
144
  return nil
111
145
  }
112
146
 
147
+ func parseArgs() {
148
+ flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
149
+ flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
150
+
151
+ flag.Parse()
152
+
153
+ option.logfile = flag.Arg(0)
154
+ }
155
+
113
156
  func main() {
114
- args := os.Args
115
157
  var in *os.File
116
158
  var out *bufio.Writer
117
159
 
118
- if len(args) < 2 {
160
+ parseArgs()
161
+
162
+ if option.logfile == "" {
119
163
  in = os.Stdin
120
164
  } else {
121
- f, err := os.Open(args[1])
165
+ f, err := os.Open(option.logfile)
122
166
  if err != nil {
123
167
  panic(err)
124
168
  }
@@ -159,9 +203,10 @@ func main() {
159
203
  } else if err != nil {
160
204
  panic(err)
161
205
  }
206
+ init_rec = records[curr]
162
207
  curr ^= 1
163
208
 
164
- buffer := bytes.NewBuffer([]byte{})
209
+ printer := projson.NewPrinter()
165
210
  for {
166
211
  prev_rec := &records[curr^1]
167
212
  cur_rec := &records[curr]
@@ -173,21 +218,26 @@ func main() {
173
218
  panic(err)
174
219
  }
175
220
 
176
- err = showStat(buffer, prev_rec, cur_rec)
221
+ err = showStat(printer, prev_rec, cur_rec)
177
222
  if err != nil {
178
- buffer.Reset()
223
+ printer.Reset()
179
224
  fmt.Fprintln(os.Stderr, "skip by err")
180
225
  continue
181
226
  }
182
227
 
183
- _, err = out.WriteString(buffer.String())
228
+ if str, err := printer.String(); err != nil {
229
+ fmt.Println("error", err)
230
+ fmt.Println(str)
231
+ } else {
232
+ _, err = out.WriteString(str + "\n")
233
+ }
184
234
  err = out.Flush()
185
235
  if err != nil {
186
236
  // stdout is closed
187
237
  break
188
238
  }
189
239
 
190
- buffer.Reset()
240
+ printer.Reset()
191
241
 
192
242
  curr ^= 1
193
243
  }