opentsdb-ruby 0.0.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 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: []