influxer 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b4166514c7bebd4c2af58c8362902eac3ee2113
4
- data.tar.gz: 4d635a59d2969f7be5134018504d1fd93679d73c
3
+ metadata.gz: a70e770a10a4ba180183d675081265ed34c96a18
4
+ data.tar.gz: ce6d3d39937bc7eeabc4b4076bb9095e6b9eac59
5
5
  SHA512:
6
- metadata.gz: 46fdff670e7c1f5d82dd4c89724c3b2710946bed1e5b584fb0fdddd2b78f7279d5e2a551599592f3ae7d99b2a1fb0f494cfbc8df981b40fada5ce2512cad04e5
7
- data.tar.gz: 7db66507e1616b9dd99dfe55310e73c080c655fd70f2f8506eb6d294e61bfd9fb94401a6caf0ef23de9e66235fafb7afe5e550cdcd68cd8aa1961175fb00d515
6
+ metadata.gz: 23a20e2f8130fa8ad58c1ad961afd71f8bfa3a55ed744dc999857c6dd505b69ddcfa659cc2a885175a6e21005f836e1ee1f6d01850e9fbf898234e8ff6108562
7
+ data.tar.gz: 0373880b57e571673420d63297b81d4ffd8af6dee289adb2c9ccc8332447e736b841c92a0b2f6b11ec04e72ddd066a7ede9742d545706d1607d0a6891e3037b4
data/.hound.yml CHANGED
@@ -1,2 +1,12 @@
1
1
  ruby:
2
- enabled: true
2
+ enabled: true
3
+ config_file: .rubocop.yml
4
+
5
+ javascript:
6
+ enabled: false
7
+
8
+ coffeescript:
9
+ enabled: false
10
+
11
+ sass:
12
+ enabled: false
data/.rubocop.yml ADDED
@@ -0,0 +1,38 @@
1
+ AllCops:
2
+ # Include gemspec and Rakefile
3
+ Include:
4
+ - 'lib/**/*.rb'
5
+ - 'lib/**/*.rake'
6
+ - 'spec/**/*.rb'
7
+ Exclude:
8
+ - 'bin/**/*'
9
+ - 'spec/dummy/**/*'
10
+ RunRailsCops: true
11
+ DisplayCopNames: true
12
+ StyleGuideCopsOnly: false
13
+
14
+ Style/Documentation:
15
+ Exclude:
16
+ - 'spec/**/*.rb'
17
+
18
+ Style/StringLiterals:
19
+ Enabled: false
20
+
21
+ Style/BlockDelimiters:
22
+ Exclude:
23
+ - 'spec/**/*.rb'
24
+
25
+ Metrics/MethodLength:
26
+ Exclude:
27
+ - 'spec/**/*.rb'
28
+
29
+ Metrics/LineLength:
30
+ Max: 100
31
+ Exclude:
32
+ - 'spec/**/*.rb'
33
+
34
+ Rails/Date:
35
+ Enabled: false
36
+
37
+ Rails/TimeZone:
38
+ Enabled: false
data/Changelog.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.2.3
2
+ - Parse fanout queries points to handle _fanouted_ values
3
+ - Add Rubocop config and cleanup code style
4
+
1
5
  ## 0.1.1
2
6
  - Add [anyway_config](https://github.com/palkan/anyway_config)
3
7
  - Add `empty?` method
data/influxer.gemspec CHANGED
@@ -14,10 +14,10 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.files = `git ls-files`.split($/)
16
16
  s.require_paths = ["lib"]
17
-
17
+
18
18
  s.add_runtime_dependency "rails", '~> 4.0'
19
- s.add_dependency "influxdb", "~> 0.1.0", ">= 0.1.8"
20
- s.add_dependency "anyway_config", "~>0", ">= 0.3"
19
+ s.add_dependency "influxdb", "~> 0.1.8"
20
+ s.add_dependency "anyway_config", "~>0.3"
21
21
 
22
22
  s.add_development_dependency "timecop"
23
23
  s.add_development_dependency "simplecov", ">= 0.3.8"
@@ -1,6 +1,7 @@
1
1
  require 'influxdb'
2
2
 
3
3
  module Influxer
4
+ # InfluxDB API client
4
5
  class Client < ::InfluxDB::Client
5
6
  def initialize
6
7
  @instrumenter = ActiveSupport::Notifications.instrumenter
@@ -9,47 +10,46 @@ module Influxer
9
10
 
10
11
  def cached_query(sql)
11
12
  log(sql) do
12
- unless Influxer.config.cache == false
13
- Rails.cache.fetch(normalized_cache_key(sql), cache_options(sql)) { self.query(sql) }
13
+ if Influxer.config.cache == false
14
+ query(sql)
14
15
  else
15
- self.query(sql)
16
+ Rails.cache.fetch(normalized_cache_key(sql), cache_options(sql)) { query(sql) }
16
17
  end
17
18
  end
18
19
  end
19
-
20
+
20
21
  private
21
22
 
22
- def log(sql)
23
- return yield unless logger.debug?
23
+ def log(sql)
24
+ return yield unless logger.debug?
24
25
 
25
- _start = Time.now
26
- res = yield
27
- _duration = (Time.now - _start)*1000
28
-
29
- name = "InfluxDB SQL (#{_duration.round(1)}ms)"
26
+ start_ts = Time.now
27
+ res = yield
28
+ duration = (Time.now - start_ts) * 1000
30
29
 
31
- # bold black name and blue query string
32
- msg = "\e[1m\e[30m#{name}\e[0m \e[34m#{sql}\e[0m"
33
- logger.debug msg
34
- res
35
- end
30
+ name = "InfluxDB SQL (#{duration.round(1)}ms)"
36
31
 
37
- def cache_options(sql=nil)
38
- options = Influxer.config.cache.dup
39
- # if sql contains 'now()' set expires to 1 minute or :cache_now_for value of config.cache if defined
40
- if sql =~ /\snow\(\)/
41
- options[:expires_in] = options[:cache_now_for] || 60
42
- end
43
- options
44
- end
32
+ # bold black name and blue query string
33
+ msg = "\e[1m\e[30m#{name}\e[0m \e[34m#{sql}\e[0m"
34
+ logger.debug msg
35
+ res
36
+ end
45
37
 
46
- # add prefix; remove whitespaces
47
- def normalized_cache_key(sql)
48
- "influxer:#{sql.gsub(/\s*/, '')}"
49
- end
38
+ # if sql contains 'now()' set expires to 1 minute or :cache_now_for value
39
+ # of config.cache if defined
40
+ def cache_options(sql = nil)
41
+ options = Influxer.config.cache.dup
42
+ options[:expires_in] = (options[:cache_now_for] || 60) if sql =~ /\snow\(\)/
43
+ options
44
+ end
50
45
 
51
- def logger
52
- Rails.logger
53
- end
46
+ # add prefix; remove whitespaces
47
+ def normalized_cache_key(sql)
48
+ "influxer:#{sql.gsub(/\s*/, '')}"
49
+ end
50
+
51
+ def logger
52
+ Rails.logger
53
+ end
54
54
  end
55
- end
55
+ end
@@ -1,12 +1,13 @@
1
1
  require 'anyway'
2
2
 
3
3
  module Influxer
4
+ # Influxer configuration
4
5
  class Config < Anyway::Config
5
6
  config_name :influxdb
6
7
 
7
- attr_config database: 'db',
8
+ attr_config database: 'db',
8
9
  host: 'localhost',
9
- port: 8083,
10
+ port: 8086,
10
11
  username: 'root',
11
12
  password: 'root',
12
13
  use_ssl: false,
@@ -22,9 +23,7 @@ module Influxer
22
23
  def load
23
24
  super
24
25
  # we want pass @cache value as options to cache store, so we want it to be a Hash
25
- if @cache == true
26
- @cache = {}.with_indifferent_access
27
- end
26
+ @cache = {}.with_indifferent_access if @cache == true
28
27
  end
29
28
  end
30
- end
29
+ end
@@ -2,11 +2,11 @@ require 'influxer'
2
2
  require 'rails'
3
3
 
4
4
  module Influxer
5
- class Engine < Rails::Engine
6
- initializer "extend ActiveRecord with influxer" do |app|
5
+ class Engine < Rails::Engine # :nodoc:
6
+ initializer "extend ActiveRecord with influxer" do |_app|
7
7
  ActiveSupport.on_load(:active_record) do
8
8
  ActiveRecord::Base.send :include, Influxer::Model
9
9
  end
10
- end
10
+ end
11
11
  end
12
- end
12
+ end
@@ -1,53 +1,65 @@
1
1
  module Influxer
2
- module Fanout
2
+ module Fanout # :nodoc: all
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
6
  class_attribute :fanouts, :fanouts_by_name, :fanout_options
7
7
  self.fanouts = []
8
8
  self.fanouts_by_name = {} # to use within `fanout?`
9
- self.fanout_options = {delimeter: "_"}
10
- end
11
-
9
+ self.fanout_options = { delimeter: "_" }
10
+ end
11
+
12
12
  module ClassMethods
13
13
  # Define fanouts for metrics as array of keys.
14
14
  # Order of keys is important.
15
15
  # Fanout delimeter can be set with 'delimiter' option (defaults to '_').
16
- #
16
+ #
17
17
  # class MyMetrics < Influxer::Metrics
18
18
  # set_series "my_points"
19
19
  # fanout :account_id, :user_id
20
20
  # end
21
- #
21
+ #
22
22
  # MyMetrics.where(user_id: 1).where(account_id: 10)
23
23
  # # select * from my_points_account_id_10_user_id_1
24
- #
24
+ #
25
25
  # class MyMetrics < Influxer::Metrics
26
26
  # set_series "my_points"
27
27
  # fanout :account_id, :user_id, delimiter: "."
28
28
  # end
29
- #
29
+ #
30
30
  # MyMetrics.where(user_id: 1).where(account_id: 10).where("req_time > 1000")
31
31
  # # select * from my_points.account_id.10.user_id.1 where req_time > 1000
32
-
32
+
33
33
  def fanout(*args, **hargs)
34
- self.fanout_options = self.fanout_options.merge hargs
34
+ self.fanout_options = fanout_options.merge hargs
35
+
36
+ names = args.map(&:to_s)
35
37
 
36
- names = args.map(&:to_s) # convert all to strings (because args can be both Symbols and Strings)
37
-
38
- self.fanouts = (self.fanouts+names).uniq
38
+ self.fanouts = (fanouts + names).uniq
39
39
 
40
40
  names_hash = {}
41
41
  names.each do |name|
42
42
  names_hash[name] = 1
43
43
  end
44
44
 
45
- self.fanouts_by_name = self.fanouts_by_name.merge names_hash
46
- end
45
+ self.fanouts_by_name = fanouts_by_name.merge names_hash
46
+ end
47
47
 
48
48
  def fanout?(key)
49
- self.fanouts_by_name.key?(key.to_s)
49
+ fanouts_by_name.key?(key.to_s)
50
+ end
51
+
52
+ def fanout_rxp
53
+ return @fanout_rxp unless @fanout_rxp.nil?
54
+ series_name = Regexp.escape(quoted_series[1..-2])
55
+ del = Regexp.escape(fanout_options[:delimeter])
56
+ rstr = "^#{series_name}"
57
+ fanouts.each do |f_name|
58
+ rstr += "(?:#{del}#{Regexp.escape(f_name)}#{del}(?<#{f_name}>[^#{del}]+))?"
59
+ end
60
+ rstr += "$"
61
+ @fanout_rxp = Regexp.new(rstr)
50
62
  end
51
63
  end
52
64
  end
53
- end
65
+ end
@@ -7,6 +7,7 @@ module Influxer
7
7
  class MetricsError < StandardError; end
8
8
  class MetricsInvalid < MetricsError; end
9
9
 
10
+ # Base class for InfluxDB querying and writing
10
11
  class Metrics
11
12
  include ActiveModel::Model
12
13
  include ActiveModel::Validations
@@ -19,13 +20,18 @@ module Influxer
19
20
 
20
21
  class << self
21
22
  # delegate query functions to all
22
- delegate *(
23
- [
24
- :write, :select, :where, :group,
25
- :merge, :time, :past, :since, :limit,
26
- :fill, :delete_all
27
- ]+Influxer::Calculations::CALCULATION_METHODS),
28
- to: :all
23
+ delegate(
24
+ *(
25
+ [
26
+ :write, :select, :where, :group,
27
+ :merge, :time, :past, :since, :limit,
28
+ :fill, :delete_all
29
+ ] + Influxer::Calculations::CALCULATION_METHODS
30
+ ),
31
+ to: :all
32
+ )
33
+
34
+ attr_reader :series
29
35
 
30
36
  def attributes(*attrs)
31
37
  attrs.each do |name|
@@ -45,9 +51,9 @@ module Influxer
45
51
 
46
52
  def set_series(*args)
47
53
  if args.empty?
48
- matches = self.to_s.match(/^(.*)Metrics$/)
54
+ matches = to_s.match(/^(.*)Metrics$/)
49
55
  if matches.nil?
50
- @series = self.superclass.respond_to?(:series) ? self.superclass.series : self.to_s.underscore
56
+ @series = superclass.respond_to?(:series) ? superclass.series : to_s.underscore
51
57
  else
52
58
  @series = matches[1].split("::").join("_").underscore
53
59
  end
@@ -58,10 +64,6 @@ module Influxer
58
64
  end
59
65
  end
60
66
 
61
- def series
62
- @series
63
- end
64
-
65
67
  def all
66
68
  if current_scope
67
69
  current_scope.clone
@@ -69,6 +71,23 @@ module Influxer
69
71
  default_scoped
70
72
  end
71
73
  end
74
+
75
+ def quoted_series(val = @series, instance = nil)
76
+ case val
77
+ when Regexp
78
+ val.inspect
79
+ when Proc
80
+ quoted_series(val.call(instance))
81
+ when Array
82
+ if val.length > 1
83
+ "merge(#{ val.map { |s| quoted_series(s) }.join(',') })"
84
+ else
85
+ quoted_series(val.first)
86
+ end
87
+ else
88
+ '"' + val.to_s.gsub(/\"/) { %q(\") } + '"'
89
+ end
90
+ end
72
91
  end
73
92
 
74
93
  def initialize(attributes = {})
@@ -78,7 +97,7 @@ module Influxer
78
97
  end
79
98
 
80
99
  def write
81
- raise MetricsError.new('Cannot write the same metrics twice') if self.persisted?
100
+ fail MetricsError if self.persisted?
82
101
 
83
102
  return false if self.invalid?
84
103
 
@@ -89,8 +108,8 @@ module Influxer
89
108
  end
90
109
 
91
110
  def write!
92
- raise MetricsInvalid.new('Validation failed') if self.invalid?
93
- self.write
111
+ fail MetricsInvalid if self.invalid?
112
+ write
94
113
  end
95
114
 
96
115
  def write_point
@@ -103,39 +122,19 @@ module Influxer
103
122
  end
104
123
 
105
124
  def series
106
- quote_series(self.class.series)
125
+ self.class.quoted_series(self.class.series, self)
107
126
  end
108
127
 
109
128
  def client
110
129
  Influxer.client
111
130
  end
112
131
 
113
-
114
132
  attributes :time
115
133
 
116
-
117
- def quote_series(val)
118
- case val
119
- when Regexp
120
- val.inspect
121
- when Proc
122
- quote_series(self.class.series.call(self))
123
- when Array
124
- if val.length > 1
125
- "merge(#{ val.map{ |s| quote_series(s) }.join(',') })"
126
- else
127
- quote_series(val.first)
128
- end
129
- else
130
- '"'+val.to_s.gsub(/\"/){ %q{\"} }+'"'
131
- end
132
- end
133
-
134
134
  private
135
135
 
136
136
  def unquote(name)
137
- name.gsub(/(\A['"]|['"]\z)/,'')
137
+ name.gsub(/(\A['"]|['"]\z)/, '')
138
138
  end
139
-
140
139
  end
141
- end
140
+ end
@@ -1,9 +1,9 @@
1
1
  module Influxer
2
- module Calculations
3
- CALCULATION_METHODS =
2
+ module Calculations #:nodoc:
3
+ CALCULATION_METHODS =
4
4
  [
5
- :count, :min, :max, :mean,
6
- :mode, :median, :distinct, :derivative,
5
+ :count, :min, :max, :mean,
6
+ :mode, :median, :distinct, :derivative,
7
7
  :stddev, :sum, :first, :last, :difference,
8
8
  :percentile, :histogram, :top, :bottom
9
9
  ]
@@ -11,11 +11,11 @@ module Influxer
11
11
  CALCULATION_METHODS.each do |name|
12
12
  class_eval <<-CODE, __FILE__, __LINE__ + 1
13
13
  def #{name}(val, option=nil) # def count(val)
14
- @values[:has_calculations] = true # @values[:has_calculations] = true
15
- select_values << "#{name}(\#\{val\}\#\{option ? ','+option.to_s : ''\})" # select_values << "count(\#\{val\})"
14
+ @values[:has_calculations] = true # @values[:has_calculations] = true
15
+ select_values << "#{name}(\#\{val\}\#\{option ? ','+option.to_s : ''\})" # select_values << "count(\#\{val\})"
16
16
  self # self
17
17
  end # end
18
18
  CODE
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -1,11 +1,11 @@
1
1
  module Influxer
2
- module FanoutQuery
3
- # Instance methods are included to Relation
2
+ module FanoutQuery #:nodoc:
3
+ # Instance methods are included to Relation
4
4
  def build_fanout(key, val)
5
5
  @values[:has_fanout] = true
6
6
  if val.is_a?(Regexp)
7
7
  @values[:fanout_rxp] = true
8
- fanout_values[key.to_s] = val.inspect[1..-2]
8
+ fanout_values[key.to_s] = val.inspect[1..-2]
9
9
  else
10
10
  fanout_values[key.to_s] = val.to_s
11
11
  end
@@ -19,15 +19,31 @@ module Influxer
19
19
  fan_parts << name
20
20
  fan_parts << fanout_values[name]
21
21
  end
22
- end
22
+ end
23
23
  if @values[:fanout_rxp] == true
24
- "merge(/^#{ fan_parts.join( @klass.fanout_options[:delimeter] ) }$/)"
24
+ "/^#{ fan_parts.join(@klass.fanout_options[:delimeter]) }$/"
25
25
  else
26
- @instance.quote_series(fan_parts.join(@klass.fanout_options[:delimeter]))
26
+ @klass.quoted_series(fan_parts.join(@klass.fanout_options[:delimeter]))
27
27
  end
28
28
  else
29
29
  @instance.series
30
30
  end
31
31
  end
32
+
33
+ def prepare_fanout_points(hash)
34
+ hash.each do |k, v|
35
+ data = extract_values(k)
36
+ v.each { |p| p.merge!(data) } unless data.empty?
37
+ end
38
+ hash
39
+ end
40
+
41
+ private
42
+
43
+ # Extract fanout values from series name
44
+ def extract_values(name)
45
+ data = @klass.fanout_rxp.match(name)
46
+ Hash[data.names.zip(data.captures)].delete_if { |_k, v| v.nil? }
47
+ end
32
48
  end
33
- end
49
+ end
@@ -1,5 +1,5 @@
1
1
  module Influxer
2
- module TimeQuery
2
+ module TimeQuery #:nodoc:
3
3
  TIME_ALIASES = {
4
4
  hour: '1h',
5
5
  minute: '1m',
@@ -7,29 +7,29 @@ module Influxer
7
7
  ms: '1u',
8
8
  week: '1w',
9
9
  day: '1d',
10
- month: '30d'
10
+ month: '30d'
11
11
  }
12
12
 
13
13
  # Add group value to relation. To be used instead of `group("time(...)").
14
14
  # Accepts symbols and strings.
15
- #
15
+ #
16
16
  # You can set fill value within options.
17
17
  #
18
18
  # Metrics.time(:hour)
19
19
  # # select * from metrics group by time(1h)
20
- #
20
+ #
21
21
  # Metrics.time("4d", fill: 0)
22
22
  # # select * from metrics group by time(4d) fill(0)
23
23
 
24
- def time(val, options={})
24
+ def time(val, options = {})
25
25
  if val.is_a?(Symbol)
26
- @values[:time] = TIME_ALIASES[val] || '1'+val.to_s
26
+ @values[:time] = TIME_ALIASES[val] || '1' + val.to_s
27
27
  else
28
28
  @values[:time] = val
29
29
  end
30
30
 
31
31
  unless options[:fill].nil?
32
- fill( (options[:fill] == :null) ? 'null' : options[:fill].to_i)
32
+ fill((options[:fill] == :null) ? 'null' : options[:fill].to_i)
33
33
  end
34
34
  self
35
35
  end
@@ -39,10 +39,10 @@ module Influxer
39
39
  #
40
40
  # Metrics.past(:hour)
41
41
  # # select * from metrics where time > now() - 1h
42
- #
42
+ #
43
43
  # Metrics.past(:d)
44
- # # select * from metrics where time > now() - 1d
45
- #
44
+ # # select * from metrics where time > now() - 1d
45
+ #
46
46
  # Metrics.past(2.days)
47
47
  # # select * from metrics where time > now() - 172800s
48
48
 
@@ -60,9 +60,9 @@ module Influxer
60
60
  # Shortcut to define start point of the time interval.
61
61
  # Accepts DateTime objects.
62
62
  #
63
- # Metrics.since(1.day.ago) # assume that now is 2014-12-31 12:00:00 UTC
63
+ # Metrics.since(1.day.ago) # assume that now is 2014-12-31 12:00:00 UTC
64
64
  # # select * from metrics where time > 1420027200s
65
- #
65
+ #
66
66
  # Metrics.since(Time.local(2014,12,31))
67
67
  # # select * from metrics where time > 1419984000s
68
68
 
@@ -70,4 +70,4 @@ module Influxer
70
70
  where("time > #{val.to_i}s")
71
71
  end
72
72
  end
73
- end
73
+ end