librato-rack 1.1.1 → 2.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.
- data/CHANGELOG.md +3 -0
 - data/README.md +43 -20
 - data/lib/librato/collector/aggregator.rb +45 -25
 - data/lib/librato/collector/counter_cache.rb +38 -24
 - data/lib/librato/collector.rb +9 -3
 - data/lib/librato/rack/configuration.rb +24 -16
 - data/lib/librato/rack/errors.rb +2 -0
 - data/lib/librato/rack/tracker.rb +11 -16
 - data/lib/librato/rack/validating_queue.rb +8 -6
 - data/lib/librato/rack/version.rb +1 -1
 - data/lib/librato/rack.rb +6 -12
 - data/test/apps/custom.ru +5 -1
 - data/test/integration/custom_test.rb +20 -6
 - data/test/integration/no_stats_test.rb +2 -3
 - data/test/integration/no_suites_test.rb +4 -5
 - data/test/integration/queue_wait_test.rb +4 -10
 - data/test/integration/request_test.rb +20 -23
 - data/test/integration/suites_test.rb +5 -7
 - data/test/remote/tracker_test.rb +53 -45
 - data/test/support/environment_helpers.rb +1 -1
 - data/test/test_helper.rb +1 -1
 - data/test/unit/collector/aggregator_test.rb +70 -31
 - data/test/unit/collector/counter_cache_test.rb +73 -33
 - data/test/unit/collector/group_test.rb +20 -16
 - data/test/unit/collector_test.rb +6 -5
 - data/test/unit/rack/configuration_test.rb +19 -8
 - data/test/unit/rack/tracker_test.rb +41 -5
 - data.tar.gz.sig +0 -0
 - metadata +83 -42
 - metadata.gz.sig +1 -0
 - checksums.yaml +0 -7
 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -49,7 +49,7 @@ If you don't have a Metrics account already, [sign up](https://metrics.librato.c 
     | 
|
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
            By default you can use `LIBRATO_USER` and `LIBRATO_TOKEN` to pass your account data to the middleware. While these are the only required variables, there are a few more optional environment variables you may find useful.
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
            * ` 
     | 
| 
      
 52 
     | 
    
         
            +
            * `LIBRATO_TAGS` - the default tags to use for submitted metrics. Format is comma-separated key=value pairs, e.g. `region=us-east,az=b`. If not set, `host` of the executing machine is detected and set as default tag
         
     | 
| 
       53 
53 
     | 
    
         
             
            * `LIBRATO_SUITES` - manage which metrics librato-rack will report. See more in [metrics suites](#metric-suites).
         
     | 
| 
       54 
54 
     | 
    
         
             
            * `LIBRATO_PREFIX` - a prefix which will be prepended to all metric names
         
     | 
| 
       55 
55 
     | 
    
         
             
            * `LIBRATO_LOG_LEVEL` - see logging section for more
         
     | 
| 
         @@ -74,19 +74,36 @@ See the [configuration class](https://github.com/librato/librato-rack/blob/maste 
     | 
|
| 
       74 
74 
     | 
    
         | 
| 
       75 
75 
     | 
    
         
             
            If you are using the [Librato Metrics Heroku addon](https://addons.heroku.com/librato), your `LIBRATO_USER` and `LIBRATO_TOKEN` environment variables will already be set in your Heroku environment. If you are running without the addon you will need to provide them yourself.
         
     | 
| 
       76 
76 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
      
 77 
     | 
    
         
            +
            NOTE: if Heroku idles your application no measurements will be sent until it receives another request and is restarted. If you see intermittent gaps in your measurements during periods of low traffic this is the most likely cause.
         
     | 
| 
       78 
78 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
      
 79 
     | 
    
         
            +
            ## Default Tags
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
      
 81 
     | 
    
         
            +
            Librato Metrics supports tagged measurements that are associated with a metric, one or more tag pairs, and a point in time. For more information on tagged measurements, visit our [API documentation](https://www.librato.com/docs/api/#measurements).
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ##### Detected Tags
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            By default, `host` is detected and applied as a default tag for submitted measurements. Optionally, you can override the detected values, e.g. `LIBRATO_TAGS=host=myapp-prod-1`
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ##### Custom Tags
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            In addition to the default tags, you can also provide custom tags:
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 92 
     | 
    
         
            +
            config = Librato::Rack::Configuration.new
         
     | 
| 
      
 93 
     | 
    
         
            +
            config.user = 'myuser@mysite.com'
         
     | 
| 
      
 94 
     | 
    
         
            +
            config.token = 'mytoken'
         
     | 
| 
      
 95 
     | 
    
         
            +
            config.tags = { service: 'myapp', environment: 'production', host: 'myapp-prod-1' }
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            use Librato::Rack, :config => config
         
     | 
| 
      
 98 
     | 
    
         
            +
            ```
         
     | 
| 
       82 
99 
     | 
    
         | 
| 
       83 
100 
     | 
    
         
             
            ##### Metric Suites
         
     | 
| 
       84 
101 
     | 
    
         | 
| 
       85 
102 
     | 
    
         
             
            The metrics recorded by `librato-rack` are organized into named metric suites that can be selectively enabled/disabled:
         
     | 
| 
       86 
103 
     | 
    
         | 
| 
       87 
104 
     | 
    
         
             
            * `rack`: The `rack.request.total`, `rack.request.time`, `rack.request.slow`, and `rack.request.queue.time` metrics
         
     | 
| 
       88 
     | 
    
         
            -
            * `rack_status`:  
     | 
| 
       89 
     | 
    
         
            -
            * `rack_method`:  
     | 
| 
      
 105 
     | 
    
         
            +
            * `rack_status`: `rack.request.status` metric with `status` tag name and HTTP status code tag value, e.g. `status=200`
         
     | 
| 
      
 106 
     | 
    
         
            +
            * `rack_method`: `rack.request.method` metric with `method` tag name and HTTP method tag value, e.g. `method=POST`
         
     | 
| 
       90 
107 
     | 
    
         | 
| 
       91 
108 
     | 
    
         
             
            All three of the metric suites listed above are enabled by default.
         
     | 
| 
       92 
109 
     | 
    
         | 
| 
         @@ -116,14 +133,23 @@ Tracking anything that interests you is easy with Metrics. There are four primar 
     | 
|
| 
       116 
133 
     | 
    
         | 
| 
       117 
134 
     | 
    
         
             
            Use for tracking a running total of something _across_ requests, examples:
         
     | 
| 
       118 
135 
     | 
    
         | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
      
 136 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 137 
     | 
    
         
            +
            # increment the 'sales_completed' metric by one
         
     | 
| 
      
 138 
     | 
    
         
            +
            Librato.increment 'sales.completed'
         
     | 
| 
      
 139 
     | 
    
         
            +
            # => {:host=>"myapp-prod-1"}
         
     | 
| 
       121 
140 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
      
 141 
     | 
    
         
            +
            # increment by five
         
     | 
| 
      
 142 
     | 
    
         
            +
            Librato.increment 'items.purchased', by: 5
         
     | 
| 
      
 143 
     | 
    
         
            +
            # => {:host=>"myapp-prod-1"}
         
     | 
| 
       124 
144 
     | 
    
         | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
      
 145 
     | 
    
         
            +
            # increment with custom per-measurement tags
         
     | 
| 
      
 146 
     | 
    
         
            +
            Librato.increment 'user.purchases', tags: { user_id: user.id, currency: 'USD' }
         
     | 
| 
      
 147 
     | 
    
         
            +
            # => {:user_id=>43, :currency=>"USD"}
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            # increment with custom per-measurement tags and inherited default tags
         
     | 
| 
      
 150 
     | 
    
         
            +
            Librato.increment 'user.purchases', tags: { user_id: user.id, currency: 'USD' }, inherit_tags: true
         
     | 
| 
      
 151 
     | 
    
         
            +
            # => {:host=>"myapp-prod-1", :user_id=>43, :currency=>"USD"}
         
     | 
| 
      
 152 
     | 
    
         
            +
            ```
         
     | 
| 
       127 
153 
     | 
    
         | 
| 
       128 
154 
     | 
    
         
             
            Other things you might track this way: user signups, requests of a certain type or to a certain route, total jobs queued or processed, emails sent or received
         
     | 
| 
       129 
155 
     | 
    
         | 
| 
         @@ -131,10 +157,10 @@ Other things you might track this way: user signups, requests of a certain type 
     | 
|
| 
       131 
157 
     | 
    
         | 
| 
       132 
158 
     | 
    
         
             
            Note that `increment` is primarily used for tracking the rate of occurrence of some event. Given this increment metrics are _continuous by default_: after being called on a metric once they will report on every interval, reporting zeros for any interval when increment was not called on the metric.
         
     | 
| 
       133 
159 
     | 
    
         | 
| 
       134 
     | 
    
         
            -
            Especially with custom  
     | 
| 
      
 160 
     | 
    
         
            +
            Especially with custom per-measurement tags you may want the opposite behavior - reporting a measurement only during intervals where `increment` was called on the metric:
         
     | 
| 
       135 
161 
     | 
    
         | 
| 
       136 
162 
     | 
    
         
             
                # report a value for 'user.uploaded_file' only during non-zero intervals
         
     | 
| 
       137 
     | 
    
         
            -
                Librato.increment 'user.uploaded_file', : 
     | 
| 
      
 163 
     | 
    
         
            +
                Librato.increment 'user.uploaded_file', tags: { user: user.id, bucket: bucket.name }, sporadic: true
         
     | 
| 
       138 
164 
     | 
    
         | 
| 
       139 
165 
     | 
    
         
             
            #### measure
         
     | 
| 
       140 
166 
     | 
    
         | 
| 
         @@ -142,8 +168,8 @@ Use when you want to track an average value _per_-request. Examples: 
     | 
|
| 
       142 
168 
     | 
    
         | 
| 
       143 
169 
     | 
    
         
             
                Librato.measure 'user.social_graph.nodes', 212
         
     | 
| 
       144 
170 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
                # report from  
     | 
| 
       146 
     | 
    
         
            -
                Librato.measure 'jobs.queued', 3, : 
     | 
| 
      
 171 
     | 
    
         
            +
                # report from custom per-measurement tags
         
     | 
| 
      
 172 
     | 
    
         
            +
                Librato.measure 'jobs.queued', 3, tags: { priority: 'high', worker: 'worker.12' }
         
     | 
| 
       147 
173 
     | 
    
         | 
| 
       148 
174 
     | 
    
         
             
            #### timing
         
     | 
| 
       149 
175 
     | 
    
         | 
| 
         @@ -205,14 +231,11 @@ If you are using `librato-rack` with sidekiq, [see these notes about setup](http 
     | 
|
| 
       205 
231 
     | 
    
         | 
| 
       206 
232 
     | 
    
         
             
            ## Cross-Process Aggregation
         
     | 
| 
       207 
233 
     | 
    
         | 
| 
       208 
     | 
    
         
            -
            `librato-rack` submits measurements back to the Librato platform on a _per-process_ basis. By default these measurements are then combined into a single measurement per  
     | 
| 
      
 234 
     | 
    
         
            +
            `librato-rack` submits measurements back to the Librato platform on a _per-process_ basis. By default these measurements are then combined into a single measurement per default tags (detects `host`) before persisting the data.
         
     | 
| 
       209 
235 
     | 
    
         | 
| 
       210 
236 
     | 
    
         
             
            For example if you have 4 hosts with 8 unicorn instances each (i.e. 32 processes total), on the Metrics site you'll find 4 data streams (1 per host) instead of 32.
         
     | 
| 
       211 
237 
     | 
    
         
             
            Current pricing applies after aggregation, so in this case you will be charged for 4 streams instead of 32.
         
     | 
| 
       212 
238 
     | 
    
         | 
| 
       213 
     | 
    
         
            -
            If you want to report per-process instead, you can set `source_pids` to `true` in
         
     | 
| 
       214 
     | 
    
         
            -
            your config, which will append the process id to the source name used by each thread.
         
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
239 
     | 
    
         
             
            ## Troubleshooting
         
     | 
| 
       217 
240 
     | 
    
         | 
| 
       218 
241 
     | 
    
         
             
            Note that it may take 2-3 minutes for the first results to show up in your Metrics account after you have started your servers with `librato-rack` enabled and the first request has been received.
         
     | 
| 
         @@ -5,16 +5,19 @@ module Librato 
     | 
|
| 
       5 
5 
     | 
    
         
             
                # maintains storage of timing and measurement type measurements
         
     | 
| 
       6 
6 
     | 
    
         
             
                #
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Aggregator
         
     | 
| 
       8 
     | 
    
         
            -
                   
     | 
| 
      
 8 
     | 
    
         
            +
                  SEPARATOR = "$$"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                  extend Forwardable
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  def_delegators :@cache, :empty?, :prefix, :prefix=
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
                  attr_reader :default_tags
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       14 
16 
     | 
    
         
             
                  def initialize(options={})
         
     | 
| 
       15 
17 
     | 
    
         
             
                    @cache = Librato::Metrics::Aggregator.new(prefix: options[:prefix])
         
     | 
| 
       16 
18 
     | 
    
         
             
                    @percentiles = {}
         
     | 
| 
       17 
19 
     | 
    
         
             
                    @lock = Mutex.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @default_tags = options.fetch(:default_tags, {})
         
     | 
| 
       18 
21 
     | 
    
         
             
                  end
         
     | 
| 
       19 
22 
     | 
    
         | 
| 
       20 
23 
     | 
    
         
             
                  def [](key)
         
     | 
| 
         @@ -26,13 +29,13 @@ module Librato 
     | 
|
| 
       26 
29 
     | 
    
         
             
                  def fetch(key, options={})
         
     | 
| 
       27 
30 
     | 
    
         
             
                    return nil if @cache.empty?
         
     | 
| 
       28 
31 
     | 
    
         
             
                    return fetch_percentile(key, options) if options[:percentile]
         
     | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
       30 
     | 
    
         
            -
                     
     | 
| 
       31 
     | 
    
         
            -
                    @lock.synchronize {  
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 32 
     | 
    
         
            +
                    measurements = nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                    tags = options[:tags] || @default_tags
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @lock.synchronize { measurements = @cache.queued[:measurements] }
         
     | 
| 
      
 35 
     | 
    
         
            +
                    measurements.each do |metric|
         
     | 
| 
       33 
36 
     | 
    
         
             
                      if metric[:name] == key.to_s
         
     | 
| 
       34 
     | 
    
         
            -
                        return metric if ! 
     | 
| 
       35 
     | 
    
         
            -
                        return metric if  
     | 
| 
      
 37 
     | 
    
         
            +
                        return metric if !tags && !metric[:tags]
         
     | 
| 
      
 38 
     | 
    
         
            +
                        return metric if tags == metric[:tags]
         
     | 
| 
       36 
39 
     | 
    
         
             
                      end
         
     | 
| 
       37 
40 
     | 
    
         
             
                    end
         
     | 
| 
       38 
41 
     | 
    
         
             
                    nil
         
     | 
| 
         @@ -89,18 +92,27 @@ module Librato 
     | 
|
| 
       89 
92 
     | 
    
         
             
                    if args.length > 1 and args[-1].respond_to?(:each)
         
     | 
| 
       90 
93 
     | 
    
         
             
                      options = args[-1]
         
     | 
| 
       91 
94 
     | 
    
         
             
                    end
         
     | 
| 
       92 
     | 
    
         
            -
                    source = options[:source]
         
     | 
| 
       93 
     | 
    
         
            -
                    percentiles = Array(options[:percentile])
         
     | 
| 
       94 
95 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
                     
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                    percentiles = Array(options[:percentile])
         
     | 
| 
      
 97 
     | 
    
         
            +
                    source = options[:source]
         
     | 
| 
      
 98 
     | 
    
         
            +
                    tags_option = options[:tags]
         
     | 
| 
      
 99 
     | 
    
         
            +
                    tags_option = { source: source } if source && !tags_option
         
     | 
| 
      
 100 
     | 
    
         
            +
                    tags =
         
     | 
| 
      
 101 
     | 
    
         
            +
                      if tags_option && options[:inherit_tags]
         
     | 
| 
      
 102 
     | 
    
         
            +
                        @default_tags.merge(tags_option)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      elsif tags_option
         
     | 
| 
      
 104 
     | 
    
         
            +
                        tags_option
         
     | 
| 
       98 
105 
     | 
    
         
             
                      else
         
     | 
| 
       99 
     | 
    
         
            -
                        @ 
     | 
| 
      
 106 
     | 
    
         
            +
                        @default_tags
         
     | 
| 
       100 
107 
     | 
    
         
             
                      end
         
     | 
| 
       101 
108 
     | 
    
         | 
| 
      
 109 
     | 
    
         
            +
                    @lock.synchronize do
         
     | 
| 
      
 110 
     | 
    
         
            +
                      payload = { value: value }
         
     | 
| 
      
 111 
     | 
    
         
            +
                      payload.merge!({ tags: tags }) if tags
         
     | 
| 
      
 112 
     | 
    
         
            +
                      @cache.add event => payload
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
       102 
114 
     | 
    
         
             
                      percentiles.each do |perc|
         
     | 
| 
       103 
     | 
    
         
            -
                        store = fetch_percentile_store(event,  
     | 
| 
      
 115 
     | 
    
         
            +
                        store = fetch_percentile_store(event, payload)
         
     | 
| 
       104 
116 
     | 
    
         
             
                        store[:reservoir] << value
         
     | 
| 
       105 
117 
     | 
    
         
             
                        track_percentile(store, perc)
         
     | 
| 
       106 
118 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -120,30 +132,38 @@ module Librato 
     | 
|
| 
       120 
132 
     | 
    
         
             
                  end
         
     | 
| 
       121 
133 
     | 
    
         | 
| 
       122 
134 
     | 
    
         
             
                  def fetch_percentile(key, options)
         
     | 
| 
       123 
     | 
    
         
            -
                    store = fetch_percentile_store(key, options 
     | 
| 
      
 135 
     | 
    
         
            +
                    store = fetch_percentile_store(key, options)
         
     | 
| 
       124 
136 
     | 
    
         
             
                    return nil unless store
         
     | 
| 
       125 
137 
     | 
    
         
             
                    store[:reservoir].percentile(options[:percentile])
         
     | 
| 
       126 
138 
     | 
    
         
             
                  end
         
     | 
| 
       127 
139 
     | 
    
         | 
| 
       128 
     | 
    
         
            -
                  def fetch_percentile_store(event,  
     | 
| 
       129 
     | 
    
         
            -
                    keyname =  
     | 
| 
      
 140 
     | 
    
         
            +
                  def fetch_percentile_store(event, options)
         
     | 
| 
      
 141 
     | 
    
         
            +
                    keyname = event
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                    if options[:tags]
         
     | 
| 
      
 144 
     | 
    
         
            +
                      keyname = Librato::Metrics::Util.build_key_for(keyname, options[:tags])
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
       130 
147 
     | 
    
         
             
                    @percentiles[keyname] ||= {
         
     | 
| 
      
 148 
     | 
    
         
            +
                      name: event,
         
     | 
| 
       131 
149 
     | 
    
         
             
                      reservoir: Hetchy::Reservoir.new(size: 1000),
         
     | 
| 
       132 
150 
     | 
    
         
             
                      percs: Set.new
         
     | 
| 
       133 
151 
     | 
    
         
             
                    }
         
     | 
| 
      
 152 
     | 
    
         
            +
                    @percentiles[keyname].merge!({ tags: options[:tags] }) if options && options[:tags]
         
     | 
| 
      
 153 
     | 
    
         
            +
                    @percentiles[keyname]
         
     | 
| 
       134 
154 
     | 
    
         
             
                  end
         
     | 
| 
       135 
155 
     | 
    
         | 
| 
       136 
156 
     | 
    
         
             
                  def flush_percentiles(queue, opts)
         
     | 
| 
       137 
157 
     | 
    
         
             
                    @percentiles.each do |key, val|
         
     | 
| 
       138 
     | 
    
         
            -
                      metric, source = key.split(SOURCE_SEPARATOR)
         
     | 
| 
       139 
158 
     | 
    
         
             
                      val[:percs].each do |perc|
         
     | 
| 
       140 
159 
     | 
    
         
             
                        perc_name = perc.to_s[0,5].gsub('.','')
         
     | 
| 
       141 
     | 
    
         
            -
                        payload = 
     | 
| 
       142 
     | 
    
         
            -
                           
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                           
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
      
 160 
     | 
    
         
            +
                        payload =
         
     | 
| 
      
 161 
     | 
    
         
            +
                          if val[:tags]
         
     | 
| 
      
 162 
     | 
    
         
            +
                            { value: val[:reservoir].percentile(perc), tags: val[:tags] }
         
     | 
| 
      
 163 
     | 
    
         
            +
                          else
         
     | 
| 
      
 164 
     | 
    
         
            +
                            val[:reservoir].percentile(perc)
         
     | 
| 
      
 165 
     | 
    
         
            +
                          end
         
     | 
| 
      
 166 
     | 
    
         
            +
                        queue.add "#{val[:name]}.p#{perc_name}" => payload
         
     | 
| 
       147 
167 
     | 
    
         
             
                      end
         
     | 
| 
       148 
168 
     | 
    
         
             
                    end
         
     | 
| 
       149 
169 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -158,4 +178,4 @@ module Librato 
     | 
|
| 
       158 
178 
     | 
    
         
             
                end
         
     | 
| 
       159 
179 
     | 
    
         | 
| 
       160 
180 
     | 
    
         
             
              end
         
     | 
| 
       161 
     | 
    
         
            -
            end
         
     | 
| 
      
 181 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "json"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Librato
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Collector
         
     | 
| 
       3 
5 
     | 
    
         
             
                # maintains storage of a set of incrementable, counter-like
         
     | 
| 
         @@ -11,10 +13,13 @@ module Librato 
     | 
|
| 
       11 
13 
     | 
    
         | 
| 
       12 
14 
     | 
    
         
             
                  def_delegators :@cache, :empty?
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
                   
     | 
| 
      
 16 
     | 
    
         
            +
                  attr_reader :default_tags
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def initialize(options={})
         
     | 
| 
       15 
19 
     | 
    
         
             
                    @cache = {}
         
     | 
| 
       16 
20 
     | 
    
         
             
                    @lock = Mutex.new
         
     | 
| 
       17 
21 
     | 
    
         
             
                    @sporadics = Set.new
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @default_tags = options.fetch(:default_tags, {})
         
     | 
| 
       18 
23 
     | 
    
         
             
                  end
         
     | 
| 
       19 
24 
     | 
    
         | 
| 
       20 
25 
     | 
    
         
             
                  # Retrieve the current value for a given metric. This is a short
         
     | 
| 
         @@ -34,14 +39,15 @@ module Librato 
     | 
|
| 
       34 
39 
     | 
    
         
             
                    @lock.synchronize { @cache.clear }
         
     | 
| 
       35 
40 
     | 
    
         
             
                  end
         
     | 
| 
       36 
41 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
42 
     | 
    
         
             
                  def fetch(key, options={})
         
     | 
| 
       39 
     | 
    
         
            -
                     
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                      @ 
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 43 
     | 
    
         
            +
                    key = key.to_s
         
     | 
| 
      
 44 
     | 
    
         
            +
                    key =
         
     | 
| 
      
 45 
     | 
    
         
            +
                      if options[:tags]
         
     | 
| 
      
 46 
     | 
    
         
            +
                        Librato::Metrics::Util.build_key_for(key, options[:tags])
         
     | 
| 
      
 47 
     | 
    
         
            +
                      elsif @default_tags
         
     | 
| 
      
 48 
     | 
    
         
            +
                        Librato::Metrics::Util.build_key_for(key, @default_tags)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      end
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @lock.synchronize { @cache[key] }
         
     | 
| 
       45 
51 
     | 
    
         
             
                  end
         
     | 
| 
       46 
52 
     | 
    
         | 
| 
       47 
53 
     | 
    
         
             
                  # transfer all measurements to queue and reset internal status
         
     | 
| 
         @@ -50,16 +56,13 @@ module Librato 
     | 
|
| 
       50 
56 
     | 
    
         
             
                    @lock.synchronize do
         
     | 
| 
       51 
57 
     | 
    
         
             
                      # work off of a duplicate data set so we block for
         
     | 
| 
       52 
58 
     | 
    
         
             
                      # as little time as possible
         
     | 
| 
       53 
     | 
    
         
            -
                       
     | 
| 
      
 59 
     | 
    
         
            +
                      # requires a deep copy of data set
         
     | 
| 
      
 60 
     | 
    
         
            +
                      counts = JSON.parse(@cache.dup.to_json, symbolize_names: true)
         
     | 
| 
       54 
61 
     | 
    
         
             
                      reset_cache unless opts[:preserve]
         
     | 
| 
       55 
62 
     | 
    
         
             
                    end
         
     | 
| 
       56 
     | 
    
         
            -
                    counts.each do |metric,  
     | 
| 
       57 
     | 
    
         
            -
                      metric 
     | 
| 
       58 
     | 
    
         
            -
                       
     | 
| 
       59 
     | 
    
         
            -
                        queue.add metric => {value: value, source: source}
         
     | 
| 
       60 
     | 
    
         
            -
                      else
         
     | 
| 
       61 
     | 
    
         
            -
                        queue.add metric => value
         
     | 
| 
       62 
     | 
    
         
            -
                      end
         
     | 
| 
      
 63 
     | 
    
         
            +
                    counts.each do |metric, payload|
         
     | 
| 
      
 64 
     | 
    
         
            +
                      metric = metric.to_s.split(SEPARATOR).first
         
     | 
| 
      
 65 
     | 
    
         
            +
                      queue.add metric => payload
         
     | 
| 
       63 
66 
     | 
    
         
             
                    end
         
     | 
| 
       64 
67 
     | 
    
         
             
                  end
         
     | 
| 
       65 
68 
     | 
    
         | 
| 
         @@ -75,22 +78,33 @@ module Librato 
     | 
|
| 
       75 
78 
     | 
    
         
             
                  #   increment :foo, :source => user.id
         
     | 
| 
       76 
79 
     | 
    
         
             
                  #
         
     | 
| 
       77 
80 
     | 
    
         
             
                  def increment(counter, options={})
         
     | 
| 
      
 81 
     | 
    
         
            +
                    metric = counter.to_s
         
     | 
| 
       78 
82 
     | 
    
         
             
                    if options.is_a?(INTEGER_CLASS)
         
     | 
| 
       79 
83 
     | 
    
         
             
                      # suppport legacy style
         
     | 
| 
       80 
84 
     | 
    
         
             
                      options = {by: options}
         
     | 
| 
       81 
85 
     | 
    
         
             
                    end
         
     | 
| 
       82 
86 
     | 
    
         
             
                    by = options[:by] || 1
         
     | 
| 
       83 
     | 
    
         
            -
                     
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                     
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
      
 87 
     | 
    
         
            +
                    source = options[:source]
         
     | 
| 
      
 88 
     | 
    
         
            +
                    tags_option = options[:tags]
         
     | 
| 
      
 89 
     | 
    
         
            +
                    tags_option = { source: source } if source && !tags_option
         
     | 
| 
      
 90 
     | 
    
         
            +
                    tags =
         
     | 
| 
      
 91 
     | 
    
         
            +
                      if tags_option && options[:inherit_tags]
         
     | 
| 
      
 92 
     | 
    
         
            +
                        @default_tags.merge(tags_option)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      elsif tags_option
         
     | 
| 
      
 94 
     | 
    
         
            +
                        tags_option
         
     | 
| 
      
 95 
     | 
    
         
            +
                      else
         
     | 
| 
      
 96 
     | 
    
         
            +
                        @default_tags
         
     | 
| 
      
 97 
     | 
    
         
            +
                      end
         
     | 
| 
      
 98 
     | 
    
         
            +
                    metric = Librato::Metrics::Util.build_key_for(metric, tags) if tags
         
     | 
| 
       88 
99 
     | 
    
         
             
                    if options[:sporadic]
         
     | 
| 
       89 
100 
     | 
    
         
             
                      make_sporadic(metric)
         
     | 
| 
       90 
101 
     | 
    
         
             
                    end
         
     | 
| 
       91 
102 
     | 
    
         
             
                    @lock.synchronize do
         
     | 
| 
       92 
     | 
    
         
            -
                      @cache[metric]  
     | 
| 
       93 
     | 
    
         
            -
                      @cache[metric]  
     | 
| 
      
 103 
     | 
    
         
            +
                      @cache[metric] = {} unless @cache[metric]
         
     | 
| 
      
 104 
     | 
    
         
            +
                      @cache[metric][:name] ||= metric
         
     | 
| 
      
 105 
     | 
    
         
            +
                      @cache[metric][:value] ||= 0
         
     | 
| 
      
 106 
     | 
    
         
            +
                      @cache[metric][:value] += by
         
     | 
| 
      
 107 
     | 
    
         
            +
                      @cache[metric][:tags] = tags if tags
         
     | 
| 
       94 
108 
     | 
    
         
             
                    end
         
     | 
| 
       95 
109 
     | 
    
         
             
                  end
         
     | 
| 
       96 
110 
     | 
    
         | 
| 
         @@ -105,7 +119,7 @@ module Librato 
     | 
|
| 
       105 
119 
     | 
    
         
             
                    @sporadics.each { |metric| @cache.delete(metric) }
         
     | 
| 
       106 
120 
     | 
    
         
             
                    @sporadics.clear
         
     | 
| 
       107 
121 
     | 
    
         
             
                    # reset all continuous source/metric pairs to 0
         
     | 
| 
       108 
     | 
    
         
            -
                    @cache.each_key { |key| @cache[key] = 0 }
         
     | 
| 
      
 122 
     | 
    
         
            +
                    @cache.each_key { |key| @cache[key][:value] = 0 }
         
     | 
| 
       109 
123 
     | 
    
         
             
                  end
         
     | 
| 
       110 
124 
     | 
    
         | 
| 
       111 
125 
     | 
    
         
             
                end
         
     | 
    
        data/lib/librato/collector.rb
    CHANGED
    
    | 
         @@ -10,14 +10,20 @@ module Librato 
     | 
|
| 
       10 
10 
     | 
    
         
             
                def_delegators :counters, :increment
         
     | 
| 
       11 
11 
     | 
    
         
             
                def_delegators :aggregate, :measure, :timing
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :tags
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(options={})
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @tags = options[:tags]
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       13 
19 
     | 
    
         
             
                # access to internal aggregator object
         
     | 
| 
       14 
20 
     | 
    
         
             
                def aggregate
         
     | 
| 
       15 
     | 
    
         
            -
                  @aggregator_cache ||= Aggregator.new(prefix: @prefix)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @aggregator_cache ||= Aggregator.new(prefix: @prefix, default_tags: @tags)
         
     | 
| 
       16 
22 
     | 
    
         
             
                end
         
     | 
| 
       17 
23 
     | 
    
         | 
| 
       18 
24 
     | 
    
         
             
                # access to internal counters object
         
     | 
| 
       19 
25 
     | 
    
         
             
                def counters
         
     | 
| 
       20 
     | 
    
         
            -
                  @counter_cache ||= CounterCache.new
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @counter_cache ||= CounterCache.new(default_tags: @tags)
         
     | 
| 
       21 
27 
     | 
    
         
             
                end
         
     | 
| 
       22 
28 
     | 
    
         | 
| 
       23 
29 
     | 
    
         
             
                # remove any accumulated but unsent metrics
         
     | 
| 
         @@ -48,4 +54,4 @@ end 
     | 
|
| 
       48 
54 
     | 
    
         
             
            require_relative 'collector/aggregator'
         
     | 
| 
       49 
55 
     | 
    
         
             
            require_relative 'collector/counter_cache'
         
     | 
| 
       50 
56 
     | 
    
         
             
            require_relative 'collector/exceptions'
         
     | 
| 
       51 
     | 
    
         
            -
            require_relative 'collector/group'
         
     | 
| 
      
 57 
     | 
    
         
            +
            require_relative 'collector/group'
         
     | 
| 
         @@ -1,5 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module Librato
         
     | 
| 
       4 
2 
     | 
    
         
             
              class Rack
         
     | 
| 
       5 
3 
     | 
    
         
             
                # Holds configuration for Librato::Rack middleware to use.
         
     | 
| 
         @@ -16,17 +14,17 @@ module Librato 
     | 
|
| 
       16 
14 
     | 
    
         | 
| 
       17 
15 
     | 
    
         
             
                  DEFAULT_SUITES = [:rack, :rack_method, :rack_status]
         
     | 
| 
       18 
16 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                  attr_accessor : 
     | 
| 
       20 
     | 
    
         
            -
                                : 
     | 
| 
       21 
     | 
    
         
            -
                                : 
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
                  attr_accessor :api_endpoint, :autorun, :disable_rack_metrics,
         
     | 
| 
      
 18 
     | 
    
         
            +
                                :flush_interval, :log_level, :log_prefix,
         
     | 
| 
      
 19 
     | 
    
         
            +
                                :log_target, :proxy, :suites,
         
     | 
| 
      
 20 
     | 
    
         
            +
                                :tags, :token, :tracker, :user
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attr_reader :deprecations, :prefix
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
       24 
23 
     | 
    
         
             
                  def initialize
         
     | 
| 
       25 
24 
     | 
    
         
             
                    # set up defaults
         
     | 
| 
       26 
25 
     | 
    
         
             
                    self.tracker = nil
         
     | 
| 
       27 
26 
     | 
    
         
             
                    self.api_endpoint = Librato::Metrics.api_endpoint
         
     | 
| 
       28 
27 
     | 
    
         
             
                    self.flush_interval = 60
         
     | 
| 
       29 
     | 
    
         
            -
                    self.source_pids = false
         
     | 
| 
       30 
28 
     | 
    
         
             
                    self.log_prefix = '[librato-rack] '
         
     | 
| 
       31 
29 
     | 
    
         
             
                    @listeners = []
         
     | 
| 
       32 
30 
     | 
    
         
             
                    @deprecations = []
         
     | 
| 
         @@ -50,8 +48,8 @@ module Librato 
     | 
|
| 
       50 
48 
     | 
    
         
             
                    end
         
     | 
| 
       51 
49 
     | 
    
         
             
                  end
         
     | 
| 
       52 
50 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                  def  
     | 
| 
       54 
     | 
    
         
            -
                     
     | 
| 
      
 51 
     | 
    
         
            +
                  def has_tags?
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @tags && !@tags.empty?
         
     | 
| 
       55 
53 
     | 
    
         
             
                  end
         
     | 
| 
       56 
54 
     | 
    
         | 
| 
       57 
55 
     | 
    
         
             
                  # check environment variables and capture current state
         
     | 
| 
         @@ -61,7 +59,7 @@ module Librato 
     | 
|
| 
       61 
59 
     | 
    
         
             
                    self.token = ENV['LIBRATO_TOKEN']
         
     | 
| 
       62 
60 
     | 
    
         
             
                    self.autorun = detect_autorun
         
     | 
| 
       63 
61 
     | 
    
         
             
                    self.prefix = ENV['LIBRATO_PREFIX']
         
     | 
| 
       64 
     | 
    
         
            -
                    self. 
     | 
| 
      
 62 
     | 
    
         
            +
                    self.tags = build_tags
         
     | 
| 
       65 
63 
     | 
    
         
             
                    self.log_level = ENV['LIBRATO_LOG_LEVEL'] || :info
         
     | 
| 
       66 
64 
     | 
    
         
             
                    self.proxy = ENV['LIBRATO_PROXY'] || ENV['https_proxy'] || ENV['http_proxy']
         
     | 
| 
       67 
65 
     | 
    
         
             
                    self.event_mode = ENV['LIBRATO_EVENT_MODE']
         
     | 
| 
         @@ -78,14 +76,9 @@ module Librato 
     | 
|
| 
       78 
76 
     | 
    
         
             
                    @listeners << listener
         
     | 
| 
       79 
77 
     | 
    
         
             
                  end
         
     | 
| 
       80 
78 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
                  def source=(src)
         
     | 
| 
       82 
     | 
    
         
            -
                    @source = src
         
     | 
| 
       83 
     | 
    
         
            -
                    @explicit_source = !!@source
         
     | 
| 
       84 
     | 
    
         
            -
                  end
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
79 
     | 
    
         
             
                  def dump
         
     | 
| 
       87 
80 
     | 
    
         
             
                    fields = {}
         
     | 
| 
       88 
     | 
    
         
            -
                    %w{ 
     | 
| 
      
 81 
     | 
    
         
            +
                    %w{flush_interval log_level prefix suites tags token user}.each do |field|
         
     | 
| 
       89 
82 
     | 
    
         
             
                      fields[field.to_sym] = self.send(field)
         
     | 
| 
       90 
83 
     | 
    
         
             
                    end
         
     | 
| 
       91 
84 
     | 
    
         
             
                    fields[:metric_suites] = metric_suites.fields
         
     | 
| 
         @@ -130,6 +123,21 @@ module Librato 
     | 
|
| 
       130 
123 
     | 
    
         
             
                    end
         
     | 
| 
       131 
124 
     | 
    
         
             
                  end
         
     | 
| 
       132 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
                  def build_tags
         
     | 
| 
      
 127 
     | 
    
         
            +
                    tags = {}
         
     | 
| 
      
 128 
     | 
    
         
            +
                    tags.tap do
         
     | 
| 
      
 129 
     | 
    
         
            +
                      if ENV["LIBRATO_TAGS"]
         
     | 
| 
      
 130 
     | 
    
         
            +
                        ENV["LIBRATO_TAGS"].split(",")
         
     | 
| 
      
 131 
     | 
    
         
            +
                          .map { |pairs| pairs.split("=") }
         
     | 
| 
      
 132 
     | 
    
         
            +
                            .map { |k,v| tags[k.to_sym] = v }
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                        if tags.all? {|k,v| k.nil? || v.nil? }
         
     | 
| 
      
 135 
     | 
    
         
            +
                          raise InvalidTagConfiguration, "Invalid tag configuration format. Example: foo=bar,baz=qux"
         
     | 
| 
      
 136 
     | 
    
         
            +
                        end
         
     | 
| 
      
 137 
     | 
    
         
            +
                      end
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
       133 
141 
     | 
    
         
             
                end
         
     | 
| 
       134 
142 
     | 
    
         
             
              end
         
     | 
| 
       135 
143 
     | 
    
         
             
            end
         
     | 
    
        data/lib/librato/rack/errors.rb
    CHANGED
    
    
    
        data/lib/librato/rack/tracker.rb
    CHANGED
    
    | 
         @@ -5,8 +5,6 @@ module Librato 
     | 
|
| 
       5 
5 
     | 
    
         
             
                class Tracker
         
     | 
| 
       6 
6 
     | 
    
         
             
                  extend Forwardable
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                  SOURCE_REGEX = /\A[-:A-Za-z0-9_.]{1,255}\z/
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
8 
     | 
    
         
             
                  def_delegators :collector, :increment, :measure, :timing, :group
         
     | 
| 
       11 
9 
     | 
    
         
             
                  def_delegators :logger, :log
         
     | 
| 
       12 
10 
     | 
    
         | 
| 
         @@ -39,7 +37,7 @@ module Librato 
     | 
|
| 
       39 
37 
     | 
    
         | 
| 
       40 
38 
     | 
    
         
             
                  # primary collector object used by this tracker
         
     | 
| 
       41 
39 
     | 
    
         
             
                  def collector
         
     | 
| 
       42 
     | 
    
         
            -
                    @collector ||= Librato::Collector.new
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @collector ||= Librato::Collector.new(tags: tags)
         
     | 
| 
       43 
41 
     | 
    
         
             
                  end
         
     | 
| 
       44 
42 
     | 
    
         | 
| 
       45 
43 
     | 
    
         
             
                  # log a deprecation message
         
     | 
| 
         @@ -59,11 +57,6 @@ module Librato 
     | 
|
| 
       59 
57 
     | 
    
         
             
                    log :error, "submission failed permanently: #{error}"
         
     | 
| 
       60 
58 
     | 
    
         
             
                  end
         
     | 
| 
       61 
59 
     | 
    
         | 
| 
       62 
     | 
    
         
            -
                  # source including process pid if indicated
         
     | 
| 
       63 
     | 
    
         
            -
                  def qualified_source
         
     | 
| 
       64 
     | 
    
         
            -
                    config.source_pids ? "#{source}.#{$$}" : source
         
     | 
| 
       65 
     | 
    
         
            -
                  end
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
60 
     | 
    
         
             
                  # current local instrumentation to be sent on next flush
         
     | 
| 
       68 
61 
     | 
    
         
             
                  # this is for debugging, don't call rapidly in production as it
         
     | 
| 
       69 
62 
     | 
    
         
             
                  # may introduce latency
         
     | 
| 
         @@ -78,10 +71,12 @@ module Librato 
     | 
|
| 
       78 
71 
     | 
    
         
             
                      log :debug, 'halting: credentials not present.'
         
     | 
| 
       79 
72 
     | 
    
         
             
                    elsif config.autorun == false
         
     | 
| 
       80 
73 
     | 
    
         
             
                      log :debug, 'halting: LIBRATO_AUTORUN disabled startup'
         
     | 
| 
       81 
     | 
    
         
            -
                    elsif  
     | 
| 
       82 
     | 
    
         
            -
                      log :warn, "halting: '#{ 
     | 
| 
       83 
     | 
    
         
            -
                    elsif  
     | 
| 
       84 
     | 
    
         
            -
                      log :warn,  
     | 
| 
      
 74 
     | 
    
         
            +
                    elsif tags.any? { |k,v| k.to_s !~ ValidatingQueue::TAGS_KEY_REGEX || v.to_s !~ ValidatingQueue::TAGS_VALUE_REGEX }
         
     | 
| 
      
 75 
     | 
    
         
            +
                      log :warn, "halting: '#{tags}' are invalid tags."
         
     | 
| 
      
 76 
     | 
    
         
            +
                    elsif tags.keys.length > ValidatingQueue::DEFAULT_TAGS_LIMIT
         
     | 
| 
      
 77 
     | 
    
         
            +
                      log :warn, "halting: cannot exceed default tags limit of #{ValidatingQueue::DEFAULT_TAGS_LIMIT} tag names per measurement."
         
     | 
| 
      
 78 
     | 
    
         
            +
                    elsif on_heroku && !config.has_tags?
         
     | 
| 
      
 79 
     | 
    
         
            +
                      log :warn, 'halting: tags must be provided in configuration.'
         
     | 
| 
       85 
80 
     | 
    
         
             
                    else
         
     | 
| 
       86 
81 
     | 
    
         
             
                      return true
         
     | 
| 
       87 
82 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -125,12 +120,12 @@ module Librato 
     | 
|
| 
       125 
120 
     | 
    
         
             
                  end
         
     | 
| 
       126 
121 
     | 
    
         | 
| 
       127 
122 
     | 
    
         
             
                  def build_flush_queue(collector, preserve=false)
         
     | 
| 
       128 
     | 
    
         
            -
                    queue = ValidatingQueue.new( client: client, 
     | 
| 
      
 123 
     | 
    
         
            +
                    queue = ValidatingQueue.new( client: client,
         
     | 
| 
       129 
124 
     | 
    
         
             
                      prefix: config.prefix, skip_measurement_times: true )
         
     | 
| 
       130 
125 
     | 
    
         
             
                    [collector.counters, collector.aggregate].each do |cache|
         
     | 
| 
       131 
126 
     | 
    
         
             
                      cache.flush_to(queue, preserve: preserve)
         
     | 
| 
       132 
127 
     | 
    
         
             
                    end
         
     | 
| 
       133 
     | 
    
         
            -
                    queue.add 'rack.processes' => 1
         
     | 
| 
      
 128 
     | 
    
         
            +
                    queue.add 'rack.processes' => { value: 1, tags: tags }
         
     | 
| 
       134 
129 
     | 
    
         
             
                    trace_queued(queue.queued) #if should_log?(:trace)
         
     | 
| 
       135 
130 
     | 
    
         
             
                    queue
         
     | 
| 
       136 
131 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -166,8 +161,8 @@ module Librato 
     | 
|
| 
       166 
161 
     | 
    
         
             
                    RUBY_DESCRIPTION.split[0]
         
     | 
| 
       167 
162 
     | 
    
         
             
                  end
         
     | 
| 
       168 
163 
     | 
    
         | 
| 
       169 
     | 
    
         
            -
                  def  
     | 
| 
       170 
     | 
    
         
            -
                    @ 
     | 
| 
      
 164 
     | 
    
         
            +
                  def tags
         
     | 
| 
      
 165 
     | 
    
         
            +
                    @tags ||= config.has_tags? ? config.tags : { host: Socket.gethostname.downcase }
         
     | 
| 
       171 
166 
     | 
    
         
             
                  end
         
     | 
| 
       172 
167 
     | 
    
         | 
| 
       173 
168 
     | 
    
         
             
                  # should we spin up a worker? wrap this in a process check
         
     | 
| 
         @@ -5,21 +5,23 @@ module Librato 
     | 
|
| 
       5 
5 
     | 
    
         
             
                # to work out the kinks
         
     | 
| 
       6 
6 
     | 
    
         
             
                #
         
     | 
| 
       7 
7 
     | 
    
         
             
                class ValidatingQueue < Librato::Metrics::Queue
         
     | 
| 
      
 8 
     | 
    
         
            +
                  DEFAULT_TAGS_LIMIT = 4
         
     | 
| 
       8 
9 
     | 
    
         
             
                  METRIC_NAME_REGEX = /\A[-.:_\w]{1,255}\z/
         
     | 
| 
       9 
     | 
    
         
            -
                   
     | 
| 
      
 10 
     | 
    
         
            +
                  TAGS_KEY_REGEX = /\A[-.:_\w]{1,64}\z/
         
     | 
| 
      
 11 
     | 
    
         
            +
                  TAGS_VALUE_REGEX = /\A[-.:_\w]{1,256}\z/
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
                  attr_accessor :logger
         
     | 
| 
       12 
14 
     | 
    
         | 
| 
       13 
15 
     | 
    
         
             
                  # screen all measurements for validity before sending
         
     | 
| 
       14 
16 
     | 
    
         
             
                  def submit
         
     | 
| 
       15 
     | 
    
         
            -
                    @queued[: 
     | 
| 
      
 17 
     | 
    
         
            +
                    @queued[:measurements].delete_if do |entry|
         
     | 
| 
       16 
18 
     | 
    
         
             
                      name = entry[:name].to_s
         
     | 
| 
       17 
     | 
    
         
            -
                       
     | 
| 
      
 19 
     | 
    
         
            +
                      tags = entry[:tags]
         
     | 
| 
       18 
20 
     | 
    
         
             
                      if name !~ METRIC_NAME_REGEX
         
     | 
| 
       19 
21 
     | 
    
         
             
                        log :warn, "invalid metric name '#{name}', not sending."
         
     | 
| 
       20 
22 
     | 
    
         
             
                        true # delete
         
     | 
| 
       21 
     | 
    
         
            -
                      elsif  
     | 
| 
       22 
     | 
    
         
            -
                        log :warn, " 
     | 
| 
      
 23 
     | 
    
         
            +
                      elsif tags && tags.any? { |k,v| k.to_s !~ TAGS_KEY_REGEX || v.to_s !~ TAGS_VALUE_REGEX }
         
     | 
| 
      
 24 
     | 
    
         
            +
                        log :warn, "halting: '#{tags}' are invalid tags."
         
     | 
| 
       23 
25 
     | 
    
         
             
                        true # delete
         
     | 
| 
       24 
26 
     | 
    
         
             
                      else
         
     | 
| 
       25 
27 
     | 
    
         
             
                        false # preserve
         
     | 
| 
         @@ -38,4 +40,4 @@ module Librato 
     | 
|
| 
       38 
40 
     | 
    
         | 
| 
       39 
41 
     | 
    
         
             
                end
         
     | 
| 
       40 
42 
     | 
    
         
             
              end
         
     | 
| 
       41 
     | 
    
         
            -
            end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/librato/rack/version.rb
    CHANGED
    
    
    
        data/lib/librato/rack.rb
    CHANGED
    
    | 
         @@ -44,21 +44,15 @@ module Librato 
     | 
|
| 
       44 
44 
     | 
    
         
             
                EOS
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
                RECORD_RACK_STATUS_BODY = <<-'EOS'
         
     | 
| 
       47 
     | 
    
         
            -
                   
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                    s.timing "#{status}.time", duration
         
     | 
| 
       52 
     | 
    
         
            -
                    s.timing "#{status.to_s[0]}xx.time", duration
         
     | 
| 
       53 
     | 
    
         
            -
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  status_tags = { status: status }
         
     | 
| 
      
 48 
     | 
    
         
            +
                  tracker.increment "rack.request.status", tags: status_tags, inherit_tags: true
         
     | 
| 
      
 49 
     | 
    
         
            +
                  tracker.timing "rack.request.status.time", duration, tags: status_tags, inherit_tags: true
         
     | 
| 
       54 
50 
     | 
    
         
             
                EOS
         
     | 
| 
       55 
51 
     | 
    
         | 
| 
       56 
52 
     | 
    
         
             
                RECORD_RACK_METHOD_BODY = <<-'EOS'
         
     | 
| 
       57 
     | 
    
         
            -
                   
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                    m.timing "#{method}.time", duration
         
     | 
| 
       61 
     | 
    
         
            -
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  method_tags = { method: http_method.downcase! }
         
     | 
| 
      
 54 
     | 
    
         
            +
                  tracker.increment "rack.request.method", tags: method_tags, inherit_tags: true
         
     | 
| 
      
 55 
     | 
    
         
            +
                  tracker.timing "rack.request.method.time", duration, tags: method_tags, inherit_tags: true
         
     | 
| 
       62 
56 
     | 
    
         
             
                EOS
         
     | 
| 
       63 
57 
     | 
    
         | 
| 
       64 
58 
     | 
    
         
             
                attr_reader :config, :tracker
         
     | 
    
        data/test/apps/custom.ru
    CHANGED
    
    | 
         @@ -5,6 +5,10 @@ use Librato::Rack 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            def application(env)
         
     | 
| 
       7 
7 
     | 
    
         
             
              case env['PATH_INFO']
         
     | 
| 
      
 8 
     | 
    
         
            +
              when '/tags'
         
     | 
| 
      
 9 
     | 
    
         
            +
                tags = { region: "us-east-1" }
         
     | 
| 
      
 10 
     | 
    
         
            +
                Librato.increment "requests", tags: tags
         
     | 
| 
      
 11 
     | 
    
         
            +
                Librato.timing "requests.time", 3, tags: tags
         
     | 
| 
       8 
12 
     | 
    
         
             
              when '/increment'
         
     | 
| 
       9 
13 
     | 
    
         
             
                Librato.increment :hits
         
     | 
| 
       10 
14 
     | 
    
         
             
              when '/measure'
         
     | 
| 
         @@ -24,4 +28,4 @@ def application(env) 
     | 
|
| 
       24 
28 
     | 
    
         
             
              [200, {"Content-Type" => 'text/html'}, ["Hello!"]]
         
     | 
| 
       25 
29 
     | 
    
         
             
            end
         
     | 
| 
       26 
30 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
            run method(:application)
         
     | 
| 
      
 31 
     | 
    
         
            +
            run method(:application)
         
     |