influxer 0.2.2 → 0.2.4

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 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