telemetry 1.0.10 → 1.1.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.
- 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
|