snowagent 0.0.1

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c6d857be04b5d7b819a749d04a0ee720475e6c52
4
+ data.tar.gz: 7bb635cb8d75c941e9260ca8078e9505e377cfac
5
+ SHA512:
6
+ metadata.gz: 9c3f1d237223602ae1989433db8f31fda2c5b8062a861a4fe06b28a7a58446141a3070849d13924f3db8926df5060e5853dcdece7fa51666e70aa098754f8f9c
7
+ data.tar.gz: 081c290770485a39e4b47c4f72d6edbe42387ab07509a8969baead136168fa5dba5c17d6725ca663d5322c3f925d1edb7e7cc203668d321ebbecbc974a6a9caa
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in snowagent.gemspec
4
+ gem 'pry'
5
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Artyom Keydunov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # SnowAgent
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'snowagent'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install snowagent
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/snowagent/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,45 @@
1
+ require 'json'
2
+ require 'uri'
3
+ require 'logger'
4
+
5
+ require "snowagent/version"
6
+ require "snowagent/railtie"
7
+ require "snowagent/agent"
8
+ require "snowagent/async_strategy"
9
+ require "snowagent/sync_strategy"
10
+ require "snowagent/sender"
11
+ require "snowagent/service"
12
+ require "snowagent/configuration"
13
+
14
+ module SnowAgent
15
+ class << self
16
+ attr_writer :configuration
17
+
18
+ def logger
19
+ @logger ||= Logger.new(STDOUT)
20
+ end
21
+
22
+ def configuration
23
+ @configuration ||= Configuration.new
24
+ end
25
+
26
+ def agent
27
+ @agent ||= Agent.new(configuration)
28
+ end
29
+
30
+ def metric(*args)
31
+ if configuration.configured?
32
+ agent.metric(*args)
33
+ else
34
+ # logger.debug "Metric was not send due to configuration."
35
+ end
36
+
37
+ nil
38
+ end
39
+
40
+ def configure
41
+ yield(configuration)
42
+ self.agent
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ module SnowAgent
2
+ class Agent
3
+ def initialize(configuration)
4
+ strategy_class = configuration.async ? AsyncStrategy : SyncStrategy
5
+ @strategy = strategy_class.new(configuration)
6
+ end
7
+
8
+ Metric = Struct.new(:name, :value, :kind, :at)
9
+
10
+ def metric(key, value, kind = nil, time = Time.now.to_i)
11
+ @strategy.metric(Metric.new(key, value, kind, time))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ module SnowAgent
2
+ class AsyncStrategy
3
+ def initialize(configuration)
4
+ @queue = Queue.new
5
+ run_sender(configuration)
6
+ end
7
+
8
+ def run_sender(conf)
9
+ sender_thread = Thread.new { Sender.new(@queue, conf).run }
10
+ sender_thread.abort_on_exception = true
11
+ end
12
+
13
+ def metric(metric)
14
+ @queue.push(metric)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module SnowAgent
2
+ class Configuration
3
+ # Base URL of the SnowmanIO server
4
+ attr_accessor :server
5
+
6
+ # Secret access token for authentication with SnowmanIO
7
+ attr_accessor :secret_token
8
+
9
+ # Interval for reporting data to the server
10
+ attr_accessor :send_interval
11
+
12
+ # Timeout when waiting for the server to return data in seconds
13
+ attr_accessor :read_timeout
14
+
15
+ # Timout when opening connection to the server
16
+ attr_accessor :open_timeout
17
+
18
+ # Whether send metrics asynchronously or not
19
+ attr_accessor :async
20
+
21
+ def initialize
22
+ self.server = ENV['SNOWMANIO_SERVER']
23
+ self.secret_token = ENV['SNOWMANIO_SECRET_TOKEN']
24
+ self.send_interval = 15
25
+
26
+ self.read_timeout = 1
27
+ self.open_timeout = 1
28
+
29
+ self.async = true
30
+ end
31
+
32
+ # Determines if the agent confiured to send metrics.
33
+ def configured?
34
+ !server.nil? # TODO: also check secret_token token
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require "rails/railtie"
2
+
3
+ module SnowAgent
4
+ class Railtie < Rails::Railtie
5
+ initializer "snowagent.subscribe_notifications" do
6
+ ActiveSupport::Notifications.subscribe /process_action.action_controller/ do |*args|
7
+ event = ActiveSupport::Notifications::Event.new(*args)
8
+ controller = event.payload[:controller]
9
+ action = event.payload[:action]
10
+ duration = event.duration/1000.0
11
+
12
+ # Send only 'request' metric for now
13
+
14
+ #SnowAgent.metric("#{controller}##{action}.total_time", duration, :specific_request)
15
+ SnowAgent.metric("request", duration, :request)
16
+
17
+ # TODO: don't send these metrics so frequent and so ugly
18
+ #SnowAgent.metric("controlles", ApplicationController.subclasses.size, :controllers)
19
+ #SnowAgent.metric("models", ActiveRecord::Base.subclasses.size, :models)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ module SnowAgent
2
+ class Sender
3
+ def initialize(queue, conf)
4
+ @queue = queue
5
+ @service = Service.new(conf)
6
+ @conf = conf
7
+ @metrics = []
8
+ @send_at = Time.now.to_i + @conf.send_interval
9
+ end
10
+
11
+ def run
12
+ loop { process }
13
+ end
14
+
15
+ def process
16
+ # Pop metrics from the queue
17
+ while !@queue.empty?
18
+ @metrics << @queue.pop
19
+ end
20
+
21
+ if @send_at <= Time.now.to_i
22
+ @send_at = Time.now.to_i + @conf.send_interval
23
+ send_data if @metrics.any?
24
+ end
25
+
26
+ sleep 1
27
+ end
28
+
29
+ def send_data
30
+ # TODO:
31
+ # * requeue data on failure
32
+ @service.post_data({ metrics: @metrics.map(&:to_h) })
33
+
34
+ @metrics.clear
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ module SnowAgent
2
+ # Encapsulates HTTP related logic for sending data
3
+ # to SnowmanIO instance
4
+ # TODO: use faraday instead of raw net/http?
5
+ class Service
6
+ def initialize(conf)
7
+ @uri = URI.join(conf.server, "agent/metrics")
8
+ @connection = build_connection(conf)
9
+ @token = conf.secret_token
10
+ end
11
+
12
+ def post_data(payload)
13
+ req = Net::HTTP::Post.new("#{@uri.path}?#{@uri.query}")
14
+ req.body = JSON.dump(payload.merge(token: @token))
15
+ size = req.body.length
16
+
17
+ response = @connection.request(req)
18
+ SnowAgent.logger.debug "POST #{size} bytes to #{@uri}"
19
+
20
+ response
21
+ end
22
+
23
+ def build_connection(conf)
24
+ http = Net::HTTP.new(@uri.host, @uri.port)
25
+
26
+ http.use_ssl = (@uri.scheme == "https")
27
+ http.read_timeout = conf.read_timeout if conf.read_timeout
28
+ http.open_timeout = conf.open_timeout if conf.open_timeout
29
+
30
+ http
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ module SnowAgent
2
+ class SyncStrategy
3
+ def initialize(configuration)
4
+ @service = Service.new(configuration)
5
+ end
6
+
7
+ def metric(metric)
8
+ @service.post_data({ metrics: [metric.to_h]})
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module SnowAgent
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'snowagent/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "snowagent"
8
+ spec.version = SnowAgent::VERSION
9
+ spec.authors = ["Alexey Vakhov", "Artyom Keydunov"]
10
+ spec.email = ["artyom.keydunov@gmail.com"]
11
+ spec.summary = %q{Send metrics to snowman}
12
+ spec.description = %q{Send metrics to snowman}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rails"
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snowagent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Vakhov
8
+ - Artyom Keydunov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-02-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.7'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.7'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ description: Send metrics to snowman
57
+ email:
58
+ - artyom.keydunov@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/snowagent.rb
69
+ - lib/snowagent/agent.rb
70
+ - lib/snowagent/async_strategy.rb
71
+ - lib/snowagent/configuration.rb
72
+ - lib/snowagent/railtie.rb
73
+ - lib/snowagent/sender.rb
74
+ - lib/snowagent/service.rb
75
+ - lib/snowagent/sync_strategy.rb
76
+ - lib/snowagent/version.rb
77
+ - snowagent.gemspec
78
+ homepage: ''
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.5
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Send metrics to snowman
102
+ test_files: []