batsd 1.0.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.
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ .DS_Store
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Benjamin Hathaway
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ batsd-ruby
2
+ ==========
3
+
4
+ A ruby client for batsd.
@@ -0,0 +1,18 @@
1
+ $:.unshift File.expand_path("../lib", __FILE__)
2
+
3
+ require "batsd/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "batsd"
7
+
8
+ s.version = Batsd::VERSION
9
+
10
+ s.homepage = "https://github.com/hathaway/batsd-client"
11
+ s.authors = ["Ben Hathaway"]
12
+ s.email = ["ben@hathaway.cc"]
13
+
14
+ s.summary = "Batsd Client"
15
+ s.description = "A Batsd client for Ruby. Provides an interface for querying data in a batsd server."
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ end
@@ -0,0 +1,224 @@
1
+ require 'timeout'
2
+ require 'json'
3
+ require 'socket'
4
+
5
+ ##
6
+ # A batsd client for querying data from a batsd server.
7
+ class Batsd
8
+
9
+ ##
10
+ # The default option values.
11
+ DEFAULTS = {
12
+ :host => "127.0.0.1",
13
+ :port => 8127,
14
+ :timeout => 2000,
15
+ :max_attempts => 2
16
+ }
17
+
18
+ ##
19
+ # The hostname of the batsd server.
20
+ def host
21
+ @options[:host]
22
+ end
23
+
24
+ ##
25
+ # The port the batsd server is running on.
26
+ def port
27
+ @options[:port]
28
+ end
29
+
30
+ ##
31
+ # The timeout in milliseconds to use for the TCP connection.
32
+ def timeout
33
+ @options[:timeout]
34
+ end
35
+
36
+ ##
37
+ # The maxiumum number of attempts to make when querying for data.
38
+ # If an error is encountered, it will try this many total times before throwing an exception.
39
+ def max_attempts
40
+ @options[:max_attempts]
41
+ end
42
+
43
+ attr_accessor :remote
44
+
45
+ def initialize(options = {})
46
+ @options = _parse_options(options)
47
+ connect!
48
+ end
49
+
50
+ ##
51
+ # Send the 'ping' command to the server.
52
+ #
53
+ # @return [String] The response received from the server.
54
+ def ping
55
+ send_command("ping")
56
+ end
57
+
58
+ # Queries for the available keys in the batsd server.
59
+ #
60
+ # @return [Array] An array of string keys.
61
+ def available
62
+ keys = send_command("available")
63
+ keys.collect do |k|
64
+ if k.match /^timer/
65
+ ["mean", "min", "max", "upper_90", "stddev", "count"].collect{|a| "#{k}:#{a}"}
66
+ else
67
+ k
68
+ end
69
+ end.flatten
70
+ end
71
+
72
+ ##
73
+ # Get the stats for a given <code>metric_name</code> that's contained in the available
74
+ # set of datapoints within the range of <code>start_timestamp</code> to
75
+ # <code>end_timestamp</code>
76
+ #
77
+ # @param [String] metric_name
78
+ # The key for the metric you are querying for.
79
+ #
80
+ # @param [Time] start_timestamp
81
+ # The start of the time range of the query.
82
+ #
83
+ # @param [Time] end_timestamp
84
+ # The end of the time range of the query. Defaults to the current time.
85
+ #
86
+ # @param [Integer] attempts
87
+ # The number of attempts that have been made for this query. Defaults to 0.
88
+ #
89
+ # @return [Array] An array of hashes. Each hash contains the <code>:timestamp</code>
90
+ # and <code>:value</code> of the data point.
91
+ def stats(metric_name, start_timestamp, end_timestamp=Time.now, attempt=0)
92
+ results = []
93
+ values = send_command("values #{metric_name} #{start_timestamp.to_i} #{end_timestamp.to_i}")
94
+ if values[metric_name].nil?
95
+ if attempt < max_attempts
96
+ return values(metric_name, start_timestamp, end_timestamp, attempt+1)
97
+ else
98
+ raise InvalidValuesError
99
+ end
100
+ end
101
+ results = values[metric_name].collect{|v| { timestamp: Time.at(v["timestamp"].to_i), value: v["value"].to_f } }
102
+ results
103
+ end
104
+
105
+ ##
106
+ # Get only the values of the stats for a given <code>metric_name</code>
107
+ # that's contained in the available set of datapoints within the range
108
+ # of <code>start_timestamp</code> to <code>end_timestamp</code>
109
+ #
110
+ # @param [String] metric_name
111
+ # The key for the metric you are querying for.
112
+ #
113
+ # @param [Time] start_timestamp
114
+ # The start of the time range of the query.
115
+ #
116
+ # @param [Time] end_timestamp
117
+ # The end of the time range of the query. Defaults to the current time.
118
+ #
119
+ # @return [Array] An array of floating point numbers.
120
+ def values(metric_name, start_timestamp, end_timestamp=Time.now)
121
+ stats(metric_name, start_timestamp, end_timestamp).map{|s| s[:value]}
122
+ end
123
+
124
+ ##
125
+ # Get only the timestamps of the stats for a given <code>metric_name</code>
126
+ # that's contained in the available set of datapoints within the range
127
+ # of <code>start_timestamp</code> to <code>end_timestamp</code>
128
+ #
129
+ # @param [String] metric_name
130
+ # The key for the metric you are querying for.
131
+ #
132
+ # @param [Time] start_timestamp
133
+ # The start of the time range of the query.
134
+ #
135
+ # @param [Time] end_timestamp
136
+ # The end of the time range of the query. Defaults to the current time.
137
+ #
138
+ # @return [Array] An array of Time objects.
139
+ def timestamps(metric_name, start_timestamp, end_timestamp=Time.now)
140
+ stats(metric_name, start_timestamp, end_timestamp).map{|s| s[:timestamp]}
141
+ end
142
+
143
+
144
+ protected
145
+
146
+ ##
147
+ # Parse the options provided in the constructor. Use the defaults for
148
+ # any options not provided.
149
+ def _parse_options(options)
150
+ defaults = DEFAULTS.dup
151
+ options = options.dup
152
+
153
+ defaults.keys.each do |key|
154
+ options[key] ||= defaults[key]
155
+ end
156
+
157
+ options
158
+ end
159
+
160
+ private
161
+
162
+ ##
163
+ # Connect to the remote batsd server over TCP.
164
+ def connect!
165
+ Timeout::timeout(5) do
166
+ self.remote = TCPSocket.new(host, port)
167
+ end
168
+ rescue Timeout::Error => e
169
+ raise ConnectionTimeoutError
170
+ rescue
171
+ raise CannotConnectError
172
+ end
173
+
174
+ ##
175
+ # Disconnect from the remote batsd server.
176
+ def disconnect
177
+ self.remote.close
178
+ end
179
+
180
+ ##
181
+ # Reconnect to the batsd server.
182
+ def reconnect!
183
+ disconnect
184
+ connect!
185
+ end
186
+
187
+ ##
188
+ # Send a command to the remote and attempt to parse the response as JSON
189
+ #
190
+ # @param [String] command
191
+ # The command to send to the server.
192
+ #
193
+ # @return [Array, String] The response received from the server. Unless it is
194
+ # the ping command, the JSON response is parsed into an array.
195
+ def send_command(command, attempt=0)
196
+ Timeout::timeout(timeout.to_f / 1000.0) do
197
+ connect! unless self.remote
198
+ self.remote.puts command
199
+ @response = self.remote.gets
200
+ unless command == "ping"
201
+ results = JSON.parse(@response)
202
+ else
203
+ results = @response.delete("\n")
204
+ end
205
+ results
206
+ end
207
+ rescue TimeoutError => e
208
+ if attempt < max_attempts
209
+ send_command(command, attempt+1)
210
+ else
211
+ raise CommandTimeoutError
212
+ end
213
+ rescue Exception => e
214
+ if attempt < max_attempts
215
+ send_command(command, attempt+1)
216
+ else
217
+ self.remote = nil
218
+ raise CommandError
219
+ end
220
+ end
221
+ end
222
+
223
+ require 'batsd/version'
224
+ require 'batsd/errors'
@@ -0,0 +1,41 @@
1
+ class Batsd
2
+ ##
3
+ # Base error for all batsd errors.
4
+ class BaseError < RuntimeError
5
+ end
6
+
7
+ ##
8
+ # Base error for connection related errors.
9
+ class BaseConnectionError < BaseError
10
+ end
11
+
12
+ ##
13
+ # Raised when connection to a batsd server cannot be made.
14
+ class CannotConnectError < BaseConnectionError
15
+ end
16
+
17
+ ##
18
+ # Raised when a new connection times out
19
+ class ConnectionTimeoutError < BaseConnectionError
20
+ end
21
+
22
+ ##
23
+ # Base error for command related errors.
24
+ class BaseCommandError < BaseError
25
+ end
26
+
27
+ ##
28
+ # Raised when a command could not be run
29
+ class CommandError < BaseCommandError
30
+ end
31
+
32
+ ##
33
+ # Raised when a command times out
34
+ class CommandTimeoutError < BaseCommandError
35
+ end
36
+
37
+ ##
38
+ # Raised when the values returned weren't the same as what was asked for
39
+ class InvalidValuesError < BaseError
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ class Batsd
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: batsd
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Hathaway
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A Batsd client for Ruby. Provides an interface for querying data in a
15
+ batsd server.
16
+ email:
17
+ - ben@hathaway.cc
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - LICENSE
24
+ - README.md
25
+ - batsd.gemspec
26
+ - lib/batsd.rb
27
+ - lib/batsd/errors.rb
28
+ - lib/batsd/version.rb
29
+ homepage: https://github.com/hathaway/batsd-client
30
+ licenses: []
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 1.8.11
50
+ signing_key:
51
+ specification_version: 3
52
+ summary: Batsd Client
53
+ test_files: []