clear_skies 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|