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.
@@ -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
@@ -0,0 +1,16 @@
1
+ class Mnemonic
2
+ module Metric
3
+ class RSS < Base
4
+ require 'mnemonic/metric/rss/ps'
5
+ require 'mnemonic/metric/rss/proc_fs'
6
+
7
+ def name
8
+ 'RSS'.freeze
9
+ end
10
+
11
+ def kind
12
+ :bytes
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ class Mnemonic
2
+ class Metric::RSS::ProcFS < Metric::RSS
3
+ def initialize
4
+ @io = File.open("/proc/#{$$}/statm", 'r')
5
+ end
6
+
7
+ private
8
+
9
+ def current_value
10
+ @io.seek(0)
11
+ @io.gets.split(/\s/)[1].to_i * Util::PageSize.value
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ class Mnemonic
2
+ class Metric::RSS::PS < Metric::RSS
3
+ private
4
+
5
+ def current_value
6
+ `ps -o rss -p #{$$}`.strip.split.last.to_i * 1024
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class Mnemonic
2
+ module Metric
3
+ class Time < Base
4
+ def name
5
+ 'Time'.freeze
6
+ end
7
+
8
+ def kind
9
+ :time
10
+ end
11
+
12
+ private
13
+
14
+ def current_value
15
+ ::Time.now
16
+ end
17
+ end
18
+ end
19
+ end