mnemonic 0.1.0

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