mnemonic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mnemonic.gemspec
4
+ gemspec
@@ -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
+
@@ -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
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mnemonic"
5
+
6
+ require "pry"
7
+ Pry.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -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
@@ -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)
@@ -0,0 +1,13 @@
1
+ mnemonic = Mnemonic.new do |config|
2
+ config.rss
3
+ end
4
+
5
+ mnemonic.attach_pretty(STDOUT)
6
+
7
+ # 5 major GCs!
8
+ 10.times do |i|
9
+ '!' * 1_000_000
10
+ mnemonic.trigger!
11
+ end
12
+
13
+ mnemonic.detach_all
@@ -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)
@@ -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)))
@@ -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