clear_skies 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/clear_skies.gemspec +1 -0
- data/exe/clear_skies +0 -2
- data/lib/clear_skies.rb +6 -5
- data/lib/clear_skies/cloud_watch/elastic_beanstalk_gauge.rb +45 -0
- data/lib/clear_skies/cloud_watch/elb_gauge.rb +44 -0
- data/lib/clear_skies/cloud_watch/gauge.rb +70 -0
- data/lib/clear_skies/cloud_watch/rds_gauge.rb +37 -0
- data/lib/clear_skies/cloud_watch/request_counter.rb +37 -0
- data/lib/clear_skies/redis/report.rb +52 -0
- data/lib/clear_skies/version.rb +1 -1
- metadata +22 -7
- data/lib/clear_skies/metrics/elastic_beanstalk_gauge.rb +0 -41
- data/lib/clear_skies/metrics/elb_gauge.rb +0 -42
- data/lib/clear_skies/metrics/gauge.rb +0 -72
- data/lib/clear_skies/metrics/rds_gauge.rb +0 -35
- data/lib/clear_skies/request_counter.rb +0 -34
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9b28817b1d9a2d115177165c9b1a2ab8d44aeb43
         | 
| 4 | 
            +
              data.tar.gz: 2033b9f62ed98513dc3eb01c3a3ab88d682d2860
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 86fbbf4d79173b447bd66d5539263ede10256bf23c129397b032ebed7e035560ee899f3b067165327ac149f44636f234cf0aa5519479bf7d6132c44774685fe4
         | 
| 7 | 
            +
              data.tar.gz: 4333fa6071ffeb618af49418fa01e644cf4729b4bf7ec996c45c5b1bdaf8cd99d81739ecc0f51ff7166b98b1792156b3ef7d6e257e3dac0a7214943ff21b143e
         | 
    
        data/README.md
    CHANGED
    
    | @@ -32,7 +32,7 @@ The SDK searches the following locations for a region: | |
| 32 32 | 
             
            To run the exporter simple do:
         | 
| 33 33 | 
             
                $ clear_skies metrics_file
         | 
| 34 34 |  | 
| 35 | 
            -
            The metrics_file is a ruby script that registers the metrics you wish to export.
         | 
| 35 | 
            +
            The `metrics_file` is a ruby script that registers the metrics you wish to export.
         | 
| 36 36 |  | 
| 37 37 | 
             
            ``` ruby
         | 
| 38 38 | 
             
            # To grab a generic cloudwatch metric use the following method:
         | 
| @@ -40,12 +40,12 @@ ClearSkies::Gauge.register(namespace, metric_name,dimensions, statistics) do |la | |
| 40 40 | 
             
              labels[:extra] = "label"
         | 
| 41 41 | 
             
              labels[:instance_id] == "something specific"
         | 
| 42 42 | 
             
            end
         | 
| 43 | 
            -
             | 
| 43 | 
            +
            ```
         | 
| 44 44 | 
             
            If you pass a block, it will be called for each dimension retrieved.  The block will be passed a hash of all computed labels, and you may add more if you wish.  If the blocks value is false, that dimension will be skipped.
         | 
| 45 45 |  | 
| 46 46 |  | 
| 47 47 | 
             
            ### RDS Metrics
         | 
| 48 | 
            -
            There is a helper class for grabbing RDS metrics.  It behaves the same as ClearSkies::Gauge | 
| 48 | 
            +
            There is a helper class for grabbing RDS metrics.  It behaves the same as `ClearSkies::Gauge`, except that it automatically adds the `vpc_id` and tags as labels.
         | 
| 49 49 |  | 
| 50 50 | 
             
            ``` ruby
         | 
| 51 51 | 
             
            # To grab an RDS metric
         | 
| @@ -53,7 +53,7 @@ ClearSkies::RDSGauge.register("ReadThroughput", ["DBInstanceIdentifier"], ["Aver | |
| 53 53 | 
             
            ```
         | 
| 54 54 |  | 
| 55 55 | 
             
            ### ELB Metrics
         | 
| 56 | 
            -
            There is a helper class for grabbing ELB metrics.  It behaves the same as ClearSkies::Gauge | 
| 56 | 
            +
            There is a helper class for grabbing ELB metrics.  It behaves the same as `ClearSkies::Gauge`, except that it automatically adds the `vpc_id` and tags as labels.
         | 
| 57 57 |  | 
| 58 58 | 
             
            ``` ruby
         | 
| 59 59 | 
             
            # To grab an ELB metric
         | 
| @@ -61,7 +61,7 @@ ClearSkies::ELBGauge.register("Latency", ["LoadBalancerName"], ["Average", "p90" | |
| 61 61 | 
             
            ```
         | 
| 62 62 |  | 
| 63 63 | 
             
            ### ElasticBeanstalk Metrics
         | 
| 64 | 
            -
            There is a helper class for grabbing ElasticBeanstalk metrics.  It behaves the same as ClearSkies::Gauge | 
| 64 | 
            +
            There is a helper class for grabbing ElasticBeanstalk metrics.  It behaves the same as `ClearSkies::Gauge`, except that it automatically adds `vpc_id` and `application_name` as labels.
         | 
| 65 65 |  | 
| 66 66 | 
             
            ``` ruby
         | 
| 67 67 | 
             
            # To grab an ELB metric
         | 
    
        data/clear_skies.gemspec
    CHANGED
    
    
    
        data/exe/clear_skies
    CHANGED
    
    | @@ -30,7 +30,5 @@ ARGV.each do |config| | |
| 30 30 | 
             
              load config
         | 
| 31 31 | 
             
            end
         | 
| 32 32 |  | 
| 33 | 
            -
            Aws::CloudWatch::Client.add_plugin(ClearSkies::RequestCounterPlugin)
         | 
| 34 | 
            -
            GreekFire::Counter.register("cloudwatch_requests_total") { ClearSkies::RequestCounter.count }
         | 
| 35 33 |  | 
| 36 34 | 
             
            Rack::Handler::Puma.run ClearSkies::App, options
         | 
    
        data/lib/clear_skies.rb
    CHANGED
    
    | @@ -7,8 +7,9 @@ require "greek_fire" | |
| 7 7 | 
             
            require "aws-sdk"
         | 
| 8 8 |  | 
| 9 9 | 
             
            require "clear_skies/app"
         | 
| 10 | 
            -
            require "clear_skies/ | 
| 11 | 
            -
            require "clear_skies/ | 
| 12 | 
            -
            require "clear_skies/ | 
| 13 | 
            -
            require "clear_skies/ | 
| 14 | 
            -
            require "clear_skies/request_counter"
         | 
| 10 | 
            +
            require "clear_skies/cloud_watch/gauge"
         | 
| 11 | 
            +
            require "clear_skies/cloud_watch/rds_gauge"
         | 
| 12 | 
            +
            require "clear_skies/cloud_watch/elb_gauge"
         | 
| 13 | 
            +
            require "clear_skies/cloud_watch/elastic_beanstalk_gauge"
         | 
| 14 | 
            +
            require "clear_skies/cloud_watch/request_counter"
         | 
| 15 | 
            +
            require "clear_skies/redis/report"
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            module ClearSkies
         | 
| 2 | 
            +
              module CloudWatch
         | 
| 3 | 
            +
                class ElasticBeanstalkGauge < ClearSkies::CloudWatch::Gauge
         | 
| 4 | 
            +
                  def self.client
         | 
| 5 | 
            +
                    @client ||= Aws::ElasticBeanstalk::Client.new
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
                  def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 8 | 
            +
                    super("AWS/ElasticBeanstalk", metric_name, dimension, statistics, description: description, &block)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def application_name(environment_name)
         | 
| 12 | 
            +
                    ElasticBeanstalkGauge.client.describe_environments({environment_names: [environment_name] }).environments.first&.application_name
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def vpc_id(application_name, environment_name)
         | 
| 16 | 
            +
                    config = ElasticBeanstalkGauge.client.describe_configuration_settings({ application_name: application_name, environment_name: environment_name }).
         | 
| 17 | 
            +
                        configuration_settings.find { |config| config.application_name == application_name && config.environment_name == environment_name}
         | 
| 18 | 
            +
                    option =  config.option_settings.find { |option| option.namespace == "aws:ec2:vpc" && option.option_name == "VPCId"}
         | 
| 19 | 
            +
                    option.value if option
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def labels_from_metric(metric)
         | 
| 24 | 
            +
                    labels = super(metric)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    if labels.has_key?( "environment_name") && !(Rails.cache.fetch("#{labels["environment_name"]}_skip"))
         | 
| 27 | 
            +
                      application_name = Rails.cache.fetch("#{labels["environment_name"]}_application_name", expires_in: 1.hour) do
         | 
| 28 | 
            +
                        application_name(labels["environment_name"])
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
                      if application_name
         | 
| 31 | 
            +
                        labels["application_name"] =  application_name
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                        labels["vpc_id"] = Rails.cache.fetch("#{labels["environment_name"]}_vpc_id_") do
         | 
| 34 | 
            +
                          vpc_id(labels["application_name"], labels["environment_name"])
         | 
| 35 | 
            +
                        end
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                    else
         | 
| 38 | 
            +
                      Rails.cache.write("#{labels["environment_name"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    return labels
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            module ClearSkies
         | 
| 2 | 
            +
              module CloudWatch
         | 
| 3 | 
            +
                class ELBGauge < ClearSkies::CloudWatch::Gauge
         | 
| 4 | 
            +
                  def self.client
         | 
| 5 | 
            +
                    @client ||= Aws::ElasticLoadBalancing::Client.new
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
                  def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 8 | 
            +
                    super("AWS/ELB", metric_name, dimension, statistics, description: description, &block)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def tags(load_balancer_name)
         | 
| 12 | 
            +
                    labels = {}
         | 
| 13 | 
            +
                    ELBGauge.client.
         | 
| 14 | 
            +
                        describe_tags({load_balancer_names: [load_balancer_name]}).
         | 
| 15 | 
            +
                        tag_descriptions.
         | 
| 16 | 
            +
                        select {|doc| doc.load_balancer_name == load_balancer_name}.each do |tag_description|
         | 
| 17 | 
            +
                      tag_description.tags.each do |tag|
         | 
| 18 | 
            +
                        labels[tag.key.downcase] = tag.value
         | 
| 19 | 
            +
                      end
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                    labels
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def labels_from_metric(metric)
         | 
| 25 | 
            +
                    labels = super(metric)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    if labels.has_key?( "load_balancer_name") && !(Rails.cache.fetch("#{labels["load_balancer_name"]}_skip"))
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      labels["vpc_id"] = Rails.cache.fetch("#{labels["load_balancer_name"]}_vpc_id_") do
         | 
| 30 | 
            +
                        ELBGauge.client.describe_load_balancers(load_balancer_names: [labels["load_balancer_name"]]).load_balancer_descriptions.first.vpc_id
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      labels.merge!(Rails.cache.fetch("#{labels["load_balancer_name"]}_tags_", expires_in: 1.hour, race_condition_ttl: 60.seconds) do
         | 
| 34 | 
            +
                        tags(labels["load_balancer_name"])
         | 
| 35 | 
            +
                      end)
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                    labels
         | 
| 38 | 
            +
                  rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound
         | 
| 39 | 
            +
                    Rails.cache.write("#{labels["load_balancer_name"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 40 | 
            +
                    return labels
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,70 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            module ClearSkies
         | 
| 3 | 
            +
              module CloudWatch
         | 
| 4 | 
            +
                class Gauge < GreekFire::Gauge
         | 
| 5 | 
            +
                  include ActiveModel::Conversion
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def self.register(*args, &block)
         | 
| 8 | 
            +
                    GreekFire::Metric.register(self.new(*args, &block))
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(namespace, metric_name, dimensions, statistics, description:nil, &block)
         | 
| 12 | 
            +
                    super("#{namespace.underscore.gsub("/", "_")}_#{metric_name.underscore}", description: description)
         | 
| 13 | 
            +
                    @namespace = namespace
         | 
| 14 | 
            +
                    @metric_name = metric_name
         | 
| 15 | 
            +
                    @dimensions = dimensions
         | 
| 16 | 
            +
                    @statistics = statistics.select { |stat| ["SampleCount", "Average", "Sum", "Minimum", "Maximum"].include?(stat.to_s) }
         | 
| 17 | 
            +
                    @extended_statistics = statistics - @statistics
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    @block = block
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def self.cloudwatch_client
         | 
| 23 | 
            +
                    @client ||= Aws::CloudWatch::Client.new
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def aws_metrics
         | 
| 27 | 
            +
                     Aws::CloudWatch::Resource.new(client: Gauge.cloudwatch_client).metrics(
         | 
| 28 | 
            +
                        namespace: @namespace,
         | 
| 29 | 
            +
                        metric_name: @metric_name,
         | 
| 30 | 
            +
                        dimensions: @dimensions.map {|dimension| {name: dimension} }
         | 
| 31 | 
            +
                    ).select { |metrics| metrics.dimensions.count == @dimensions.count }
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def labels_from_metric(metric)
         | 
| 35 | 
            +
                    metric.dimensions.inject(ActiveSupport::HashWithIndifferentAccess.new) do |labels, dimension|
         | 
| 36 | 
            +
                      labels[dimension.name.underscore] = dimension.value
         | 
| 37 | 
            +
                      labels
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def metrics
         | 
| 42 | 
            +
                    aws_metrics.map do |metric|
         | 
| 43 | 
            +
                      labels = labels_from_metric(metric)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      next unless @block.call(labels) if @block
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      stats = metric.get_statistics(
         | 
| 48 | 
            +
                          start_time: Time.now.advance(minutes: -6),
         | 
| 49 | 
            +
                          end_time: Time.now.advance(minutes: -5),
         | 
| 50 | 
            +
                          period: 1,
         | 
| 51 | 
            +
                          statistics: @statistics,
         | 
| 52 | 
            +
                          extended_statistics: @extended_statistics,
         | 
| 53 | 
            +
                          dimensions: metric.dimensions
         | 
| 54 | 
            +
                      )
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                      stats.datapoints.map do |datapoint|
         | 
| 57 | 
            +
                        datapoint.to_h.select {|k, v| ![:unit, :timestamp].include?(k) }.map do |key, value|
         | 
| 58 | 
            +
                          if (key == :extended_statistics)
         | 
| 59 | 
            +
                            value.map {|e_key, e_value| GreekFire::Metric.new(name, labels.merge({statistic: e_key}), e_value)}
         | 
| 60 | 
            +
                          else
         | 
| 61 | 
            +
                            GreekFire::Metric.new(name, labels.merge({statistic: key}), value)
         | 
| 62 | 
            +
                          end
         | 
| 63 | 
            +
                        end
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    end.flatten.compact
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module ClearSkies
         | 
| 2 | 
            +
              module CloudWatch
         | 
| 3 | 
            +
                class RDSGauge < ClearSkies::CloudWatch::Gauge
         | 
| 4 | 
            +
                  def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 5 | 
            +
                    super("AWS/RDS", metric_name, dimension, statistics, description: description, &block)
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def tags(db)
         | 
| 9 | 
            +
                    labels = {}
         | 
| 10 | 
            +
                    db.client.list_tags_for_resource(resource_name: db.db_instance_arn).tag_list.each do |tag|
         | 
| 11 | 
            +
                      labels[tag.key.downcase] = tag.value
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                    labels
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def labels_from_metric(metric)
         | 
| 17 | 
            +
                    labels = super(metric)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    if labels.has_key?( "db_instance_identifier") && !(Rails.cache.fetch("#{labels["db_instance_identifier"]}_skip"))
         | 
| 20 | 
            +
                      db = Aws::RDS::DBInstance.new(labels["db_instance_identifier"])
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      labels["vpc_id"] = Rails.cache.fetch("#{labels["db_instance_identifier"]}_vpc_id_") do
         | 
| 23 | 
            +
                        db.db_subnet_group.vpc_id
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      labels.merge!(Rails.cache.fetch("#{labels["db_instance_identifier"]}_tags_", expires_in: 1.hour, race_condition_ttl: 60.seconds) do
         | 
| 27 | 
            +
                        tags(db)
         | 
| 28 | 
            +
                      end)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    labels
         | 
| 31 | 
            +
                  rescue Aws::RDS::Errors::DBInstanceNotFound
         | 
| 32 | 
            +
                    Rails.cache.write("#{labels["db_instance_identifier"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 33 | 
            +
                    return labels
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module ClearSkies
         | 
| 2 | 
            +
              module CloudWatch
         | 
| 3 | 
            +
                class RequestCounter < Seahorse::Client::Handler
         | 
| 4 | 
            +
                  @mutex = Mutex.new
         | 
| 5 | 
            +
                  def self.increment
         | 
| 6 | 
            +
                    @mutex.synchronize do
         | 
| 7 | 
            +
                      @count ||= 0
         | 
| 8 | 
            +
                      @count += 1
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def self.count
         | 
| 13 | 
            +
                    @count ||= 0
         | 
| 14 | 
            +
                    @count
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def initialize(handler)
         | 
| 18 | 
            +
                    @handler = handler
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def call(context)
         | 
| 22 | 
            +
                    RequestCounter.increment
         | 
| 23 | 
            +
                    @handler.call(context)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                class RequestCounterPlugin < Seahorse::Client::Plugin
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def add_handlers(handlers, config)
         | 
| 30 | 
            +
                    handlers.add(RequestCounter, step: :validate)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            Aws::CloudWatch::Client.add_plugin(ClearSkies::CloudWatch::RequestCounterPlugin)
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require 'redis'
         | 
| 2 | 
            +
            module ClearSkies
         | 
| 3 | 
            +
              module Redis
         | 
| 4 | 
            +
                class Report
         | 
| 5 | 
            +
                  def self.register(host, port, extra_labels=nil)
         | 
| 6 | 
            +
                    extra_labels = Hash.new unless extra_labels
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                    r = ClearSkies::Redis::Report.new(host, port)
         | 
| 9 | 
            +
                    databases = Proc.new { ::Redis.new(:host => host, :port => port).info.keys.map {|k| k =~ /^db/ && k.sub("db", "")}.compact }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    GreekFire::Gauge.register("redis_keys",                        labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).keys }
         | 
| 12 | 
            +
                    GreekFire::Gauge.register("redis_last_save",                   labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).last_save }
         | 
| 13 | 
            +
                    GreekFire::Gauge.register("redis_uptime",                      labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).uptime }
         | 
| 14 | 
            +
                    GreekFire::Gauge.register("redis_connected_clients",           labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).connected_clients }
         | 
| 15 | 
            +
                    GreekFire::Gauge.register("redis_blocked_clients",             labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).blocked_clients }
         | 
| 16 | 
            +
                    GreekFire::Gauge.register("redis_used_memory",                 labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).used_memory }
         | 
| 17 | 
            +
                    GreekFire::Gauge.register("redis_mem_fragmentation_ratio",     labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).mem_fragmentation_ratio }
         | 
| 18 | 
            +
                    GreekFire::Gauge.register("redis_rdb_changes_since_last_save", labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).rdb_changes_since_last_save }
         | 
| 19 | 
            +
                    GreekFire::Gauge.register("redis_rdb_last_bgsave_time_sec",    labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).rdb_last_bgsave_time_sec }
         | 
| 20 | 
            +
                    GreekFire::Counter.register("redis_total_commands_processed",  labels: {"database" => databases} ) { | labels| labels.merge!(extra_labels);r.redis_metrics(labels).total_commands_processed }
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def redis_metrics(labels)
         | 
| 25 | 
            +
                    cache_key = "redis_stats_#{@host}_#{@port}_#{labels["database"]}"
         | 
| 26 | 
            +
                    Rails.cache.fetch(cache_key, expires_in: 1.second) do
         | 
| 27 | 
            +
                      redis = ::Redis.new(host: @host, port: @port, db: labels["database"])
         | 
| 28 | 
            +
                      redis_info = redis.info
         | 
| 29 | 
            +
                      metrics = OpenStruct.new
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                      metrics.keys = redis.dbsize
         | 
| 32 | 
            +
                      metrics.last_save = Time.now.to_i - redis.lastsave
         | 
| 33 | 
            +
                      metrics.uptime = redis_info["uptime_in_seconds"].to_f
         | 
| 34 | 
            +
                      metrics.connected_clients =  redis_info["connected_clients"].to_i
         | 
| 35 | 
            +
                      metrics.blocked_clients =  redis_info["blocked_clients"].to_i
         | 
| 36 | 
            +
                      metrics.used_memory =  redis_info["used_memory"].to_f
         | 
| 37 | 
            +
                      metrics.mem_fragmentation_ratio =  redis_info["mem_fragmentation_ratio"].to_f
         | 
| 38 | 
            +
                      metrics.rdb_changes_since_last_save =  redis_info["rdb_changes_since_last_save"].to_f
         | 
| 39 | 
            +
                      metrics.rdb_last_bgsave_time_sec =  redis_info["rdb_last_bgsave_time_sec"].to_f
         | 
| 40 | 
            +
                      metrics.total_commands_processed =  redis_info["total_commands_processed"].to_f
         | 
| 41 | 
            +
                      metrics
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  private
         | 
| 46 | 
            +
                  def initialize(host, port)
         | 
| 47 | 
            +
                    @host = host
         | 
| 48 | 
            +
                    @port = port
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
    
        data/lib/clear_skies/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: clear_skies
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Chris Constantine
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2017- | 
| 11 | 
            +
            date: 2017-06-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: puma
         | 
| @@ -38,6 +38,20 @@ dependencies: | |
| 38 38 | 
             
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: '0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: redis
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 41 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 56 | 
             
              name: greek_fire
         | 
| 43 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -116,11 +130,12 @@ files: | |
| 116 130 | 
             
            - exe/clear_skies
         | 
| 117 131 | 
             
            - lib/clear_skies.rb
         | 
| 118 132 | 
             
            - lib/clear_skies/app.rb
         | 
| 119 | 
            -
            - lib/clear_skies/ | 
| 120 | 
            -
            - lib/clear_skies/ | 
| 121 | 
            -
            - lib/clear_skies/ | 
| 122 | 
            -
            - lib/clear_skies/ | 
| 123 | 
            -
            - lib/clear_skies/request_counter.rb
         | 
| 133 | 
            +
            - lib/clear_skies/cloud_watch/elastic_beanstalk_gauge.rb
         | 
| 134 | 
            +
            - lib/clear_skies/cloud_watch/elb_gauge.rb
         | 
| 135 | 
            +
            - lib/clear_skies/cloud_watch/gauge.rb
         | 
| 136 | 
            +
            - lib/clear_skies/cloud_watch/rds_gauge.rb
         | 
| 137 | 
            +
            - lib/clear_skies/cloud_watch/request_counter.rb
         | 
| 138 | 
            +
            - lib/clear_skies/redis/report.rb
         | 
| 124 139 | 
             
            - lib/clear_skies/version.rb
         | 
| 125 140 | 
             
            homepage: https://github.com/omadahealth/clear_skies
         | 
| 126 141 | 
             
            licenses:
         | 
| @@ -1,41 +0,0 @@ | |
| 1 | 
            -
            module ClearSkies
         | 
| 2 | 
            -
              class ElasticBeanstalkGauge < ClearSkies::Gauge
         | 
| 3 | 
            -
                def self.client
         | 
| 4 | 
            -
                  @client ||= Aws::ElasticBeanstalk::Client.new
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
                def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 7 | 
            -
                  super("AWS/ElasticBeanstalk", metric_name, dimension, statistics, description: description, &block)
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                def application_name(environment_name)
         | 
| 11 | 
            -
                  ElasticBeanstalkGauge.client.describe_environments({environment_names: [environment_name] }).environments.first.application_name
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def vpc_id(application_name, environment_name)
         | 
| 15 | 
            -
                  config = ElasticBeanstalkGauge.client.describe_configuration_settings({ application_name: application_name, environment_name: environment_name }).
         | 
| 16 | 
            -
                      configuration_settings.find { |config| config.application_name == application_name && config.environment_name == environment_name}
         | 
| 17 | 
            -
                  option =  config.option_settings.find { |option| option.namespace == "aws:ec2:vpc" && option.option_name == "VPCId"}
         | 
| 18 | 
            -
                  option.value if option
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
                def labels_from_metric(metric)
         | 
| 23 | 
            -
                  labels = super(metric)
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  if labels.has_key?( "environment_name") && !(Rails.cache.fetch("#{labels["environment_name"]}_skip"))
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                    labels["application_name"] =  Rails.cache.fetch("#{labels["environment_name"]}_application_name", expires_in: 1.hour) do
         | 
| 28 | 
            -
                      application_name(labels["environment_name"])
         | 
| 29 | 
            -
                    end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                    labels["vpc_id"] = Rails.cache.fetch("#{labels["environment_name"]}_vpc_id_") do
         | 
| 32 | 
            -
                      vpc_id(labels["application_name"], labels["environment_name"])
         | 
| 33 | 
            -
                    end
         | 
| 34 | 
            -
                  end
         | 
| 35 | 
            -
                  labels
         | 
| 36 | 
            -
                rescue Aws::RDS::Errors::DBInstanceNotFound
         | 
| 37 | 
            -
                  Rails.cache.write("#{labels["environment_name"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 38 | 
            -
                  return labels
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
              end
         | 
| 41 | 
            -
            end
         | 
| @@ -1,42 +0,0 @@ | |
| 1 | 
            -
            module ClearSkies
         | 
| 2 | 
            -
              class ELBGauge < ClearSkies::Gauge
         | 
| 3 | 
            -
                def self.client
         | 
| 4 | 
            -
                  @client ||= Aws::ElasticLoadBalancing::Client.new
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
                def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 7 | 
            -
                  super("AWS/ELB", metric_name, dimension, statistics, description: description, &block)
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                def tags(load_balancer_name)
         | 
| 11 | 
            -
                  labels = {}
         | 
| 12 | 
            -
                  ELBGauge.client.
         | 
| 13 | 
            -
                      describe_tags({load_balancer_names: [load_balancer_name]}).
         | 
| 14 | 
            -
                      tag_descriptions.
         | 
| 15 | 
            -
                      select {|doc| doc.load_balancer_name == load_balancer_name}.each do |tag_description|
         | 
| 16 | 
            -
                    tag_description.tags.each do |tag|
         | 
| 17 | 
            -
                      labels[tag.key.downcase] = tag.value
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                  labels
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                def labels_from_metric(metric)
         | 
| 24 | 
            -
                  labels = super(metric)
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                  if labels.has_key?( "load_balancer_name") && !(Rails.cache.fetch("#{labels["load_balancer_name"]}_skip"))
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                    labels["vpc_id"] = Rails.cache.fetch("#{labels["load_balancer_name"]}_vpc_id_") do
         | 
| 29 | 
            -
                      ELBGauge.client.describe_load_balancers(load_balancer_names: [labels["load_balancer_name"]]).load_balancer_descriptions.first.vpc_id
         | 
| 30 | 
            -
                    end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                    labels.merge!(Rails.cache.fetch("#{labels["load_balancer_name"]}_tags_", expires_in: 1.hour, race_condition_ttl: 60.seconds) do
         | 
| 33 | 
            -
                      tags(labels["load_balancer_name"])
         | 
| 34 | 
            -
                    end)
         | 
| 35 | 
            -
                  end
         | 
| 36 | 
            -
                  labels
         | 
| 37 | 
            -
                rescue Aws::RDS::Errors::DBInstanceNotFound
         | 
| 38 | 
            -
                  Rails.cache.write("#{labels["load_balancer_name"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 39 | 
            -
                  return labels
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
              end
         | 
| 42 | 
            -
            end
         | 
| @@ -1,72 +0,0 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            module ClearSkies
         | 
| 3 | 
            -
              class Gauge < GreekFire::Gauge
         | 
| 4 | 
            -
                include ActiveModel::Conversion
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                def self.register(*args, &block)
         | 
| 7 | 
            -
                  GreekFire::Metric.register(self.new(*args, &block))
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                def to_partial_path
         | 
| 11 | 
            -
                  GreekFire::Gauge._to_partial_path
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def initialize(namespace, metric_name, dimensions, statistics, description:nil, &block)
         | 
| 15 | 
            -
                  super("#{namespace.underscore.gsub("/", "_")}_#{metric_name.underscore}", description: description)
         | 
| 16 | 
            -
                  @namespace = namespace
         | 
| 17 | 
            -
                  @metric_name = metric_name
         | 
| 18 | 
            -
                  @dimensions = dimensions
         | 
| 19 | 
            -
                  @statistics = statistics.select { |stat| ["SampleCount", "Average", "Sum", "Minimum", "Maximum"].include?(stat.to_s) }
         | 
| 20 | 
            -
                  @extended_statistics = statistics - @statistics
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  @block = block
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                def self.cloudwatch_client
         | 
| 26 | 
            -
                  @client ||= Aws::CloudWatch::Client.new
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                def aws_metrics
         | 
| 30 | 
            -
                   Aws::CloudWatch::Resource.new(client: Gauge.cloudwatch_client).metrics(
         | 
| 31 | 
            -
                      namespace: @namespace,
         | 
| 32 | 
            -
                      metric_name: @metric_name,
         | 
| 33 | 
            -
                      dimensions: @dimensions.map {|dimension| {name: dimension} }
         | 
| 34 | 
            -
                  ).select { |metrics| metrics.dimensions.count == @dimensions.count }
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                def labels_from_metric(metric)
         | 
| 38 | 
            -
                  metric.dimensions.inject(ActiveSupport::HashWithIndifferentAccess.new) do |labels, dimension|
         | 
| 39 | 
            -
                    labels[dimension.name.underscore] = dimension.value
         | 
| 40 | 
            -
                    labels
         | 
| 41 | 
            -
                  end
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                def metrics
         | 
| 45 | 
            -
                  aws_metrics.map do |metric|
         | 
| 46 | 
            -
                    labels = labels_from_metric(metric)
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                    next unless @block.call(labels) if @block
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    stats = metric.get_statistics(
         | 
| 51 | 
            -
                        start_time: Time.now.advance(minutes: -6),
         | 
| 52 | 
            -
                        end_time: Time.now.advance(minutes: -5),
         | 
| 53 | 
            -
                        period: 1,
         | 
| 54 | 
            -
                        statistics: @statistics,
         | 
| 55 | 
            -
                        extended_statistics: @extended_statistics,
         | 
| 56 | 
            -
                        dimensions: metric.dimensions
         | 
| 57 | 
            -
                    )
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    stats.datapoints.map do |datapoint|
         | 
| 60 | 
            -
                      datapoint.to_h.select {|k, v| ![:unit, :timestamp].include?(k) }.map do |key, value|
         | 
| 61 | 
            -
                        if (key == :extended_statistics)
         | 
| 62 | 
            -
                          value.map {|e_key, e_value| GreekFire::Metric.new(name, labels.merge({statistic: e_key}), e_value)}
         | 
| 63 | 
            -
                        else
         | 
| 64 | 
            -
                          GreekFire::Metric.new(name, labels.merge({statistic: key}), value)
         | 
| 65 | 
            -
                        end
         | 
| 66 | 
            -
                      end
         | 
| 67 | 
            -
                    end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  end.flatten.compact
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
              end
         | 
| 72 | 
            -
            end
         | 
| @@ -1,35 +0,0 @@ | |
| 1 | 
            -
            module ClearSkies
         | 
| 2 | 
            -
              class RDSGauge < ClearSkies::Gauge
         | 
| 3 | 
            -
                def initialize(metric_name, dimension, statistics, description: nil, &block)
         | 
| 4 | 
            -
                  super("AWS/RDS", metric_name, dimension, statistics, description: description, &block)
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def tags(db)
         | 
| 8 | 
            -
                  labels = {}
         | 
| 9 | 
            -
                  db.client.list_tags_for_resource(resource_name: db.db_instance_arn).tag_list.each do |tag|
         | 
| 10 | 
            -
                    labels[tag.key.downcase] = tag.value
         | 
| 11 | 
            -
                  end
         | 
| 12 | 
            -
                  labels
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def labels_from_metric(metric)
         | 
| 16 | 
            -
                  labels = super(metric)
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  if labels.has_key?( "db_instance_identifier") && !(Rails.cache.fetch("#{labels["db_instance_identifier"]}_skip"))
         | 
| 19 | 
            -
                    db = Aws::RDS::DBInstance.new(labels["db_instance_identifier"])
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                    labels["vpc_id"] = Rails.cache.fetch("#{labels["db_instance_identifier"]}_vpc_id_") do
         | 
| 22 | 
            -
                      db.db_subnet_group.vpc_id
         | 
| 23 | 
            -
                    end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                    labels.merge!(Rails.cache.fetch("#{labels["db_instance_identifier"]}_tags_", expires_in: 1.hour, race_condition_ttl: 60.seconds) do
         | 
| 26 | 
            -
                      tags(db)
         | 
| 27 | 
            -
                    end)
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                  labels
         | 
| 30 | 
            -
                rescue Aws::RDS::Errors::DBInstanceNotFound
         | 
| 31 | 
            -
                  Rails.cache.write("#{labels["db_instance_identifier"]}_skip", true, expires_in: 1.hour, race_condition_ttl: 60.seconds)
         | 
| 32 | 
            -
                  return labels
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
            end
         | 
| @@ -1,34 +0,0 @@ | |
| 1 | 
            -
            module ClearSkies
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              class RequestCounter < Seahorse::Client::Handler
         | 
| 4 | 
            -
                @mutex = Mutex.new
         | 
| 5 | 
            -
                def self.increment
         | 
| 6 | 
            -
                  @mutex.synchronize do
         | 
| 7 | 
            -
                    @count ||= 0
         | 
| 8 | 
            -
                    @count += 1
         | 
| 9 | 
            -
                  end
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                def self.count
         | 
| 13 | 
            -
                  @count ||= 0
         | 
| 14 | 
            -
                  @count
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                def initialize(handler)
         | 
| 18 | 
            -
                  @handler = handler
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                def call(context)
         | 
| 22 | 
            -
                  RequestCounter.increment
         | 
| 23 | 
            -
                  @handler.call(context)
         | 
| 24 | 
            -
                end
         | 
| 25 | 
            -
              end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
              class RequestCounterPlugin < Seahorse::Client::Plugin
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                def add_handlers(handlers, config)
         | 
| 30 | 
            -
                  handlers.add(RequestCounter, step: :validate)
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              end
         | 
| 34 | 
            -
            end
         |