telemetry 1.0.10 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.rspec +3 -0
- data/Gemfile +0 -2
- data/LICENSE.txt +1 -1
- data/Rakefile +6 -0
- data/bin/telemetryd +32 -4
- data/lib/telemetry/api.rb +209 -0
- data/lib/telemetry/{config_parser.rb → daemon_config_parser.rb} +17 -11
- data/lib/telemetry/flows.rb +189 -0
- data/lib/telemetry/version.rb +2 -2
- data/lib/telemetry.rb +2 -5
- data/spec/batch_spec.rb +35 -0
- data/spec/daemon_spec.rb +12 -0
- data/spec/flows_spec.rb +182 -0
- data/spec/spec_helper.rb +9 -0
- data/telemetry.gemspec +4 -1
- metadata +60 -16
- data/lib/telemetry/telemetry.rb +0 -71
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjQxNzM4Y2E3NWE4ZGE1MGRhZjZmZGYwYWVjOGViYWI1NDc1MGFmOQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDg3MjY5N2MwNWM2YTQwN2EzOGM4NGNkNGFiMWYzNzkxN2E4MGY2Yg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NmYyYTE3MjVjZmNjMzM0OTFkMDkxZDI2M2JiOWM1NWMyZjQxMDdhYjE3ZDE0
|
10
|
+
MThhZTQzNTgyZGUyNTliNzU4OGM3MjA3OWY4YmVhZjZmM2JjMGYwZGE1Njdl
|
11
|
+
N2UzOTA5MDA5ODZmNWE2ODFiNzFlNmRhOTMwYjJkYzE3YmQ3N2Q=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjFkZTMxZDJkYzczODZmZmIwZDE5NDg4MTE2MzcxOGE0NGQyODM1MDlhN2Fj
|
14
|
+
OGIzZGIwNGFiNjkzZTRiMjMyMjQwNTIxYWRmMDE2YmEyZDBjM2ZjYzIyZWQ5
|
15
|
+
OWZjMzNlN2Q4NmE2OWQ3YjM1YmM5ZGY5ZThhYWE3OWMxYzc5N2M=
|
data/.rspec
ADDED
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/Rakefile
CHANGED
data/bin/telemetryd
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "dante"
|
4
|
-
|
4
|
+
|
5
|
+
require_relative "../lib/telemetry"
|
6
|
+
require_relative "../lib/telemetry/daemon_config_parser"
|
5
7
|
|
6
8
|
include Telemetry
|
7
9
|
|
8
10
|
runner = Dante::Runner.new('telemetryd', :port => 9990)
|
9
|
-
runner.description = "telemetryd #{Telemetry::
|
11
|
+
runner.description = "telemetryd #{Telemetry::TELEMETRY_VERSION}, a daemon for sending data to www.telemetryapp.com"
|
10
12
|
runner.with_options do |opts|
|
11
13
|
opts.on("-c", "--config PATH", String, "Config file location") do |config|
|
12
14
|
options[:config] = config
|
13
15
|
end
|
16
|
+
opts.on("-o", "--once", "Run once") do |o|
|
17
|
+
options[:once] = o
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
runner.execute do |opts|
|
@@ -22,7 +27,7 @@ runner.execute do |opts|
|
|
22
27
|
if File.exist?(config_file_path)
|
23
28
|
require_relative config_file_path
|
24
29
|
else
|
25
|
-
|
30
|
+
Telemetry::logger.error "Config file not found, please create /etc/telemetryd_config.rb or specify its location with -c"
|
26
31
|
exit
|
27
32
|
end
|
28
33
|
|
@@ -31,7 +36,30 @@ runner.execute do |opts|
|
|
31
36
|
start_timestamp = Time.now.to_f
|
32
37
|
Telemetry.run_begin_interval
|
33
38
|
output = Telemetry.run_scheduled_flow_updates
|
34
|
-
|
39
|
+
|
40
|
+
begin
|
41
|
+
Telemetry::Api.send(:post, "/flows", {:data => output})
|
42
|
+
|
43
|
+
rescue Telemetry::RateLimited
|
44
|
+
Telemetry::logger.error "Rate limited: sleeping for 3600s"
|
45
|
+
sleep 3600
|
46
|
+
|
47
|
+
rescue Telemetry::AuthenticationFailed => e
|
48
|
+
raise e
|
49
|
+
|
50
|
+
rescue Telemetry::AuthorizationError => e
|
51
|
+
raise e
|
52
|
+
|
53
|
+
rescue Telemetry::FormatError => e
|
54
|
+
raise e
|
55
|
+
|
56
|
+
rescue Exception => e
|
57
|
+
Telemetry::logger.error "Temporary exception (#{e}): sleeping for 60s"
|
58
|
+
sleep 60
|
59
|
+
end
|
60
|
+
|
61
|
+
exit if opts[:once]
|
62
|
+
|
35
63
|
Telemetry.run_end_interval
|
36
64
|
Telemetry.wait_for_interval_from(start_timestamp)
|
37
65
|
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
#/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'multi_json'
|
4
|
+
require 'oj'
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
require 'logger'
|
8
|
+
|
9
|
+
module Telemetry
|
10
|
+
|
11
|
+
@affiliate_id
|
12
|
+
@token = nil
|
13
|
+
|
14
|
+
def self.api_host
|
15
|
+
if ENV["RACK_ENV"] == 'development' || ENV["RACK_ENV"] == 'test'
|
16
|
+
"http://data.test.telemetryapp.com"
|
17
|
+
else
|
18
|
+
"https://data.telemetryapp.com"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.logger
|
23
|
+
@logger ||= Logger.new(STDOUT)
|
24
|
+
if ENV['RACK_ENV'] == 'development'
|
25
|
+
@logger.level = Logger::DEBUG
|
26
|
+
else
|
27
|
+
@logger.level = Logger::WARN
|
28
|
+
end
|
29
|
+
@logger
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.token
|
33
|
+
@token
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.token=(token)
|
37
|
+
@token = token
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.affiliate_id
|
41
|
+
@token
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.affiliate_id=(affiliate_id)
|
45
|
+
@affiliate_id = affiliate_id
|
46
|
+
end
|
47
|
+
|
48
|
+
class Api
|
49
|
+
|
50
|
+
def self.get_flow(id)
|
51
|
+
Telemetry::Api.send(:get, "/flows/#{id}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.get_flow_data(id)
|
55
|
+
Telemetry::Api.send(:get, "/flows/#{id}/data")
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.delete_flow_data(id)
|
59
|
+
Telemetry::Api.send(:delete, "/flows/#{id}/data")
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.flow_update(flow)
|
63
|
+
raise Telemetry::AuthenticationFailed, "Please set your Telemetry.token" unless Telemetry.token
|
64
|
+
values = flow.to_hash
|
65
|
+
tag = values.delete('tag')
|
66
|
+
result = Telemetry::Api.send(:put, "/flows/#{tag}", values)
|
67
|
+
raise ResponseError, "API Response: #{result['errors'].join(', ')}" unless result["updated"].include?(tag)
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.flow_update_batch(flows)
|
72
|
+
raise Telemetry::AuthenticationFailed, "Please set your Telemetry.token" unless Telemetry.token
|
73
|
+
raise RuntimeError, "Must supply flows to send" if flows == 0 || flows.count == 0
|
74
|
+
data = {}
|
75
|
+
flows.each do |flow|
|
76
|
+
values = flow.to_hash
|
77
|
+
tag = values.delete('tag')
|
78
|
+
data[tag] = values
|
79
|
+
end
|
80
|
+
return Telemetry::Api.send(:post, "/flows", {:data => data})
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.send(method, endpoint, data = nil)
|
84
|
+
|
85
|
+
uri = URI("#{Telemetry.api_host}#{endpoint}")
|
86
|
+
|
87
|
+
Telemetry::logger.debug "REQ #{uri} - #{MultiJson.dump(data)}"
|
88
|
+
|
89
|
+
if method == :post
|
90
|
+
request = Net::HTTP::Post.new(uri.path)
|
91
|
+
request.body = MultiJson.dump(data)
|
92
|
+
elsif method == :put
|
93
|
+
request = Net::HTTP::Put.new(uri.path)
|
94
|
+
request.body = MultiJson.dump(data)
|
95
|
+
elsif method == :get
|
96
|
+
request = Net::HTTP::Get.new(uri.path)
|
97
|
+
elsif method == :delete
|
98
|
+
request = Net::HTTP::Delete.new(uri.path)
|
99
|
+
end
|
100
|
+
|
101
|
+
request.basic_auth(Telemetry.token, "") if Telemetry.token
|
102
|
+
request['Content-Type'] = 'application/json'
|
103
|
+
request['Accept-Version'] = '~ 1'
|
104
|
+
request['User-Agent'] = "Telemetry Ruby Gem (#{Telemetry::TELEMETRY_VERSION})"
|
105
|
+
|
106
|
+
begin
|
107
|
+
ssl = true if Telemetry.api_host.match(/^https/)
|
108
|
+
result = Net::HTTP.start(uri.host, uri.port, :use_ssl => ssl) do |http|
|
109
|
+
response = http.request(request)
|
110
|
+
code = response.code
|
111
|
+
|
112
|
+
Telemetry::logger.debug "RESP: #{response.code}:#{response.body}"
|
113
|
+
|
114
|
+
case response.code
|
115
|
+
when "200"
|
116
|
+
return MultiJson.load(response.body)
|
117
|
+
when "400"
|
118
|
+
json = MultiJson.load(response.body)
|
119
|
+
error = "#{Time.now} (HTTP 400): #{json['code'] if json} #{json['message'] if json}"
|
120
|
+
Telemetry::logger.error error
|
121
|
+
raise Telemetry::FormatError, error
|
122
|
+
when "401"
|
123
|
+
if Telemetry.token == nil
|
124
|
+
error = "#{Time.now} (HTTP 401): Authentication failed, please set Telemetry.token to your API Token."
|
125
|
+
Telemetry::logger.error error
|
126
|
+
raise Telemetry::AuthenticationFailed, error
|
127
|
+
else
|
128
|
+
error = "#{Time.now} (HTTP 401): Authentication failed, please verify your token."
|
129
|
+
Telemetry::logger.error error
|
130
|
+
raise Telemetry::AuthenticationFailed, error
|
131
|
+
end
|
132
|
+
when "403"
|
133
|
+
error = "#{Time.now} (HTTP 403): Authorization failed, please check your account access."
|
134
|
+
Telemetry::logger.error error
|
135
|
+
raise Telemetry::AuthorizationError, error
|
136
|
+
when "404"
|
137
|
+
error = "#{Time.now} (HTTP 404): Requested object not found."
|
138
|
+
Telemetry::logger.error error
|
139
|
+
raise Telemetry::FlowNotFound, error
|
140
|
+
when "429"
|
141
|
+
error = "#{Time.now} (HTTP 429): Rate limited. Please reduce your update interval."
|
142
|
+
Telemetry::logger.error error
|
143
|
+
raise Telemetry::RateLimited, error
|
144
|
+
when "500"
|
145
|
+
error = "#{Time.now} (HTTP 500): Data API server error."
|
146
|
+
Telemetry::logger.error error
|
147
|
+
raise Telemetry::ServerException, error
|
148
|
+
when "502"
|
149
|
+
error = "#{Time.now} (HTTP 502): Data API server is down."
|
150
|
+
Telemetry::logger.error error
|
151
|
+
raise Telemetry::Unavailable, error
|
152
|
+
when "503"
|
153
|
+
error = "#{Time.now} (HTTP 503): Data API server is down."
|
154
|
+
Telemetry::logger.error error
|
155
|
+
raise Telemetry::Unavailable, error
|
156
|
+
else
|
157
|
+
error = "#{Time.now} ERROR UNK: #{response.body}."
|
158
|
+
raise Telemetry::UnknownError, error
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
rescue Errno::ETIMEDOUT => e
|
163
|
+
error = "#{Time.now} ERROR #{e}"
|
164
|
+
Telemetry::logger.error error
|
165
|
+
raise Telemetry::ConnectionError, error
|
166
|
+
|
167
|
+
rescue Errno::ECONNREFUSED => e
|
168
|
+
error = "#{Time.now} ERROR #{e}"
|
169
|
+
Telemetry::logger.error error
|
170
|
+
raise Telemetry::ConnectionError, error
|
171
|
+
|
172
|
+
rescue Exception => e
|
173
|
+
raise e
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class FormatError < Exception
|
179
|
+
end
|
180
|
+
|
181
|
+
class AuthenticationFailed < Exception
|
182
|
+
end
|
183
|
+
|
184
|
+
class AuthorizationError < Exception
|
185
|
+
end
|
186
|
+
|
187
|
+
class FlowNotFound < Exception
|
188
|
+
end
|
189
|
+
|
190
|
+
class RateLimited < Exception
|
191
|
+
end
|
192
|
+
|
193
|
+
class ServerException < Exception
|
194
|
+
end
|
195
|
+
|
196
|
+
class Unavailable < Exception
|
197
|
+
end
|
198
|
+
|
199
|
+
class UnknownError < Exception
|
200
|
+
end
|
201
|
+
|
202
|
+
class ConnectionError < Exception
|
203
|
+
end
|
204
|
+
|
205
|
+
class ResponseError < Exception
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
end
|
@@ -2,12 +2,8 @@
|
|
2
2
|
|
3
3
|
module Telemetry
|
4
4
|
|
5
|
-
def token
|
6
|
-
@@token
|
7
|
-
end
|
8
|
-
|
9
5
|
def api_token(token)
|
10
|
-
|
6
|
+
Telemetry.token = token
|
11
7
|
end
|
12
8
|
|
13
9
|
def interval(interval)
|
@@ -55,6 +51,11 @@ module Telemetry
|
|
55
51
|
@@tasks << [ :barchart, tag, frequency, offset, block ]
|
56
52
|
end
|
57
53
|
|
54
|
+
def bulletchart(tag, frequency = 0, offset=nil, &block)
|
55
|
+
@@tasks ||= []
|
56
|
+
@@tasks << [ :value, tag, frequency, offset, block ]
|
57
|
+
end
|
58
|
+
|
58
59
|
def countdown(tag, frequency = 0, offset=nil, &block)
|
59
60
|
@@tasks ||= []
|
60
61
|
@@tasks << [ :countdown, tag, frequency, offset, block ]
|
@@ -105,6 +106,11 @@ module Telemetry
|
|
105
106
|
@@tasks << [ :servers, tag, frequency, offset, block ]
|
106
107
|
end
|
107
108
|
|
109
|
+
def status(tag, frequency = 0, offset=nil, &block)
|
110
|
+
@@tasks ||= []
|
111
|
+
@@tasks << [ :servers, tag, frequency, offset, block ]
|
112
|
+
end
|
113
|
+
|
108
114
|
def table(tag, frequency = 0, offset=nil, &block)
|
109
115
|
@@tasks ||= []
|
110
116
|
@@tasks << [ :table, tag, frequency, offset, block ]
|
@@ -159,20 +165,20 @@ module Telemetry
|
|
159
165
|
|
160
166
|
# Check whether we should wait an interval before running
|
161
167
|
if frequency > 0
|
162
|
-
#
|
168
|
+
#Telemetry::logger.debug "Update frequency is #{frequency} now #{Time.now.to_i} next #{@@next_run_at[tag]}"
|
163
169
|
next if @@next_run_at[tag] && @@next_run_at[tag] >= now.to_i
|
164
|
-
|
170
|
+
@@next_run_at[tag] = now.to_i + frequency
|
165
171
|
|
166
|
-
|
167
|
-
|
168
|
-
|
172
|
+
# If an offset is defined then align runtimes to the offset
|
173
|
+
# How close you can get to the desired offset depends on the global interval. So set it relatively small
|
174
|
+
# when using this feature
|
169
175
|
if offset and offset >= 0 and offset <= 86400
|
170
176
|
this_morning = Time.new(now.year, now.month, now.day).to_i
|
171
177
|
time_since_offset = now.to_i - this_morning - offset
|
172
178
|
time_since_offset += 86400 if time_since_offset < 0
|
173
179
|
|
174
180
|
@@next_run_at[tag] -= time_since_offset % frequency
|
175
|
-
#
|
181
|
+
#Telemetry::logger.debug "#{now.to_i} #{@@next_run_at[tag]}"
|
176
182
|
end
|
177
183
|
end
|
178
184
|
|
@@ -0,0 +1,189 @@
|
|
1
|
+
#/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
module TelemetryFlows
|
6
|
+
def emit
|
7
|
+
Telemetry::Api.flow_update(self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Telemetry
|
12
|
+
|
13
|
+
# Barchart
|
14
|
+
class Barchart < Hashie::Dash
|
15
|
+
include TelemetryFlows
|
16
|
+
property :tag, :required => true
|
17
|
+
property :bars, :default => []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Bulletchart
|
21
|
+
class Bulletchart < Hashie::Dash
|
22
|
+
include TelemetryFlows
|
23
|
+
property :tag, :required => true
|
24
|
+
property :bulletcharts, :default => []
|
25
|
+
end
|
26
|
+
|
27
|
+
# Countdown
|
28
|
+
class Countdown < Hashie::Dash
|
29
|
+
include TelemetryFlows
|
30
|
+
property :tag, :required => true
|
31
|
+
property :time, :required => true
|
32
|
+
property :message, :required => true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Gauge
|
36
|
+
class Gauge < Hashie::Dash
|
37
|
+
include TelemetryFlows
|
38
|
+
property :tag, :required => true
|
39
|
+
property :value, :required => true
|
40
|
+
property :value_color
|
41
|
+
property :max
|
42
|
+
property :range
|
43
|
+
property :value_2
|
44
|
+
property :value_2_color
|
45
|
+
property :value_2_label
|
46
|
+
end
|
47
|
+
|
48
|
+
# Graph
|
49
|
+
class Graph < Hashie::Dash
|
50
|
+
include TelemetryFlows
|
51
|
+
property :tag, :required => true
|
52
|
+
property :renderer
|
53
|
+
property :series, :default => []
|
54
|
+
property :min_scale
|
55
|
+
property :unstack
|
56
|
+
property :x_labels
|
57
|
+
end
|
58
|
+
|
59
|
+
# Icons
|
60
|
+
class Icons < Hashie::Dash
|
61
|
+
include TelemetryFlows
|
62
|
+
property :tag, :required => true
|
63
|
+
property :icons, :default => []
|
64
|
+
end
|
65
|
+
|
66
|
+
# iFrame
|
67
|
+
class Iframe < Hashie::Dash
|
68
|
+
include TelemetryFlows
|
69
|
+
property :tag, :required => true
|
70
|
+
property :url, :required => true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Log
|
74
|
+
class Log < Hashie::Dash
|
75
|
+
include TelemetryFlows
|
76
|
+
property :tag, :required => true
|
77
|
+
property :messages, :default => []
|
78
|
+
end
|
79
|
+
|
80
|
+
# Map
|
81
|
+
class Map < Hashie::Dash
|
82
|
+
include TelemetryFlows
|
83
|
+
property :tag, :required => true
|
84
|
+
property :map_type, :required => true
|
85
|
+
property :points, :default => []
|
86
|
+
end
|
87
|
+
|
88
|
+
# Multigauge
|
89
|
+
class Multigauge < Hashie::Dash
|
90
|
+
include TelemetryFlows
|
91
|
+
property :tag, :required => true
|
92
|
+
property :gauges, :default => []
|
93
|
+
end
|
94
|
+
|
95
|
+
# Multivalue
|
96
|
+
class Multivalue < Hashie::Dash
|
97
|
+
include TelemetryFlows
|
98
|
+
property :tag, :required => true
|
99
|
+
property :values, :default => []
|
100
|
+
end
|
101
|
+
|
102
|
+
# Servers
|
103
|
+
class Servers < Hashie::Dash
|
104
|
+
include TelemetryFlows
|
105
|
+
property :tag, :required => true
|
106
|
+
property :servers, :default => []
|
107
|
+
property :orange
|
108
|
+
property :red
|
109
|
+
end
|
110
|
+
|
111
|
+
# Status
|
112
|
+
class Status < Hashie::Dash
|
113
|
+
include TelemetryFlows
|
114
|
+
property :tag, :required => true
|
115
|
+
property :statuses, :default => []
|
116
|
+
end
|
117
|
+
|
118
|
+
# Table
|
119
|
+
class Table < Hashie::Dash
|
120
|
+
include TelemetryFlows
|
121
|
+
property :tag, :required => true
|
122
|
+
property :table, :default => []
|
123
|
+
property :headers, :default => []
|
124
|
+
property :colors, :default => []
|
125
|
+
end
|
126
|
+
|
127
|
+
# Text
|
128
|
+
class Text < Hashie::Dash
|
129
|
+
include TelemetryFlows
|
130
|
+
property :tag, :required => true
|
131
|
+
property :text, :required => true
|
132
|
+
property :alignment
|
133
|
+
end
|
134
|
+
|
135
|
+
# Tickertape
|
136
|
+
class Tickertape < Hashie::Dash
|
137
|
+
include TelemetryFlows
|
138
|
+
property :tag, :required => true
|
139
|
+
property :messages, :default => []
|
140
|
+
end
|
141
|
+
|
142
|
+
# Timechart
|
143
|
+
class Timechart < Hashie::Dash
|
144
|
+
include TelemetryFlows
|
145
|
+
property :tag, :required => true
|
146
|
+
property :values, :default => []
|
147
|
+
property :type, :required => true
|
148
|
+
end
|
149
|
+
|
150
|
+
# Timeline
|
151
|
+
class Timeline < Hashie::Dash
|
152
|
+
include TelemetryFlows
|
153
|
+
property :tag, :required => true
|
154
|
+
property :messages, :default => []
|
155
|
+
end
|
156
|
+
|
157
|
+
# Timeseries
|
158
|
+
class Timeseries < Hashie::Dash
|
159
|
+
include TelemetryFlows
|
160
|
+
property :tag, :required => true
|
161
|
+
property :value, :required => true
|
162
|
+
property :type, :required => true
|
163
|
+
property :label, :required => true
|
164
|
+
property :color
|
165
|
+
property :smoothing
|
166
|
+
property :value_type
|
167
|
+
end
|
168
|
+
|
169
|
+
# Upstatus
|
170
|
+
class Upstatus < Hashie::Dash
|
171
|
+
include TelemetryFlows
|
172
|
+
property :tag, :required => true
|
173
|
+
property :up, :default => []
|
174
|
+
property :down, :default => []
|
175
|
+
property :uptime
|
176
|
+
property :last_down
|
177
|
+
end
|
178
|
+
|
179
|
+
# Value
|
180
|
+
class Value < Hashie::Dash
|
181
|
+
include TelemetryFlows
|
182
|
+
property :tag, :required => true
|
183
|
+
property :value, :required => true
|
184
|
+
property :color
|
185
|
+
property :delta
|
186
|
+
property :value_type
|
187
|
+
property :delta_type
|
188
|
+
end
|
189
|
+
end
|
data/lib/telemetry/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Telemetry
|
2
|
-
|
3
|
-
end
|
2
|
+
TELEMETRY_VERSION = "1.1.1"
|
3
|
+
end
|
data/lib/telemetry.rb
CHANGED
data/spec/batch_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Batch" do
|
4
|
+
before(:all) do
|
5
|
+
Telemetry.token = "test-api-token"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should perform a batch update" do
|
9
|
+
|
10
|
+
flows = []
|
11
|
+
|
12
|
+
barchart_properties = {
|
13
|
+
tag: "test-flow-barchart",
|
14
|
+
bars: [{value:1000, label:'test', color:'red'}]
|
15
|
+
}
|
16
|
+
flows << Telemetry::Barchart.new(barchart_properties)
|
17
|
+
|
18
|
+
gauge_properties = {
|
19
|
+
tag: "test-flow-gauge",
|
20
|
+
value: 3434
|
21
|
+
}
|
22
|
+
flows << Telemetry::Gauge.new(gauge_properties)
|
23
|
+
|
24
|
+
value_properties = {
|
25
|
+
tag: "test-flow-value",
|
26
|
+
value: 3434
|
27
|
+
}
|
28
|
+
flows << Telemetry::Value.new(value_properties)
|
29
|
+
|
30
|
+
result = Telemetry::Api.flow_update_batch(flows)
|
31
|
+
|
32
|
+
result["skipped"].should eql([])
|
33
|
+
result["errors"].should eql([])
|
34
|
+
end
|
35
|
+
end
|
data/spec/daemon_spec.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative "../lib/telemetry/daemon_config_parser"
|
3
|
+
|
4
|
+
describe "Daemon" do
|
5
|
+
before(:all) do
|
6
|
+
Telemetry.token = "test-api-token"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should run the daemon" do
|
10
|
+
`bin/telemetryd -c telemetryd_config.rb -o`
|
11
|
+
end
|
12
|
+
end
|
data/spec/flows_spec.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Flows" do
|
4
|
+
before(:all) do
|
5
|
+
Telemetry.token = "test-api-token"
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should update a Barchart", flows: true do
|
9
|
+
properties = {
|
10
|
+
tag: "test-flow-barchart",
|
11
|
+
bars: [{value:1000, label:'test', color:'red'}]
|
12
|
+
}
|
13
|
+
Telemetry::Barchart.new(properties).emit
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should update a Bulletchart", flows: true do
|
17
|
+
properties = {
|
18
|
+
tag: "test-flow-bulletchart",
|
19
|
+
bulletcharts: [{value: 34, max: 4434}]
|
20
|
+
}
|
21
|
+
Telemetry::Bulletchart.new(properties).emit
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should update a Countdown", flows: true do
|
25
|
+
properties = {
|
26
|
+
tag: "test-flow-countdown",
|
27
|
+
time: 1373664109,
|
28
|
+
message: "Party Time"
|
29
|
+
}
|
30
|
+
Telemetry::Countdown.new(properties).emit
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should update a Gauge" do
|
34
|
+
properties = {
|
35
|
+
tag: "test-flow-gauge",
|
36
|
+
value: 3434
|
37
|
+
}
|
38
|
+
Telemetry::Gauge.new(properties).emit
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should update a Graph" do
|
42
|
+
properties = {
|
43
|
+
tag: "test-flow-graph",
|
44
|
+
series: [{values:[4,3,53,3,54,33,21]}]
|
45
|
+
}
|
46
|
+
Telemetry::Graph.new(properties).emit
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should update a Icons" do
|
50
|
+
properties = {
|
51
|
+
tag: "test-flow-icons",
|
52
|
+
icons: [{type: "icon-dashboard", label: "Alert", color: "red"}]
|
53
|
+
}
|
54
|
+
Telemetry::Icons.new(properties).emit
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should update a Iframe" do
|
58
|
+
properties = {
|
59
|
+
tag: "test-flow-iframe",
|
60
|
+
url: "http://www.telemetryapp.com"
|
61
|
+
}
|
62
|
+
Telemetry::Iframe.new(properties).emit
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should update a Log" do
|
66
|
+
properties = {
|
67
|
+
tag: "test-flow-log",
|
68
|
+
messages: [{timestamp: 1373664109, text: "This is a first message", color: "red"}]
|
69
|
+
}
|
70
|
+
Telemetry::Log.new(properties).emit
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should update a Map" do
|
74
|
+
properties = {
|
75
|
+
tag: "test-flow-map",
|
76
|
+
map_type: "asia",
|
77
|
+
points: [[34.344,129.344],[55.233,121.233]]
|
78
|
+
}
|
79
|
+
Telemetry::Map.new(properties).emit
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should update a Multigauge" do
|
83
|
+
properties = {
|
84
|
+
tag: "test-flow-multigauge",
|
85
|
+
gauges: [{value: 34, label: "Alpha"},{value: 23, label: "Alpha"}]
|
86
|
+
}
|
87
|
+
Telemetry::Multigauge.new(properties).emit
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should update a Multivalue" do
|
91
|
+
properties = {
|
92
|
+
tag: "test-flow-multivalue",
|
93
|
+
values: [{value: 34, label: "Alpha"},{value: 344, label: "Bravo"}]
|
94
|
+
}
|
95
|
+
Telemetry::Multivalue.new(properties).emit
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should update a Servers" do
|
99
|
+
properties = {
|
100
|
+
tag: "test-flow-servers",
|
101
|
+
servers: [{values: [33,22,55], title: "Alpha"}]
|
102
|
+
}
|
103
|
+
Telemetry::Servers.new(properties).emit
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should update a Status" do
|
107
|
+
properties = {
|
108
|
+
tag: "test-flow-status",
|
109
|
+
statuses: [{label: "Alpha", color: "red"}]
|
110
|
+
}
|
111
|
+
Telemetry::Status.new(properties).emit
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should update a Table" do
|
115
|
+
properties = {
|
116
|
+
tag: "test-flow-table",
|
117
|
+
table: [["Row1Col1", "Row1Col2", "Row1Col3"]]
|
118
|
+
}
|
119
|
+
Telemetry::Table.new(properties).emit
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should update a Text" do
|
123
|
+
properties = {
|
124
|
+
tag: "test-flow-text",
|
125
|
+
text: "testing"
|
126
|
+
}
|
127
|
+
Telemetry::Text.new(properties).emit
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should update a Tickertape" do
|
131
|
+
properties = {
|
132
|
+
tag: "test-flow-tickertape",
|
133
|
+
messages: ["Hello World!"]
|
134
|
+
}
|
135
|
+
Telemetry::Tickertape.new(properties).emit
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should update a Timechart" do
|
139
|
+
properties = {
|
140
|
+
tag: "test-flow-timechart",
|
141
|
+
type: "week",
|
142
|
+
values: [34,123,76,43,45,16,48]
|
143
|
+
}
|
144
|
+
Telemetry::Timechart.new(properties).emit
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should update a Timeline" do
|
148
|
+
properties = {
|
149
|
+
tag: "test-flow-timeline",
|
150
|
+
messages: [{timestamp: 1373665284, from: "Telemetry", text: "This is the second message"}]
|
151
|
+
}
|
152
|
+
Telemetry::Timeline.new(properties).emit
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should update a Timeseries" do
|
156
|
+
properties = {
|
157
|
+
tag: "test-flow-timeseries",
|
158
|
+
value: 33,
|
159
|
+
type: "hour",
|
160
|
+
label: "Alpha"
|
161
|
+
}
|
162
|
+
Telemetry::Timeseries.new(properties).emit
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should update a Upstatus" do
|
166
|
+
properties = {
|
167
|
+
tag: "test-flow-upstatus",
|
168
|
+
up: ["www.telemetryapp.com"]
|
169
|
+
}
|
170
|
+
Telemetry::Upstatus.new(properties).emit
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should update a Value" do
|
174
|
+
properties = {
|
175
|
+
tag: "test-flow-value",
|
176
|
+
value: 3434
|
177
|
+
}
|
178
|
+
Telemetry::Value.new(properties).emit
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
data/spec/spec_helper.rb
ADDED
data/telemetry.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'telemetry/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "telemetry"
|
8
|
-
gem.version = Telemetry::
|
8
|
+
gem.version = Telemetry::TELEMETRY_VERSION
|
9
9
|
gem.authors = ["W. Gersham Meharg"]
|
10
10
|
gem.email = ["gersham@etosi.com"]
|
11
11
|
gem.description = %q{Telemetry Data Submission API Gem. See our website for a more detailed description.}
|
@@ -19,4 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_dependency "oj"
|
20
20
|
gem.add_dependency "multi_json"
|
21
21
|
gem.add_dependency "dante"
|
22
|
+
gem.add_dependency "hashie"
|
23
|
+
gem.add_development_dependency "rspec"
|
24
|
+
gem.add_development_dependency "rake"
|
22
25
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: telemetry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.1.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- W. Gersham Meharg
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: oj
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: multi_json
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: dante
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,48 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: hashie
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
93
|
requirements:
|
59
94
|
- - ! '>='
|
60
95
|
- !ruby/object:Gem::Version
|
@@ -69,38 +104,47 @@ extensions: []
|
|
69
104
|
extra_rdoc_files: []
|
70
105
|
files:
|
71
106
|
- .gitignore
|
107
|
+
- .rspec
|
72
108
|
- Gemfile
|
73
109
|
- LICENSE.txt
|
74
110
|
- README.md
|
75
111
|
- Rakefile
|
76
112
|
- bin/telemetryd
|
77
113
|
- lib/telemetry.rb
|
78
|
-
- lib/telemetry/
|
79
|
-
- lib/telemetry/
|
114
|
+
- lib/telemetry/api.rb
|
115
|
+
- lib/telemetry/daemon_config_parser.rb
|
116
|
+
- lib/telemetry/flows.rb
|
80
117
|
- lib/telemetry/version.rb
|
118
|
+
- spec/batch_spec.rb
|
119
|
+
- spec/daemon_spec.rb
|
120
|
+
- spec/flows_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
81
122
|
- telemetry.gemspec
|
82
123
|
homepage: http://www.telemetryapp.com
|
83
124
|
licenses: []
|
125
|
+
metadata: {}
|
84
126
|
post_install_message:
|
85
127
|
rdoc_options: []
|
86
128
|
require_paths:
|
87
129
|
- lib
|
88
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
131
|
requirements:
|
91
132
|
- - ! '>='
|
92
133
|
- !ruby/object:Gem::Version
|
93
134
|
version: 1.9.2
|
94
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
136
|
requirements:
|
97
137
|
- - ! '>='
|
98
138
|
- !ruby/object:Gem::Version
|
99
139
|
version: '0'
|
100
140
|
requirements: []
|
101
141
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
142
|
+
rubygems_version: 2.0.5
|
103
143
|
signing_key:
|
104
|
-
specification_version:
|
144
|
+
specification_version: 4
|
105
145
|
summary: Telemetry Data Submission API Gem
|
106
|
-
test_files:
|
146
|
+
test_files:
|
147
|
+
- spec/batch_spec.rb
|
148
|
+
- spec/daemon_spec.rb
|
149
|
+
- spec/flows_spec.rb
|
150
|
+
- spec/spec_helper.rb
|
data/lib/telemetry/telemetry.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
#/usr/bin/env ruby
|
2
|
-
|
3
|
-
module Telemetry
|
4
|
-
class Api
|
5
|
-
require 'multi_json'
|
6
|
-
require 'net/http'
|
7
|
-
require 'uri'
|
8
|
-
|
9
|
-
def self.send(data)
|
10
|
-
return unless Telemetry.token
|
11
|
-
return unless data.size > 0
|
12
|
-
|
13
|
-
body = MultiJson.dump({:data => data})
|
14
|
-
|
15
|
-
uri = URI("https://data.telemetryapp.com/flows")
|
16
|
-
request = Net::HTTP::Post.new(uri.path)
|
17
|
-
request.basic_auth(Telemetry.token, "")
|
18
|
-
request['Content-Type'] = 'application/json'
|
19
|
-
request['User-Agent'] = "Telemetry Ruby Gem (#{Telemetry::VERSION})"
|
20
|
-
request.body = body
|
21
|
-
|
22
|
-
begin
|
23
|
-
result = Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
|
24
|
-
response = http.request(request)
|
25
|
-
case response.code
|
26
|
-
when "200"
|
27
|
-
json = MultiJson.load(response.body)
|
28
|
-
if json
|
29
|
-
puts "#{Time.now} Update OK: Updated #{json["updated"].count} flows" if json["updated"] && json["updated"].count > 0
|
30
|
-
puts "#{Time.now} Update OK: Skipped #{json["skipped"].count} flows (#{json["skipped"].join(", ")})" if json["skipped"] && json["skipped"].count > 0
|
31
|
-
puts "#{Time.now} Update OK: Errors with #{json["errors"].count} flows (#{json["errors"].join(", ")})" if json["errors"] && json["errors"].count > 0
|
32
|
-
end
|
33
|
-
when "400"
|
34
|
-
puts "#{Time.now} ERROR 400: Request error. #{response.body}. Exiting."
|
35
|
-
exit
|
36
|
-
when "401"
|
37
|
-
puts "#{Time.now} ERROR 401: Authentication failed, please check your api_token. Exiting."
|
38
|
-
exit
|
39
|
-
when "403"
|
40
|
-
puts "#{Time.now} ERROR 403: Authorization failed, please check your account access. Exiting."
|
41
|
-
exit
|
42
|
-
when "429"
|
43
|
-
puts "#{Time.now} ERROR 429: Rate limited. Please reduce your update interval. Pausing updates for 300s."
|
44
|
-
sleep 300
|
45
|
-
when "500"
|
46
|
-
puts "#{Time.now} ERROR 500: Data API server error. Pausing updates for 60s."
|
47
|
-
sleep 60
|
48
|
-
when "503"
|
49
|
-
puts "#{Time.now} ERROR 503: Data API server is down. Pausing updates for 60s."
|
50
|
-
sleep 60
|
51
|
-
else
|
52
|
-
puts "#{Time.now} ERROR UNK: #{response.body}. Exiting."
|
53
|
-
exit
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
rescue Errno::ETIMEDOUT => e
|
58
|
-
puts "#{Time.now} ERROR #{e}"
|
59
|
-
sleep 60
|
60
|
-
|
61
|
-
rescue Errno::ECONNREFUSED => e
|
62
|
-
puts "#{Time.now} ERROR #{e}"
|
63
|
-
sleep 60
|
64
|
-
|
65
|
-
rescue Exception => e
|
66
|
-
puts "#{Time.now} ERROR #{e}"
|
67
|
-
sleep 60
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|