evenitron 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.
data/README.markdown ADDED
@@ -0,0 +1,65 @@
1
+ # Setting up with delayed_job
2
+
3
+ There are two options for setting up Evenitron to monitor your delayed_job tasks.
4
+
5
+ Firstly, add the gem to your Gemfile:
6
+
7
+ ```ruby
8
+ gem 'evenitron-ruby', :git => 'git@github.com:evenitron/evenitron-ruby.git'
9
+ ```
10
+
11
+ *We'll use the git references if possible until things are public.*
12
+
13
+ Then you need to configure it within your `boot.rb` for Rails (I have no idea if this is the right file but it works). You can either do this explicitly:
14
+
15
+ ```ruby
16
+ require 'evenitron/delayed_job'
17
+
18
+ Evenitron::DelayedJob.configure do
19
+ system_key 'benchmarking'
20
+ # collector_url 'http://localhost:5000/'
21
+ end
22
+ ```
23
+
24
+ Or you can rely on the environment variables `EVENITRON_SYSTEM_KEY` and `EVENITRON_COLLECTOR_URL`:
25
+
26
+ ```ruby
27
+ require 'evenitron/delayed_job'
28
+
29
+ Evenitron::DelayedJob.configure
30
+ ```
31
+
32
+ You must specify your system key either through configuration or the `EVENITRON_SYSTEM_KEY` environment variable but you will normally rely on the default collector URL of `https://collector.evenitron.com/`.
33
+
34
+ # Setting up with resque
35
+
36
+ There are two options for setting up Evenitron to monitor your delayed_job tasks.
37
+
38
+ Firstly, add the gem to your Gemfile:
39
+
40
+ ```ruby
41
+ gem 'evenitron-ruby', :git => 'git@github.com:evenitron/evenitron-ruby.git'
42
+ ```
43
+
44
+ *We'll use the git references if possible until things are public.*
45
+
46
+ Then you need to configure it within your `boot.rb` for Rails (I have no idea if this is the right file but it works). You can either do this explicitly:
47
+
48
+ ```ruby
49
+ require 'evenitron/resque'
50
+
51
+ Evenitron::Resque.configure do
52
+ system_key 'benchmarking'
53
+ # collector_url 'http://localhost:5000/'
54
+ end
55
+ ```
56
+
57
+ Or you can rely on the environment variables `EVENITRON_SYSTEM_KEY` and `EVENITRON_COLLECTOR_URL`:
58
+
59
+ ```ruby
60
+ require 'evenitron/resque'
61
+
62
+ Evenitron::Resque.configure
63
+ ```
64
+
65
+ You must specify your system key either through configuration or the `EVENITRON_SYSTEM_KEY` environment variable but you will normally rely on the default collector URL of `https://collector.evenitron.com/`.
@@ -0,0 +1,76 @@
1
+ module Evenitron
2
+
3
+ class CollectorClient
4
+
5
+ include Evenitron::Logger
6
+
7
+ DEFAULT_URL = "https://collector.evenitron.com/"
8
+
9
+ def initialize(system_key, url = DEFAULT_URL, component = nil)
10
+ @system_key = system_key
11
+ @url = url
12
+ @user_agent = 'evenitron-ruby 0.1'
13
+ @user_agent = "#{@user_agent} (#{component})" if component
14
+ @simulate_requests = ENV['EVENITRON_SIMULATE_REQUESTS'] == 'true'
15
+ log.warn 'Simulating Evenitron messages' if @simulate_requests
16
+ end
17
+
18
+ def job_queued(args)
19
+ send_message :queued, args
20
+ end
21
+
22
+ def job_started(args)
23
+ send_message :started, args
24
+ end
25
+
26
+ def job_failed(args)
27
+ send_message :failed, args
28
+ end
29
+
30
+ def job_complete(args)
31
+ send_message :complete, args
32
+ end
33
+
34
+ private
35
+
36
+ def send_message(stage, args)
37
+ send message(stage, args)
38
+ end
39
+
40
+ def send(msg)
41
+ json = msg.to_json
42
+
43
+ if @simulate_requests
44
+ log.info "Simulating message for #{@system_key} to #{@url} - #{json}"
45
+ return nil
46
+ else
47
+ log.debug "Sending message for #{@system_key} to #{@url} - #{json}"
48
+ end
49
+
50
+ Thread.new do
51
+ begin
52
+ RestClient.post @url, json, :content_type => nil, 'Evenitron-Key' => @system_key, 'User-Agent' => @user_agent
53
+ rescue => e
54
+ log.error "Failed to send message for #{@system_key} to #{@url} - #{json}"
55
+ log.debug e
56
+ end
57
+ end
58
+
59
+ nil
60
+ end
61
+
62
+ def message(stage, args)
63
+ msg = args.dup
64
+ msg[:stage] = stage
65
+ msg[:version] = 1
66
+ msg[:timestamp] = since_epoch(Time.now)
67
+ msg
68
+ end
69
+
70
+ def since_epoch(time)
71
+ (time.to_f * 1000).to_i
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,112 @@
1
+ require_relative '../evenitron'
2
+ require 'delayed_job'
3
+
4
+ module Evenitron
5
+
6
+ module DelayedJob
7
+
8
+ def self.configure(&block)
9
+ dj = Evenitron::DelayedJobCollector.new
10
+ dj.configure &block unless block.nil?
11
+ dj.start!
12
+ nil
13
+ end
14
+
15
+ end
16
+
17
+ class DelayedJobCollector
18
+
19
+ include Evenitron::Logger
20
+
21
+ def initialize
22
+ @collector_url = ENV['EVENITRON_COLLECTOR_URL']
23
+ @system_key = ENV['EVENITRON_SYSTEM_KEY']
24
+ end
25
+
26
+ def configure(&block)
27
+ instance_eval &block
28
+ end
29
+
30
+ def system_key(key)
31
+ @system_key = key
32
+ end
33
+
34
+ def api_key(key)
35
+ @api_key = key
36
+ end
37
+
38
+ def collector_url(url)
39
+ @collector_url = url
40
+ end
41
+
42
+ def start!
43
+ log.info "Registering delayed_job evenitron collector with system key #{@system_key} to send messages to #{@collector_url}"
44
+ @client = Evenitron::CollectorClient.new @system_key, @collector_url, 'dj'
45
+ register_lifecycle_hooks
46
+ end
47
+
48
+ private
49
+
50
+ def lifecycle
51
+ Delayed::Worker.lifecycle
52
+ end
53
+
54
+ def register_lifecycle_hooks
55
+ log.info "Registering delayed_job job queued callback"
56
+ lifecycle.around :enqueue do |job, &block|
57
+ result = block.call(job)
58
+ job_queued job
59
+ result
60
+ end
61
+
62
+ log.info "Registering delayed_job job failed callback"
63
+ lifecycle.before :failure do |worker, job|
64
+ job_failed job
65
+ end
66
+
67
+ log.info "Registering delayed_job job requeued callback"
68
+ lifecycle.after :error do |worker, job|
69
+ job_queued job unless job.failed? or job.frozen?
70
+ end
71
+
72
+ log.info "Registering delayed_job job started callback"
73
+ log.info "Registering delayed_job job complete callback"
74
+ lifecycle.around :perform do |worker, job, &block|
75
+ job_started job, worker
76
+ result = block.call(worker, job)
77
+ job_complete job if result
78
+ result
79
+ end
80
+ end
81
+
82
+ def job_queued(job)
83
+ id = get_id(job)
84
+ log.info "Sending job queued message for job #{job.id} (evenitron id #{id})"
85
+ @client.job_queued :id => id, :queue => job.class.table_name, :task => job.name
86
+ end
87
+
88
+ def job_started(job, worker)
89
+ id = get_id(job)
90
+ log.info "Sending job started message for job #{job.id} (evenitron id #{id})"
91
+ @client.job_started :id => id, :worker => worker.name, :task => job.name
92
+ end
93
+
94
+ def job_failed(job)
95
+ id = get_id(job)
96
+ log.info "Sending job failed message for job #{job.id} (evenitron id #{id})"
97
+ @client.job_failed :id => id, :task => job.name
98
+ end
99
+
100
+ def job_complete(job)
101
+ id = get_id(job)
102
+ log.info "Sending job complete message for job #{job.id} (evenitron id #{id})"
103
+ @client.job_complete :id => id, :task => job.name
104
+ end
105
+
106
+ def get_id(job)
107
+ Evenitron.encode job.class.table_name, job.id
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,32 @@
1
+ module Evenitron
2
+
3
+ def self.logger
4
+ @@logger ||= default_logger
5
+ end
6
+
7
+ def self.logger=(logger)
8
+ @@logger = logger
9
+ end
10
+
11
+ def self.encode(*values)
12
+ value = values.join ':'
13
+ cleanse_base64 Base64.encode64(value)
14
+ end
15
+
16
+ def self.generate_id(length = 64)
17
+ cleanse_base64 SecureRandom.base64(length)
18
+ end
19
+
20
+ private
21
+
22
+ def self.default_logger
23
+ logger = ::Logger.new(STDOUT)
24
+ logger.level = ::Logger::INFO
25
+ logger
26
+ end
27
+
28
+ def self.cleanse_base64(value)
29
+ value.gsub /[\s=]/, ''
30
+ end
31
+
32
+ end
@@ -0,0 +1,11 @@
1
+ module Evenitron
2
+
3
+ module Logger
4
+
5
+ def log
6
+ Evenitron.logger
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,149 @@
1
+ require_relative '../evenitron'
2
+ require 'resque'
3
+
4
+ module Evenitron
5
+
6
+ class NullResqueCollector
7
+
8
+ include Evenitron::Logger
9
+
10
+ def job_queued(queue, item)
11
+ log.warn "EVENITRON NOT CONFIGURED : Not sending job queued message for job #{item['evenitron_id']}"
12
+ end
13
+
14
+ def job_started(job)
15
+ log.info "EVENITRON NOT CONFIGURED : Not sending job started message for job #{job.evenitron_id}"
16
+ end
17
+
18
+ def job_failed(job)
19
+ log.info "EVENITRON NOT CONFIGURED : Not sending job failed message for job #{job.evenitron_id}"
20
+ end
21
+
22
+ def job_complete(job)
23
+ log.info "EVENITRON NOT CONFIGURED : Not sending job complete message for job #{job.evenitron_id}"
24
+ end
25
+
26
+ end
27
+
28
+ module Resque
29
+
30
+ @@collector = Evenitron::NullResqueCollector.new
31
+
32
+ def self.configure(&block)
33
+ rc = Evenitron::ResqueCollector.new
34
+ rc.configure &block unless block.nil?
35
+ rc.start!
36
+ @@collector = rc
37
+ nil
38
+ end
39
+
40
+ def self.collector
41
+ @@collector
42
+ end
43
+
44
+ end
45
+
46
+ class ResqueCollector
47
+
48
+ include Evenitron::Logger
49
+
50
+ def initialize
51
+ @collector_url = ENV['EVENITRON_COLLECTOR_URL']
52
+ @system_key = ENV['EVENITRON_SYSTEM_KEY']
53
+ end
54
+
55
+ def configure(&block)
56
+ instance_eval &block
57
+ end
58
+
59
+ def system_key(key)
60
+ @system_key = key
61
+ end
62
+
63
+ def api_key(key)
64
+ @api_key = key
65
+ end
66
+
67
+ def collector_url(url)
68
+ @collector_url = url
69
+ end
70
+
71
+ def start!
72
+ log.info "Registering resque evenitron collector with system key #{@system_key} to send messages to #{@collector_url}"
73
+ @client = Evenitron::CollectorClient.new @system_key, @collector_url, 'resque'
74
+ end
75
+
76
+ def job_queued(queue, item)
77
+ id = get_id(item)
78
+ log.info "Sending job queued message for job #{id}"
79
+ @client.job_queued :id => id, :queue => queue, :task => item[:class]
80
+ end
81
+
82
+ def job_started(job)
83
+ log.info "Sending job started message for job #{job.evenitron_id}"
84
+ @client.job_started :id => job.evenitron_id, :worker => job.worker.to_s, :task => job.payload['class']
85
+ end
86
+
87
+ def job_failed(job)
88
+ log.info "Sending job failed message for job #{job.evenitron_id}"
89
+ @client.job_failed :id => job.evenitron_id, :task => job.payload['class']
90
+ end
91
+
92
+ def job_complete(job)
93
+ log.info "Sending job complete message for job #{job.evenitron_id}"
94
+ @client.job_complete :id => job.evenitron_id, :task => job.payload['class']
95
+ end
96
+
97
+ private
98
+
99
+ def get_id(item)
100
+ item['evenitron_id']
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
107
+ module Resque
108
+
109
+ class << self
110
+
111
+ alias :base_push :push
112
+
113
+ def push(queue, item)
114
+ item['evenitron_id'] ||= Evenitron.generate_id
115
+ base_push(queue, item)
116
+ Evenitron::Resque.collector.job_queued queue, item
117
+ end
118
+
119
+ end
120
+
121
+ class Job
122
+
123
+ alias :base_perform :perform
124
+
125
+ def perform
126
+ begin
127
+ Evenitron.logger.debug "Processing job #{evenitron_id}"
128
+ Evenitron::Resque.collector.job_started self
129
+
130
+ result = base_perform
131
+ Evenitron::Resque.collector.job_complete self
132
+
133
+ Evenitron.logger.debug "Processed job #{evenitron_id}, result was #{result}"
134
+ result
135
+ rescue => e
136
+ Evenitron.logger.fatal "Exception occurred whilst processing job #{evenitron_id}"
137
+ Evenitron.logger.debug e.inspect
138
+ Evenitron::Resque.collector.job_failed self
139
+ raise e
140
+ end
141
+ end
142
+
143
+ def evenitron_id
144
+ @payload['evenitron_id']
145
+ end
146
+
147
+ end
148
+
149
+ end
data/lib/evenitron.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ require 'base64'
3
+ require 'rest_client'
4
+ require 'securerandom'
5
+ require 'logger'
6
+ require 'json'
7
+
8
+ module Evenitron ; end
9
+
10
+ require_relative 'evenitron/evenitron'
11
+ require_relative 'evenitron/logger'
12
+ require_relative 'evenitron/collector_client'
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evenitron
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Evenitron
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-25 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: &70228307216040 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70228307216040
25
+ description: Ruby client for Evenitron with hooks for delayed_job and resque
26
+ email:
27
+ - support@evenitron.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/evenitron/collector_client.rb
33
+ - lib/evenitron/delayed_job.rb
34
+ - lib/evenitron/evenitron.rb
35
+ - lib/evenitron/logger.rb
36
+ - lib/evenitron/resque.rb
37
+ - lib/evenitron.rb
38
+ - README.markdown
39
+ homepage: https://github.com/evenitron/evenitron-ruby
40
+ licenses: []
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project: evenitron-ruby
59
+ rubygems_version: 1.8.15
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Ruby client for Evenitron
63
+ test_files: []
64
+ has_rdoc: