mnemonic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 11af3b3be9c8bbfc7f2f894153f15d43fd17f24f
|
4
|
+
data.tar.gz: 1ab4eebad3666c8375fcf688de6103fc431b4c90
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 591b470a1fc840c66068c6f697c82cddc267126c7aa3ecfccc00a5d3086d50556d864028434ba27f9cedbc4228c87d493978c1631658097ed06a206a43c8c458
|
7
|
+
data.tar.gz: 972c5ff51b863f6b5c6f88860b7da359d649ddf21c36d0e499c076ea4621b4164cd99c087218433761fa2219fcaf6f0668aca2a16beaef5df5425f84081045b5
|
data/.gitignore
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/vendor/bundle
|
26
|
+
/lib/bundler/man/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
# Gemfile.lock
|
31
|
+
# .ruby-version
|
32
|
+
# .ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mnemonic (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
coderay (1.1.0)
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
method_source (0.8.2)
|
12
|
+
pry (0.10.3)
|
13
|
+
coderay (~> 1.1.0)
|
14
|
+
method_source (~> 0.8.1)
|
15
|
+
slop (~> 3.4)
|
16
|
+
rake (10.4.2)
|
17
|
+
rspec (3.4.0)
|
18
|
+
rspec-core (~> 3.4.0)
|
19
|
+
rspec-expectations (~> 3.4.0)
|
20
|
+
rspec-mocks (~> 3.4.0)
|
21
|
+
rspec-core (3.4.0)
|
22
|
+
rspec-support (~> 3.4.0)
|
23
|
+
rspec-expectations (3.4.0)
|
24
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
25
|
+
rspec-support (~> 3.4.0)
|
26
|
+
rspec-mocks (3.4.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.4.0)
|
29
|
+
rspec-support (3.4.0)
|
30
|
+
slop (3.6.0)
|
31
|
+
|
32
|
+
PLATFORMS
|
33
|
+
ruby
|
34
|
+
|
35
|
+
DEPENDENCIES
|
36
|
+
bundler (~> 1.10)
|
37
|
+
mnemonic!
|
38
|
+
pry
|
39
|
+
rake (~> 10.0)
|
40
|
+
rspec
|
41
|
+
|
42
|
+
BUNDLED WITH
|
43
|
+
1.10.6
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Alexey Gaziev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# mnemonic - The best tool to find leakage
|
2
|
+
|
3
|
+
If you know (or even just think) that your application is leaking, but you having hard times with figuring out
|
4
|
+
what exactly is leaking, when and why – this tool will help you to figure this out.
|
5
|
+
|
6
|
+
<a href="https://evilmartians.com/?utm_source=gon">
|
7
|
+
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
|
8
|
+
</a>
|
9
|
+
|
10
|
+
## How it works
|
11
|
+
|
12
|
+
Сейчас у мнемоника есть два режима работы –
|
13
|
+
|
14
|
+
1. Полуавтоматический, когда вы добавляете в нужных вам местах триггеры мнемоника.
|
15
|
+
В этом режиме мнемоник будет выводить или сохранять данные каждый раз, когда
|
16
|
+
будет выполняться код триггера.
|
17
|
+
|
18
|
+
2. Автоматический, когда вы проксируете ваш логгер через прокси мнемоника.
|
19
|
+
В этом режиме мнемоник будет выводить или сохранять данные каждый раз,
|
20
|
+
когда вызывается логгер.
|
21
|
+
|
22
|
+
## Formats
|
23
|
+
|
24
|
+
Мнемоник поддерживает три формата вывода данных:
|
25
|
+
|
26
|
+
1. Pretty - красиво отформаттированный текстовый вывод данных:
|
27
|
+
скриншот
|
28
|
+
|
29
|
+
2. JSON - данные представлены в виде JSON-массива, удобно для дальнейшего анализа при
|
30
|
+
помощи внешних инструментов
|
31
|
+
пример формата
|
32
|
+
|
33
|
+
3. CSV - данные представлены в формате CSV, можно воспользоваться любым инструментом
|
34
|
+
с поддержкой импорта из csv, таким как Google Sheets и тп.
|
35
|
+
пример формата
|
36
|
+
|
37
|
+
Если вам не хватает какого-либо формата – мы будем очень рады пулл реквесту или
|
38
|
+
ишью с описанием недостающего формата.
|
39
|
+
|
40
|
+
## What and how you can track with mnemonic
|
41
|
+
|
42
|
+
Мы постарались добавить в этот инструмент все метрики, которые когда-либо
|
43
|
+
помогали нам в расследовании наших утечек. Если мы упустили что-то важное - мы
|
44
|
+
будем очень благодарны за пулл реквест или ишью с описанием метрики.
|
45
|
+
|
46
|
+
На данный момент инструмент позволяет следить за следующими показателями:
|
47
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
data/examples/gc_stat.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
mnemonic = Mnemonic.new do |config|
|
2
|
+
config.gc_stat :minor_gc_count, :major_gc_count
|
3
|
+
end
|
4
|
+
|
5
|
+
mnemonic.attach_pretty(STDOUT)
|
6
|
+
|
7
|
+
# 5 major GCs!
|
8
|
+
10.times do |i|
|
9
|
+
GC.start if i.odd?
|
10
|
+
mnemonic.trigger!(i.odd? ? 'major!' : 'no major')
|
11
|
+
end
|
12
|
+
|
13
|
+
mnemonic.detach_all
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class X
|
2
|
+
end
|
3
|
+
|
4
|
+
mnemonic = Mnemonic.new do |config|
|
5
|
+
config.time_milliseconds
|
6
|
+
config.instances_count(X)
|
7
|
+
config.instances_size(X)
|
8
|
+
end
|
9
|
+
|
10
|
+
mnemonic.attach_csv(STDOUT, extra: true)
|
11
|
+
|
12
|
+
10.times do
|
13
|
+
X.new
|
14
|
+
mnemonic.trigger!(:without_gc)
|
15
|
+
end
|
16
|
+
|
17
|
+
10.times do
|
18
|
+
X.new
|
19
|
+
GC.start
|
20
|
+
mnemonic.trigger!(:with_gc)
|
21
|
+
end
|
22
|
+
|
23
|
+
mnemonic.detach_all
|
data/examples/logger.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'mnemonic/logger_proxy'
|
2
|
+
|
3
|
+
file_name = './tmp.log'
|
4
|
+
logger = Mnemonic::LoggerProxy.new(Logger.new(file_name)) do |config|
|
5
|
+
config.objects_count(:T_HASH)
|
6
|
+
config.objects_size(:T_HASH)
|
7
|
+
config.objects_count(:T_ARRAY)
|
8
|
+
config.objects_size(:T_ARRAY)
|
9
|
+
end
|
10
|
+
|
11
|
+
10.times do
|
12
|
+
{}; {[] => []}; [] # +3 arrays, +2 hashes
|
13
|
+
logger.info 'hello with logging enabled!'
|
14
|
+
end
|
15
|
+
|
16
|
+
logger.disable_mnemonic!
|
17
|
+
|
18
|
+
10.times do
|
19
|
+
logger.info 'hello with logging disabled!'
|
20
|
+
end
|
21
|
+
|
22
|
+
logger.enable_mnemonic!
|
23
|
+
|
24
|
+
10.times do
|
25
|
+
logger.info 'hello with logging re-enabled!'
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
puts File.read(file_name)
|
data/examples/rss.rb
ADDED
data/examples/to_csv.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
file_name = './tmp.csv'
|
2
|
+
|
3
|
+
mnemonic = Mnemonic.new do |config|
|
4
|
+
config.time_milliseconds
|
5
|
+
config.objects_count(:T_HASH)
|
6
|
+
config.objects_size(:T_HASH)
|
7
|
+
end
|
8
|
+
|
9
|
+
mnemonic.attach_csv(file_name)
|
10
|
+
|
11
|
+
100.times do
|
12
|
+
Hash.new
|
13
|
+
mnemonic.trigger!
|
14
|
+
end
|
15
|
+
|
16
|
+
mnemonic.detach_all
|
17
|
+
|
18
|
+
puts File.read(file_name)
|
19
|
+
|
20
|
+
puts
|
21
|
+
puts "WITH EXTRA COLUMN"
|
22
|
+
puts
|
23
|
+
|
24
|
+
mnemonic = Mnemonic.new do |config|
|
25
|
+
config.time_milliseconds
|
26
|
+
config.objects_count(:T_HASH)
|
27
|
+
config.objects_size(:T_HASH)
|
28
|
+
end
|
29
|
+
|
30
|
+
mnemonic.attach_csv(file_name, extra: true)
|
31
|
+
|
32
|
+
100.times do |i|
|
33
|
+
Hash.new
|
34
|
+
mnemonic.trigger!(2 ** i)
|
35
|
+
end
|
36
|
+
|
37
|
+
mnemonic.detach_all
|
38
|
+
|
39
|
+
puts File.read(file_name)
|
data/examples/to_json.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
file_name = './tmp.json'
|
2
|
+
|
3
|
+
mnemonic = Mnemonic.new do |config|
|
4
|
+
config.time_milliseconds
|
5
|
+
config.objects_count(:T_HASH, :T_ARRAY)
|
6
|
+
end
|
7
|
+
|
8
|
+
mnemonic.attach_json(file_name)
|
9
|
+
|
10
|
+
10.times do
|
11
|
+
{}; {[] => []}; [] # +3 arrays, +2 hashes
|
12
|
+
mnemonic.trigger!
|
13
|
+
end
|
14
|
+
|
15
|
+
mnemonic.detach_all
|
16
|
+
|
17
|
+
puts JSON.pretty_generate(JSON.load(File.read(file_name)))
|
data/lib/mnemonic.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'objspace'
|
2
|
+
require 'monitor.rb'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
class Mnemonic
|
6
|
+
require 'mnemonic/version'
|
7
|
+
require 'mnemonic/config'
|
8
|
+
require 'mnemonic/metric'
|
9
|
+
require 'mnemonic/sink'
|
10
|
+
require 'mnemonic/util'
|
11
|
+
|
12
|
+
include MonitorMixin
|
13
|
+
|
14
|
+
attr_reader :root_metrics, :metrics, :metric_names
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
config = Mnemonic::Config.new
|
19
|
+
yield config
|
20
|
+
|
21
|
+
@root_metrics = config.metrics.map do |metric|
|
22
|
+
metric.klass.new(*metric.args)
|
23
|
+
end
|
24
|
+
|
25
|
+
@metrics = @root_metrics.flat_map do |metric|
|
26
|
+
metric.to_enum(:each_submetric).to_a
|
27
|
+
end
|
28
|
+
|
29
|
+
@root_metrics.each(&:start!)
|
30
|
+
@metric_names = @metrics.map(&:name)
|
31
|
+
@sinks = Set.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def trigger!(extra = nil)
|
35
|
+
synchronize do
|
36
|
+
@root_metrics.each(&:refresh!)
|
37
|
+
@sinks.each { |s| s.drop!(extra) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def attach_csv(*args)
|
42
|
+
attach(Sink::CSV, *args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def attach_json(*args)
|
46
|
+
attach(Sink::JSON, *args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def attach_pretty(*args)
|
50
|
+
attach(Sink::Pretty, *args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def attach(sink_class, *args, &block)
|
54
|
+
synchronize do
|
55
|
+
sink_class.new(self, *args, &block).tap do |sink|
|
56
|
+
@sinks << sink
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def detach(sink)
|
62
|
+
synchronize do
|
63
|
+
sink.close
|
64
|
+
@sinks.delete sink
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def detach_all
|
69
|
+
synchronize do
|
70
|
+
@sinks.each(&:close)
|
71
|
+
@sinks.clear
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Mnemonic
|
2
|
+
class Config
|
3
|
+
MetricDescription = Struct.new(:klass, :args)
|
4
|
+
|
5
|
+
attr_reader :metrics
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@metrics = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_metric(klass, args=nil)
|
12
|
+
@metrics << MetricDescription.new(klass, args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def gc_stat(*stat_names)
|
16
|
+
add_metric Metric::GCStat, stat_names
|
17
|
+
end
|
18
|
+
|
19
|
+
def objects_count(*object_types)
|
20
|
+
add_metric Metric::ObjectsCount, object_types
|
21
|
+
end
|
22
|
+
|
23
|
+
def objects_size(*object_types)
|
24
|
+
add_metric Metric::ObjectsSize, object_types
|
25
|
+
end
|
26
|
+
|
27
|
+
def instances_count(*target_klass_names)
|
28
|
+
target_klass_names.each do |klass_name|
|
29
|
+
add_metric Metric::InstancesCount, klass_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def instances_size(*target_klass_names)
|
34
|
+
target_klass_names.each do |klass_name|
|
35
|
+
add_metric Metric::InstancesSize, klass_name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def time_seconds
|
40
|
+
add_metric Metric::TimeSeconds
|
41
|
+
end
|
42
|
+
|
43
|
+
def time_milliseconds
|
44
|
+
add_metric Metric::TimeMilliseconds
|
45
|
+
end
|
46
|
+
|
47
|
+
def time
|
48
|
+
add_metric Metric::Time
|
49
|
+
end
|
50
|
+
|
51
|
+
def rss
|
52
|
+
# TODO: finish!
|
53
|
+
klass = case Util::OS.type
|
54
|
+
when :linux
|
55
|
+
Metric::RSS::ProcFS
|
56
|
+
else
|
57
|
+
Metric::RSS::PS
|
58
|
+
end
|
59
|
+
add_metric klass
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|