opentsdb-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2ebb5075958cfa76233980e4dae55bd0ad30e28e
4
+ data.tar.gz: 003174b10051ea7d851344a17ca254a31136d9d3
5
+ SHA512:
6
+ metadata.gz: 827664beb3f3aaea2c5a2e010940738214bec02afdba5532629eaf9747bd418668a7f6e8655192fa607914320906d1d330315501c8cfa889b907b879befd5a46
7
+ data.tar.gz: 51b7fd589fa67d8490133476336a3e11070d0798062da5588d3a41fee5a38dabbffb0fca6b93734de1cdcee0f9878fd449ebacb6a6c53ba02a918563b2597ab5
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # opentsdb-ruby
2
+
3
+ Ruby client for OpenTSDB HTTP Query API.
4
+
5
+ [![Build Status](https://travis-ci.org/cloudinsight/opentsdb-ruby.png)](https://travis-ci.org/cloudinsight/opentsdb-ruby) [![Code Climate](https://codeclimate.com/github/cloudinsight/opentsdb-ruby/badges/gpa.svg)](https://codeclimate.com/github/cloudinsight/opentsdb-ruby)
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'openstd-ruby', github: 'cloudinsight/opentsdb-ruby'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install openstd-ruby
21
+
22
+
23
+ ## Quick Start Guide
24
+
25
+ ### Configure openstdb
26
+
27
+ ```ruby
28
+ #config/initializers/cloudinsight_openstdb.rb
29
+
30
+ if defined?(CloudInsight)
31
+ CloudInsight::Opentsdb.configure do |config|
32
+ config.host = 'localhost' # opentsdb server host default: localhost
33
+ config.port = 4242 # opentsdb server port default: 4242
34
+ end
35
+ end
36
+
37
+ ```
38
+
39
+ ### Usage
40
+
41
+ ```ruby
42
+
43
+ # define simple query params
44
+ params = { begin: Time.now.ago(1.hour), q: 'avg:system.load.1{host=*}' }
45
+ # opensted
46
+ client = CloudInsight::Opentsdb::Client.new(params)
47
+ result = client.query # opentsdb json result
48
+
49
+
50
+ # complicate query params
51
+ params = { begin: Time.now.ago(1.hour), end: Time.now, q: 'avg:system.load.1{host=server1, host=server2, tagk=tagv}by{host}', interval: 360 }
52
+ client = CloudInsight::Opentsdb::Client.new(params)
53
+ result = client.query # opentsdb json result
54
+
55
+
56
+ # reconfig opentsdb host port
57
+ params = { host: '192.168.0.100', port: 8000, q: 'avg:system.load.1{host=*}' }
58
+ client = CloudInsight::Opentsdb::Client.new(params)
59
+ result = client.query # opentsdb json result
60
+ ```
61
+
62
+
@@ -0,0 +1,46 @@
1
+ require_relative 'http_client'
2
+ module CloudInsight
3
+ module Opentsdb
4
+ # ruby client for OpenTsdb HTTP API
5
+ class Client
6
+ extend Forwardable
7
+
8
+ def_instance_delegators :@http, :post
9
+
10
+ attr_reader :host, :port, :query_options
11
+
12
+ def initialize(options = {})
13
+ @host = options.delete(:host) || Opentsdb.host
14
+ @port = options.delete(:port) || Opentsdb.port
15
+ @http = HttpClient.new
16
+ @query_options = options
17
+ end
18
+
19
+ def query
20
+ [].tap do |data|
21
+ parse_queries.each do |query_commad|
22
+ data << post(query_uri, query_commad.to_json)
23
+ end
24
+ end
25
+ end
26
+
27
+ def parse_queries
28
+ [].tap do |qs|
29
+ query_options[:q].split(';').each do |q|
30
+ query = QueryParser.parse(q)
31
+ query.interval = query_options[:interval]
32
+ query.start_time = query_options[:begin].to_i
33
+ query.end_time = query_options[:end].to_i
34
+ qs << query
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def query_uri
42
+ URI("http://#{host}:#{port}/api/query")
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,38 @@
1
+ require 'net/http'
2
+ require 'benchmark'
3
+ module CloudInsight
4
+ module Opentsdb
5
+ # :nodoc:
6
+ class HttpClient
7
+ def post(uri, body)
8
+ send_http(uri) do |http|
9
+ Opentsdb.logger.debug "Http post body: #{body}"
10
+ req = Net::HTTP::Post.new(uri, headers)
11
+ req.body = body
12
+ http.request(req)
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def headers
19
+ { 'Content-Type' => 'application/json; charset=UTF-8' }
20
+ end
21
+
22
+ def send_http(uri)
23
+ Opentsdb.logger.info "Http request uri: #{uri}"
24
+ http = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https')
25
+ res = nil
26
+ time = Benchmark.realtime do
27
+ res = yield(http)
28
+ end
29
+ Opentsdb.logger.info "Response: #{res.code} consume: #{time} s"
30
+ res
31
+ rescue Timeout::Error, Errno::ECONNRESET, Net::HTTPBadResponse,
32
+ Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
33
+ Opentsdb.logger.error "Http request error: #{e}"
34
+ false
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,65 @@
1
+ module CloudInsight
2
+ # :nodoc:
3
+ class QueryParam
4
+ attr_accessor :aggregator, :rate, :metric, :tags, :downsample, :interval
5
+ attr_accessor :start_time, :end_time, :queries
6
+
7
+ def initialize(options = {})
8
+ @aggregator = options[:aggregator]
9
+ @rate = options[:rate] || false
10
+ @metric = options[:metric]
11
+ @tags = options[:tags] || {}
12
+ end
13
+
14
+ def start_time
15
+ @start_time > 0 ? to_ms(@start_time) : (end_time - 3_600_000) # 1 hour ago
16
+ end
17
+
18
+ def end_time
19
+ @end_time > 0 ? to_ms(@end_time) : to_ms(Time.now)
20
+ end
21
+
22
+ def to_json
23
+ {}.tap do |h|
24
+ h[:start] = start_time
25
+ h[:end] = end_time
26
+ h[:queries] = queries
27
+ end.to_json
28
+ end
29
+
30
+ def tags
31
+ @tags.each do |tagk, tagv|
32
+ @tags[tagk] = tagv.to_a.compact.join('|') if tagv.is_a?(Array) || tagv.is_a?(Set)
33
+ end
34
+ end
35
+
36
+ def downsample
37
+ "#{interval}s-#{aggregator_for}" if interval
38
+ end
39
+
40
+ private
41
+
42
+ def to_ms(time = Time.now)
43
+ (time.to_f * 1000).to_i
44
+ end
45
+
46
+ def queries
47
+ [{}.tap do |qh|
48
+ qh[:aggregator] = aggregator
49
+ qh[:rate] = rate
50
+ qh[:metric] = metric
51
+ qh[:tags] = tags
52
+ qh[:downsample] = downsample if downsample
53
+ end]
54
+ end
55
+
56
+ def aggregator_for
57
+ case aggregator
58
+ when 'sum', 'avg' then 'avg'
59
+ when 'min' then 'mimmin'
60
+ when 'max' then 'mimmax'
61
+ else 'avg'
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,80 @@
1
+ module CloudInsight
2
+ module Opentsdb
3
+ # :nodoc:
4
+ class QueryParser
5
+ class << self
6
+ def parse(q_string)
7
+ parts = split_for(q_string, ':')
8
+ return nil if parts.size < 2 || parts.size > 3
9
+ metric_query = {}
10
+ metric_query[:aggregator] = parts[0]
11
+ metric_query[:rate] = false
12
+ temp = parts[1]
13
+ if parts.size == 3
14
+ metric_query[:rate] = true if temp.start_with?('rate')
15
+ temp = parts[2]
16
+ end
17
+ query_metric = parse_query_metric(temp)
18
+ QueryParam.new metric_query.merge(query_metric)
19
+ end
20
+
21
+ private
22
+
23
+ def parse_query_metric(metric)
24
+ start_index = metric.index('{')
25
+ return { metric: metric } unless start_index
26
+ {}.tap do |h|
27
+ h[:metric] = metric[0...start_index]
28
+ end_index = metric.index('}')
29
+ h[:tags] = parse_tags metric[(start_index + 1)...end_index].strip
30
+ groups_str = metric[(end_index + 1)..-1]
31
+ if groups_str.size > 5 # length of by{} is 4
32
+ h[:group] = parse_groups groups_str
33
+ h[:group].each { |group| h[:tags][group] ||= ['*'] }
34
+ end
35
+ end
36
+ end
37
+
38
+ def parse_tags(tags)
39
+ return if tags.nil?
40
+ rtags = {}
41
+ split_for(tags, ',').each do |tag|
42
+ tagk, tagv = split_for(tag, '=')
43
+ next if tagk.nil? || tagv.nil?
44
+ rtags[tagk] ||= []
45
+ rtags[tagk].concat tagv.split('|').uniq
46
+ end
47
+ rtags
48
+ end
49
+
50
+ def parse_groups(groups_str)
51
+ start_index = groups_str.index('{')
52
+ end_index = groups_str.index('}')
53
+ groups = groups_str[(start_index + 1)...end_index].strip
54
+ return [] if groups.empty?
55
+ split_for(groups, ',').map(&:strip)
56
+ end
57
+
58
+ def split_for(string, token = ':')
59
+ result = []
60
+ index = start = pos = 0
61
+ is_in_bracket = false
62
+ string.each_char do |char|
63
+ if char == '{'
64
+ is_in_bracket = true
65
+ elsif char == '}'
66
+ is_in_bracket = false
67
+ elsif char == token && !is_in_bracket
68
+ result[index] = string[start...pos]
69
+ index += 1
70
+ start = pos + 1
71
+ end
72
+ pos += 1
73
+ end
74
+ result[index] = string[start...pos]
75
+ result
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,5 @@
1
+ module CloudInsight
2
+ module Opentsdb
3
+ VERSION = '0.0.1'.freeze
4
+ end
5
+ end
@@ -0,0 +1,39 @@
1
+ module CloudInsight
2
+ # :nodoc:
3
+ module Opentsdb
4
+ #:nodoc:
5
+ class << self
6
+ attr_accessor :host, :port
7
+
8
+ def configure
9
+ yield self
10
+ end
11
+
12
+ def host
13
+ @host || 'localhost'
14
+ end
15
+
16
+ def port
17
+ @port || 4242
18
+ end
19
+
20
+ def reset
21
+ @host = nil
22
+ @port = nil
23
+ end
24
+
25
+ def logger
26
+ @logger ||= begin
27
+ Logger.new(STDOUT).tap { |logger| logger.datetime_format = '%Y-%m-%d %H:%M:%S' }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ require 'logger'
34
+ require 'net/http'
35
+ require 'cloudinsight/opentsdb/version'
36
+ require 'cloudinsight/opentsdb/client'
37
+ require 'cloudinsight/opentsdb/query_parser'
38
+ require 'cloudinsight/opentsdb/query_param'
39
+ require 'forwardable'
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opentsdb-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - lizhe
8
+ - luyingrui
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-05-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '10.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '10.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '5.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '5.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: minitest-reporters
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '1.1'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.1'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rubocop
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '0.40'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.40'
70
+ - !ruby/object:Gem::Dependency
71
+ name: guard
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '2.13'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '2.13'
84
+ - !ruby/object:Gem::Dependency
85
+ name: listen
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: '3.0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: guard-minitest
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ version: '2.4'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: '2.4'
112
+ - !ruby/object:Gem::Dependency
113
+ name: mocha
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: '1.1'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '1.1'
126
+ - !ruby/object:Gem::Dependency
127
+ name: pry
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ~>
131
+ - !ruby/object:Gem::Version
132
+ version: '0.10'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ version: '0.10'
140
+ description: A ruby client library for querying data by OpenTSDB HTTP API.
141
+ email:
142
+ - lnz013@qq.com
143
+ - luyingrui@oneapm.com
144
+ executables: []
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - README.md
149
+ - lib/cloudinsight/opentsdb.rb
150
+ - lib/cloudinsight/opentsdb/client.rb
151
+ - lib/cloudinsight/opentsdb/http_client.rb
152
+ - lib/cloudinsight/opentsdb/query_param.rb
153
+ - lib/cloudinsight/opentsdb/query_parser.rb
154
+ - lib/cloudinsight/opentsdb/version.rb
155
+ homepage: https://github.com/cloudinsight/opentsdb-ruby
156
+ licenses:
157
+ - MIT
158
+ metadata:
159
+ allowed_push_host: https://rubygems.org
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: 2.0.0
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.4.5
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Ruby client for OpenTSDB HTTP Query API.
180
+ test_files: []