perfmonger 0.10.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }