mnemonic 0.1.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 +7 -0
- data/.gitignore +35 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +43 -0
- data/LICENSE +22 -0
- data/README.md +47 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +7 -0
- data/examples/gc_stat.rb +13 -0
- data/examples/instances.rb +23 -0
- data/examples/logger.rb +30 -0
- data/examples/rss.rb +13 -0
- data/examples/to_csv.rb +39 -0
- data/examples/to_json.rb +17 -0
- data/lib/mnemonic.rb +74 -0
- data/lib/mnemonic/config.rb +62 -0
- data/lib/mnemonic/logger_proxy.rb +91 -0
- data/lib/mnemonic/metric.rb +14 -0
- data/lib/mnemonic/metric/base.rb +30 -0
- data/lib/mnemonic/metric/gc_stat.rb +50 -0
- data/lib/mnemonic/metric/hash_metric.rb +54 -0
- data/lib/mnemonic/metric/instances_count.rb +20 -0
- data/lib/mnemonic/metric/instances_size.rb +20 -0
- data/lib/mnemonic/metric/objects_count.rb +48 -0
- data/lib/mnemonic/metric/objects_size.rb +47 -0
- data/lib/mnemonic/metric/rss.rb +16 -0
- data/lib/mnemonic/metric/rss/proc_fs.rb +14 -0
- data/lib/mnemonic/metric/rss/ps.rb +9 -0
- data/lib/mnemonic/metric/time.rb +19 -0
- data/lib/mnemonic/metric/time_milliseconds.rb +19 -0
- data/lib/mnemonic/metric/time_seconds.rb +19 -0
- data/lib/mnemonic/sink.rb +8 -0
- data/lib/mnemonic/sink/csv.rb +43 -0
- data/lib/mnemonic/sink/json.rb +41 -0
- data/lib/mnemonic/sink/pretty.rb +89 -0
- data/lib/mnemonic/util.rb +6 -0
- data/lib/mnemonic/util/os.rb +27 -0
- data/lib/mnemonic/util/page_size.rb +24 -0
- data/lib/mnemonic/version.rb +3 -0
- data/mnemonic.gemspec +23 -0
- metadata +141 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'monitor'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
class Mnemonic
|
6
|
+
class LoggerProxy
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def initialize(logger, mnemonic = Mnemonic.new(&proc))
|
10
|
+
super()
|
11
|
+
@monitor = Monitor.new
|
12
|
+
@logger = logger
|
13
|
+
@mnemonic = mnemonic
|
14
|
+
enable_mnemonic!
|
15
|
+
end
|
16
|
+
|
17
|
+
def enable_mnemonic!
|
18
|
+
@monitor.synchronize do
|
19
|
+
@sink = @mnemonic.attach_pretty(@logger)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def disable_mnemonic!
|
24
|
+
@monitor.synchronize do
|
25
|
+
@mnemonic.detach(@sink)
|
26
|
+
@sink = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def mnemonic_enabled?
|
31
|
+
@monitor.synchronize { !!@sink }
|
32
|
+
end
|
33
|
+
|
34
|
+
def_delegators :@logger,
|
35
|
+
:level,
|
36
|
+
:level=,
|
37
|
+
:formatter,
|
38
|
+
:formatter=,
|
39
|
+
:datetime_format,
|
40
|
+
:datetime_format=
|
41
|
+
|
42
|
+
[
|
43
|
+
:debug,
|
44
|
+
:info,
|
45
|
+
:warn,
|
46
|
+
:error,
|
47
|
+
:fatal,
|
48
|
+
:unknown
|
49
|
+
].each do |name|
|
50
|
+
severity = Logger.const_get(name.to_s.upcase)
|
51
|
+
define_method(name) do |progname = nil, &block|
|
52
|
+
add(severity, nil, progname, &block)
|
53
|
+
end
|
54
|
+
def_delegator :@logger, "#{name}?"
|
55
|
+
end
|
56
|
+
|
57
|
+
def add(severity, message = nil, progname = nil, &block)
|
58
|
+
@monitor.synchronize do
|
59
|
+
@logger.add(severity, message, progname, &block).tap do |result|
|
60
|
+
@mnemonic.trigger! if result && @sink && severity >= @logger.level
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
alias_method :log, :add
|
65
|
+
|
66
|
+
def <<(msg)
|
67
|
+
@monitor.synchronize do
|
68
|
+
@logger << msg
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def close
|
73
|
+
@monitor.synchronize do
|
74
|
+
disable_mnemonic!
|
75
|
+
@logger.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def method_missing(method_name, *args, &block)
|
80
|
+
if @logger.respond_to? method_name
|
81
|
+
@logger.send(method_name, *args, &block)
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def respond_to?(method_name, include_private = false)
|
88
|
+
@logger.respond_to?(method_name) || super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
require 'mnemonic/metric/base'
|
4
|
+
require 'mnemonic/metric/hash_metric'
|
5
|
+
require 'mnemonic/metric/rss'
|
6
|
+
require 'mnemonic/metric/time'
|
7
|
+
require 'mnemonic/metric/time_milliseconds'
|
8
|
+
require 'mnemonic/metric/gc_stat'
|
9
|
+
require 'mnemonic/metric/objects_count'
|
10
|
+
require 'mnemonic/metric/objects_size'
|
11
|
+
require 'mnemonic/metric/instances_count'
|
12
|
+
require 'mnemonic/metric/instances_size'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class Base
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :start_value, :prev_value, :value
|
6
|
+
attr_reader :diff, :diff_from_start
|
7
|
+
|
8
|
+
def start!
|
9
|
+
@start_value = @value = current_value
|
10
|
+
end
|
11
|
+
|
12
|
+
def refresh!
|
13
|
+
@prev_value = @value
|
14
|
+
@value = current_value
|
15
|
+
@diff = @value - @prev_value
|
16
|
+
@diff_from_start = @value - @start_value
|
17
|
+
end
|
18
|
+
|
19
|
+
def each_submetric
|
20
|
+
yield self
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def current_value
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class GCStat < HashMetric
|
4
|
+
def initialize(*keys)
|
5
|
+
keys = DEFAULT_KEYS if keys.empty?
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
'GCStat'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def refresh_hash!
|
16
|
+
GC.stat(@current_hash_value)
|
17
|
+
end
|
18
|
+
|
19
|
+
KIND_TABLE = {
|
20
|
+
:count => :number,
|
21
|
+
:heap_allocated_pages => :number,
|
22
|
+
:heap_sorted_length => :number,
|
23
|
+
:heap_allocatable_pages => :number,
|
24
|
+
:heap_available_slots => :number,
|
25
|
+
:heap_live_slots => :number,
|
26
|
+
:heap_free_slots => :number,
|
27
|
+
:heap_final_slots => :number,
|
28
|
+
:heap_marked_slots => :number,
|
29
|
+
:heap_swept_slots => :number,
|
30
|
+
:heap_eden_pages => :number,
|
31
|
+
:heap_tomb_pages => :number,
|
32
|
+
:total_allocated_pages => :number,
|
33
|
+
:total_freed_pages => :number,
|
34
|
+
:total_allocated_objects => :number,
|
35
|
+
:total_freed_objects => :number,
|
36
|
+
:malloc_increase_bytes => :bytes,
|
37
|
+
:malloc_increase_bytes_limit => :bytes,
|
38
|
+
:minor_gc_count => :number,
|
39
|
+
:major_gc_count => :number,
|
40
|
+
:remembered_wb_unprotected_objects => :number,
|
41
|
+
:remembered_wb_unprotected_objects_limit => :number,
|
42
|
+
:old_objects => :bytes,
|
43
|
+
:old_objects_limit => :bytes,
|
44
|
+
:oldmalloc_increase_bytes => :number,
|
45
|
+
:oldmalloc_increase_bytes_limit => :number
|
46
|
+
}
|
47
|
+
DEFAULT_KEYS = KIND_TABLE.keys
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class HashMetric
|
4
|
+
class Submetric < Base
|
5
|
+
attr_reader :kind
|
6
|
+
|
7
|
+
def initialize(parent, key, kind)
|
8
|
+
@parent = parent
|
9
|
+
@key = key
|
10
|
+
@name = "#{parent.name}(#{key.inspect})"
|
11
|
+
@kind = kind
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def current_value
|
17
|
+
@parent[@key]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(*keys)
|
22
|
+
@current_hash_value = {}
|
23
|
+
kind_table = self.class.const_get(:KIND_TABLE)
|
24
|
+
@submetrics = keys.map do |key|
|
25
|
+
Submetric.new(self, key, kind_table[key])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def start!
|
30
|
+
refresh_hash!
|
31
|
+
@submetrics.each(&:start!)
|
32
|
+
end
|
33
|
+
|
34
|
+
def refresh!
|
35
|
+
refresh_hash!
|
36
|
+
@submetrics.each(&:refresh!)
|
37
|
+
end
|
38
|
+
|
39
|
+
def each_submetric(&block)
|
40
|
+
@submetrics.each(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def [](key)
|
44
|
+
@current_hash_value[key]
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def refresh_hash!
|
50
|
+
raise NotImplementedError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class InstancesCount < Base
|
4
|
+
def initialize(klass)
|
5
|
+
@enum = ObjectSpace.each_object(klass)
|
6
|
+
@name = "Count(#{klass.name || klass.inspect})"
|
7
|
+
end
|
8
|
+
|
9
|
+
def kind
|
10
|
+
:number
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def current_value
|
16
|
+
@enum.count
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class InstancesSize < Base
|
4
|
+
def initialize(klass)
|
5
|
+
@klass = klass
|
6
|
+
@name = "Size(#{klass.name || klass.inspect})"
|
7
|
+
end
|
8
|
+
|
9
|
+
def kind
|
10
|
+
:bytes
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def current_value
|
16
|
+
ObjectSpace.memsize_of_all(@klass)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class ObjectsCount < HashMetric
|
4
|
+
def initialize(*keys)
|
5
|
+
keys = DEFAULT_KEYS if keys.empty?
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
'Count'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def kind
|
14
|
+
:number
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def refresh_hash!
|
20
|
+
ObjectSpace.count_objects(@current_hash_value)
|
21
|
+
end
|
22
|
+
|
23
|
+
KIND_TABLE = {
|
24
|
+
:TOTAL => :number,
|
25
|
+
:FREE => :number,
|
26
|
+
:T_OBJECT => :number,
|
27
|
+
:T_CLASS => :number,
|
28
|
+
:T_MODULE => :number,
|
29
|
+
:T_FLOAT => :number,
|
30
|
+
:T_STRING => :number,
|
31
|
+
:T_REGEXP => :number,
|
32
|
+
:T_ARRAY => :number,
|
33
|
+
:T_HASH => :number,
|
34
|
+
:T_STRUCT => :number,
|
35
|
+
:T_BIGNUM => :number,
|
36
|
+
:T_FILE => :number,
|
37
|
+
:T_DATA => :number,
|
38
|
+
:T_MATCH => :number,
|
39
|
+
:T_COMPLEX => :number,
|
40
|
+
:T_RATIONAL => :number,
|
41
|
+
:T_SYMBOL => :number,
|
42
|
+
:T_NODE => :number,
|
43
|
+
:T_ICLASS => :number
|
44
|
+
}
|
45
|
+
DEFAULT_KEYS = KIND_TABLE.keys
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
module Metric
|
3
|
+
class ObjectsSize < HashMetric
|
4
|
+
def initialize(*keys)
|
5
|
+
keys = DEFAULT_KEYS if keys.empty?
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
'Size'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def kind
|
14
|
+
:bytes
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def refresh_hash!
|
20
|
+
ObjectSpace.count_objects_size(@current_hash_value)
|
21
|
+
end
|
22
|
+
|
23
|
+
KIND_TABLE = {
|
24
|
+
:T_OBJECT => :bytes,
|
25
|
+
:T_CLASS => :bytes,
|
26
|
+
:T_MODULE => :bytes,
|
27
|
+
:T_FLOAT => :bytes,
|
28
|
+
:T_STRING => :bytes,
|
29
|
+
:T_REGEXP => :bytes,
|
30
|
+
:T_ARRAY => :bytes,
|
31
|
+
:T_HASH => :bytes,
|
32
|
+
:T_STRUCT => :bytes,
|
33
|
+
:T_BIGNUM => :bytes,
|
34
|
+
:T_FILE => :bytes,
|
35
|
+
:T_DATA => :bytes,
|
36
|
+
:T_MATCH => :bytes,
|
37
|
+
:T_COMPLEX => :bytes,
|
38
|
+
:T_RATIONAL => :bytes,
|
39
|
+
:T_SYMBOL => :bytes,
|
40
|
+
:T_NODE => :bytes,
|
41
|
+
:T_ICLASS => :bytes,
|
42
|
+
:TOTAL => :bytes
|
43
|
+
}
|
44
|
+
DEFAULT_KEYS = KIND_TABLE.keys
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|