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
|