cloudwatch-sender 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +38 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +116 -0
- data/Rakefile +1 -0
- data/bin/cloudwatch-sender +11 -0
- data/cloudwatch-sender.gemspec +26 -0
- data/configs/example.yaml +63 -0
- data/lib/cloudwatch/sender/base.rb +26 -0
- data/lib/cloudwatch/sender/cli.rb +47 -0
- data/lib/cloudwatch/sender/ec2.rb +40 -0
- data/lib/cloudwatch/sender/fetcher/base.rb +57 -0
- data/lib/cloudwatch/sender/fetcher/custom.rb +46 -0
- data/lib/cloudwatch/sender/fetcher/ec2.rb +70 -0
- data/lib/cloudwatch/sender/fetcher/sqs.rb +48 -0
- data/lib/cloudwatch/sender/metric_definition.rb +12 -0
- data/lib/cloudwatch/sender/version.rb +5 -0
- data/lib/cloudwatch_sender.rb +7 -0
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0de3762390f886fad8a077d0cecd0e2f1e1ad48f
|
4
|
+
data.tar.gz: cde93ef7efa2f1286dffb59c3139aad87cd222a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c6c836c2c5051ddd48438b930279041ac8c5da3a5f48495e866018e58f0d8f81274de1133a1f5582c83ee4b5ff07028a33b9847fdc0309669ab1c4eac59bc1e
|
7
|
+
data.tar.gz: e7b8c961bb55cfdcc3b12f579e145217bddb24ca46de1f8351062ac959de3006c2b48a223e0b746b24ef192658d682d28bb8a81593f53ecd82cb5a0d45ecc276
|
data/.gitignore
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/vendor/bundle
|
26
|
+
/lib/bundler/man/
|
27
|
+
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
30
|
+
# Gemfile.lock
|
31
|
+
# .ruby-version
|
32
|
+
# .ruby-gemset
|
33
|
+
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
35
|
+
.rvmrc
|
36
|
+
.DS_Store
|
37
|
+
|
38
|
+
Gemfile.lock
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.3
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 BBC News
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
<h1 align="center">cloudwatch-sender</h1>
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<a href="https://rubygems.org/gems/cloudwatch-sender"><img src="https://img.shields.io/gem/v/cloudwatch-sender.svg?style=flat-square"></a>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<p align="center">
|
8
|
+
Retrieves metrics from <b>Cloudwatch</b> and sends them to <b>InfluxDB</b>/<b>Graphite</b>.
|
9
|
+
</p>
|
10
|
+
|
11
|
+
## What is this?
|
12
|
+
|
13
|
+
Allows you to send **EC2**, **SQS** and **custom** metrics from Cloudwatch to InfluxDB or Graphite. EC2 metrics are gathered via EC2 tags instead of EC2 Instance IDs, making the tool far more dynamic.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem "cloudwatch-sender"
|
21
|
+
```
|
22
|
+
|
23
|
+
Then execute:
|
24
|
+
|
25
|
+
```
|
26
|
+
bundle
|
27
|
+
```
|
28
|
+
|
29
|
+
Or install it yourself:
|
30
|
+
|
31
|
+
```
|
32
|
+
gem install cloudwatch-sender
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### Command Line
|
38
|
+
|
39
|
+
```sh
|
40
|
+
cloudwatch-sender send_metrics /path/to/config.yaml $AWS_ACCESS_KEY $AWS_SECRET_KEY $AWS_REGION
|
41
|
+
```
|
42
|
+
|
43
|
+
If you would like to stream metrics to your endpoint at a set interval, use `continuous`:
|
44
|
+
|
45
|
+
```sh
|
46
|
+
cloudwatch-sender continuous /path/to/config.yaml $AWS_ACCESS_KEY $AWS_SECRET_KEY $AWS_REGION $INTERVAL
|
47
|
+
```
|
48
|
+
|
49
|
+
**Note** - the default `$INTERVAL` is 60 seconds.
|
50
|
+
|
51
|
+
### Programmatically
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
require "cloudwatch/sender/cli"
|
55
|
+
|
56
|
+
loop do
|
57
|
+
Cloudwatch::Sender::CLI.new.send_metrics(config_path, key_id, access_key, region)
|
58
|
+
sleep 120
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
require "cloudwatch/sender/cli"
|
64
|
+
|
65
|
+
Cloudwatch::Sender::CLI.new.continuous(config_path, key_id, access_key, region, sleep_time)
|
66
|
+
```
|
67
|
+
|
68
|
+
## Configs
|
69
|
+
|
70
|
+
The gem is powered via a YAML config file, see [example.yaml](https://github.com/BBC-News/cloudwatch-sender/blob/master/configs/example.yaml) for an example.
|
71
|
+
|
72
|
+
**Note**: take into account how often metrics update for each AWS product:
|
73
|
+
|
74
|
+
- **EC2** - every 60 seconds.
|
75
|
+
- **SQS** - every 5 minutes.
|
76
|
+
- **Custom** - every 60 seconds.
|
77
|
+
|
78
|
+
## How it works
|
79
|
+
|
80
|
+
The gem extracts metrics for a given set of EC2 instances based on an EC2 tag key/value. For example:
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
ec2_tag_key: ProjectName
|
84
|
+
ec2_tag_value: bbc_news
|
85
|
+
```
|
86
|
+
|
87
|
+
As seen in the example above a tag relates to a single project. Thus if that key/value is called, it returns all the instances attached to that project - which is what the gem then uses to gather metrics on each instance.
|
88
|
+
|
89
|
+
The gem collects EC2 metrics for the previous 3 minutes and SQS metrics for the previous 20 minutes. Thus running the gem every 60 seconds for EC2 and every 5 minutes for SQS will provide sufficient data. This allows for the gem to remain unaffected by network/database issues.
|
90
|
+
|
91
|
+
## Why make this?
|
92
|
+
|
93
|
+
We found the existing tools heavily rely upon AWS variables which often become out-of-date, e.g. EC2 Instance ID. This becomes a problem when a component is being regularly re-built and deployed. Thus we made the decision to base cloudwatch-sender on a broder set of criteria, such as EC2 tags.
|
94
|
+
|
95
|
+
## TODO
|
96
|
+
|
97
|
+
See [open issues](https://github.com/BBC-News/cloudwatch-sender/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3Ato-do).
|
98
|
+
|
99
|
+
## License
|
100
|
+
|
101
|
+
Standard MIT License, see included [license file](https://github.com/BBC-News/cloudwatch-sender/blob/master/LICENSE.txt).
|
102
|
+
|
103
|
+
## Authors
|
104
|
+
|
105
|
+
- [David Blooman](http://twitter.com/dblooman)
|
106
|
+
- [Charlie Revett](http://twitter.com/charlierevett)
|
107
|
+
|
108
|
+
## Contributing
|
109
|
+
|
110
|
+
1. [Fork it!](https://github.com/bbc-news/cloudwatch-sender/fork)
|
111
|
+
2. Create your feature branch: `git checkout -b my-new-feature`
|
112
|
+
3. Commit your changes: `git commit -am "Add some feature"`
|
113
|
+
4. Push to the branch: `git push origin my-new-feature`
|
114
|
+
5. Create a new [Pull Request](https://github.com/BBC-News/cloudwatch-sender/compare).
|
115
|
+
|
116
|
+
Please feel free to raise an [issue](https://github.com/BBC-News/cloudwatch-sender/issues/new) if you find a bug or have a feature request.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "cloudwatch/sender/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cloudwatch-sender"
|
8
|
+
spec.version = Cloudwatch::Sender::VERSION
|
9
|
+
spec.authors = ["DaveBlooman", "Charlie Revett"]
|
10
|
+
spec.email = ["david.blooman@gmail.com", "charlierevett@gmail.com"]
|
11
|
+
spec.summary = "Cloudwatch Metrics Sender"
|
12
|
+
spec.description = "Get metrics from Cloudwatch and send to Graphite/InfluxDB"
|
13
|
+
spec.homepage = "https://github.com/BBC-News/cloudwatch-sender"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
|
24
|
+
spec.add_runtime_dependency "aws-sdk"
|
25
|
+
spec.add_runtime_dependency "thor"
|
26
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
metric_prefix: "cloudwatch"
|
3
|
+
influx_host: "influxdb.domain.com"
|
4
|
+
influx_port: 2003
|
5
|
+
|
6
|
+
metric_types:
|
7
|
+
## EC2 Metrics
|
8
|
+
-
|
9
|
+
namespace: "AWS/EC2"
|
10
|
+
ec2_tag_key: "BBCComponent"
|
11
|
+
ec2_tag_value: "newsbeat-composition"
|
12
|
+
metrics:
|
13
|
+
-
|
14
|
+
name: "CPUUtilization"
|
15
|
+
unit: "Percent"
|
16
|
+
statistics:
|
17
|
+
- Average
|
18
|
+
-
|
19
|
+
name: "NetworkIn"
|
20
|
+
unit: "Bytes"
|
21
|
+
statistics:
|
22
|
+
- Average
|
23
|
+
-
|
24
|
+
name: "NetworkOut"
|
25
|
+
unit: "Bytes"
|
26
|
+
statistics:
|
27
|
+
- Average
|
28
|
+
|
29
|
+
## Custom Metrics
|
30
|
+
-
|
31
|
+
namespace: "BBCApp/newsbeat/live"
|
32
|
+
metrics:
|
33
|
+
-
|
34
|
+
name: "Headline301Redirect"
|
35
|
+
unit: "Count"
|
36
|
+
statistics:
|
37
|
+
- Sum
|
38
|
+
-
|
39
|
+
name: "InvalidHeadline"
|
40
|
+
unit: "Count"
|
41
|
+
statistics:
|
42
|
+
- Sum
|
43
|
+
-
|
44
|
+
name: "LegacyArticle"
|
45
|
+
unit: "Count"
|
46
|
+
statistics:
|
47
|
+
- Sum
|
48
|
+
|
49
|
+
## SQS Metrics
|
50
|
+
-
|
51
|
+
namespace: "AWS/SQS"
|
52
|
+
queue_name: "live-news-ArticleQueue-N7RAX00100RC"
|
53
|
+
metrics:
|
54
|
+
-
|
55
|
+
name: "ApproximateNumberOfMessagesVisible"
|
56
|
+
unit: "Count"
|
57
|
+
statistics:
|
58
|
+
- Sum
|
59
|
+
-
|
60
|
+
name: "NumberOfMessagesDeleted"
|
61
|
+
unit: "Count"
|
62
|
+
statistics:
|
63
|
+
- Sum
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "json"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module Cloudwatch
|
5
|
+
module Sender
|
6
|
+
class Base
|
7
|
+
def initialize(server, port)
|
8
|
+
@influx_server = server
|
9
|
+
@influx_port = port
|
10
|
+
end
|
11
|
+
|
12
|
+
def send_tcp(contents)
|
13
|
+
sock = TCPSocket.open(influx_server, influx_port)
|
14
|
+
sock.print contents
|
15
|
+
rescue StandardError => e
|
16
|
+
logger.debug "Error: #{e}"
|
17
|
+
ensure
|
18
|
+
sock.close
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
attr_reader :influx_server, :influx_port
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "logger"
|
3
|
+
require "cloudwatch/sender/ec2"
|
4
|
+
require "cloudwatch/sender/metric_definition"
|
5
|
+
require "cloudwatch/sender/fetcher/base"
|
6
|
+
require "cloudwatch/sender/fetcher/ec2"
|
7
|
+
require "cloudwatch/sender/fetcher/sqs"
|
8
|
+
require "cloudwatch/sender/fetcher/custom"
|
9
|
+
|
10
|
+
module Cloudwatch
|
11
|
+
module Sender
|
12
|
+
class CLI < Thor
|
13
|
+
include Thor::Actions
|
14
|
+
|
15
|
+
desc "send_metrics [metrics_file] [key_id] [access_key] [region]", "Gets metrics from Cloudwatch and sends them to influx"
|
16
|
+
def send_metrics(metrics_file, key_id, access_key, region)
|
17
|
+
setup_aws(key_id, access_key, region)
|
18
|
+
MetricDefinition.metric_type load_metrics(metrics_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "continuous [metrics_file] [key_id] [access_key] [region] [sleep time]", "Continuously sends metrics to Influx/Cloudwatch"
|
22
|
+
def continuous(metrics_file, key_id, access_key, region, sleep_time = 60)
|
23
|
+
logger = Logger.new(STDOUT)
|
24
|
+
|
25
|
+
loop do
|
26
|
+
begin
|
27
|
+
send_metrics(metrics_file, key_id, access_key, region)
|
28
|
+
sleep sleep_time.to_i
|
29
|
+
rescue => e
|
30
|
+
logger.debug("Unable to complete operation #{e}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
no_commands do
|
36
|
+
def load_metrics(metrics_file)
|
37
|
+
YAML.load(File.open(metrics_file))
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_aws(key_id, access_key, region)
|
41
|
+
Aws.config.update(:region => region,
|
42
|
+
:credentials => Aws::Credentials.new(key_id, access_key))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "aws-sdk"
|
2
|
+
|
3
|
+
module Cloudwatch
|
4
|
+
module Sender
|
5
|
+
class EC2
|
6
|
+
def initialize
|
7
|
+
@ec2 = Aws::EC2::Client.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def list_instances(key, value)
|
11
|
+
list_instance_ids aws_resp(key, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :ec2
|
17
|
+
|
18
|
+
def aws_resp(key, value)
|
19
|
+
ec2.describe_instances(
|
20
|
+
:filters => [
|
21
|
+
{
|
22
|
+
:name => "tag-key",
|
23
|
+
:values => [key]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
:name => "tag-value",
|
27
|
+
:values => [value]
|
28
|
+
}
|
29
|
+
]
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def list_instance_ids(instances)
|
34
|
+
instances.reservations.map do |reservations|
|
35
|
+
reservations.instances.map(&:instance_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "cloudwatch/sender/base"
|
2
|
+
|
3
|
+
module Cloudwatch
|
4
|
+
module Sender
|
5
|
+
module Fetcher
|
6
|
+
class Base
|
7
|
+
def initialize(components, namespace)
|
8
|
+
@components = components
|
9
|
+
@namespace = namespace
|
10
|
+
end
|
11
|
+
|
12
|
+
def retrieve(component_meta)
|
13
|
+
component_meta["metrics"].each do |metric|
|
14
|
+
metric_type(component_meta, metric)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :components, :namespace
|
21
|
+
|
22
|
+
def cloudwatch
|
23
|
+
Aws::CloudWatch::Client.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def extract_class_name(component_meta)
|
27
|
+
component_meta["namespace"].split("/").last
|
28
|
+
end
|
29
|
+
|
30
|
+
def fetcher(component_meta)
|
31
|
+
namespace.start_with?("AWS/") ? Object.const_get(class_namespace component_meta)
|
32
|
+
: Cloudwatch::Sender::Fetcher::Custom
|
33
|
+
end
|
34
|
+
|
35
|
+
def class_namespace(component_meta)
|
36
|
+
"Cloudwatch::Sender::Fetcher::#{extract_class_name component_meta}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def metric_prefix
|
40
|
+
components["metric_prefix"]
|
41
|
+
end
|
42
|
+
|
43
|
+
def metric_type(component_meta, metric)
|
44
|
+
fetcher(component_meta).new(
|
45
|
+
cloudwatch, sender, metric_prefix
|
46
|
+
).metrics(component_meta, metric)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sender
|
50
|
+
Cloudwatch::Sender::Base.new(
|
51
|
+
components["influx_host"], components["influx_port"]
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Cloudwatch
|
2
|
+
module Sender
|
3
|
+
module Fetcher
|
4
|
+
class Custom
|
5
|
+
attr_reader :metric_prefix, :cloudwatch, :sender
|
6
|
+
|
7
|
+
def initialize(cloudwatch, sender, metric_prefix)
|
8
|
+
@cloudwatch = cloudwatch
|
9
|
+
@sender = sender
|
10
|
+
@metric_prefix = metric_prefix
|
11
|
+
end
|
12
|
+
|
13
|
+
START_TIME = 180
|
14
|
+
|
15
|
+
def metrics(component_meta, metric)
|
16
|
+
resp = cloudwatch.get_metric_statistics(
|
17
|
+
:namespace => component_meta["namespace"],
|
18
|
+
:metric_name => metric["name"],
|
19
|
+
:start_time => Time.now - START_TIME,
|
20
|
+
:end_time => Time.now,
|
21
|
+
:period => 60,
|
22
|
+
:statistics => metric["statistics"],
|
23
|
+
:unit => metric["unit"]
|
24
|
+
)
|
25
|
+
name = component_meta["namespace"].downcase
|
26
|
+
name_metrics(resp, name, metric["statistics"])
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def name_metrics(resp, name, statistics)
|
32
|
+
resp.data["datapoints"].each do |data|
|
33
|
+
time = data["timestamp"].to_i
|
34
|
+
check_statistics(name, resp.data["label"], statistics, time, data)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_statistics(name, label, statistics, time, data)
|
39
|
+
statistics.each do |stat|
|
40
|
+
sender.send_tcp("#{metric_prefix}.#{name}.#{label.downcase}.#{stat.downcase}" " " "#{data[stat.downcase]}" " " "#{time}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Cloudwatch
|
2
|
+
module Sender
|
3
|
+
module Fetcher
|
4
|
+
class EC2
|
5
|
+
def initialize(cloudwatch, sender, metric_prefix)
|
6
|
+
@cloudwatch = cloudwatch
|
7
|
+
@sender = sender
|
8
|
+
@metric_prefix = metric_prefix
|
9
|
+
end
|
10
|
+
|
11
|
+
def metrics(component_meta, metric)
|
12
|
+
ec2_metrics(instance_list(component_meta), component_meta, metric)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :metric_prefix, :cloudwatch, :sender
|
18
|
+
|
19
|
+
START_TIME = 180
|
20
|
+
|
21
|
+
def ec2_metrics(instance_list, component_meta, metric)
|
22
|
+
instance_list.each do |instance|
|
23
|
+
metric_data = aws_metric_meta(component_meta, metric, instance)
|
24
|
+
resp = cloudwatch.get_metric_statistics metric_data
|
25
|
+
name_metrics(resp, instance, component_meta["ec2_tag_value"], metric["statistics"])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def aws_metric_meta(component_meta, metric, instance)
|
30
|
+
{
|
31
|
+
:namespace => component_meta["namespace"],
|
32
|
+
:metric_name => metric["name"],
|
33
|
+
:dimensions => [{ :name => "InstanceId", :value => instance }],
|
34
|
+
:start_time => Time.now - START_TIME,
|
35
|
+
:end_time => Time.now,
|
36
|
+
:period => 60,
|
37
|
+
:statistics => metric["statistics"],
|
38
|
+
:unit => metric["unit"]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def ec2
|
43
|
+
Cloudwatch::Sender::EC2.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def instance_list(component_meta)
|
47
|
+
ec2.list_instances(
|
48
|
+
component_meta["ec2_tag_key"], component_meta["ec2_tag_value"]
|
49
|
+
).flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
def name_metrics(resp, instance, name, statistics)
|
53
|
+
resp.data["datapoints"].each do |data|
|
54
|
+
check_statistics(instance, name, resp.data["label"], statistics, metric_time(data), data)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def metric_time(data)
|
59
|
+
data["timestamp"].to_i
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_statistics(instanceid, name, label, statistics, time, data)
|
63
|
+
statistics.each do |stat|
|
64
|
+
sender.send_tcp("#{metric_prefix}.#{name}.#{instanceid}.#{label.downcase}.#{stat}" " " "#{data[stat.downcase]}" " " "#{time}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Cloudwatch
|
2
|
+
module Sender
|
3
|
+
module Fetcher
|
4
|
+
class SQS
|
5
|
+
attr_reader :metric_prefix, :cloudwatch, :sender
|
6
|
+
|
7
|
+
def initialize(cloudwatch, sender, metric_prefix)
|
8
|
+
@cloudwatch = cloudwatch
|
9
|
+
@sender = sender
|
10
|
+
@metric_prefix = metric_prefix
|
11
|
+
end
|
12
|
+
|
13
|
+
START_TIME = 1200
|
14
|
+
|
15
|
+
def metrics(component_meta, metric)
|
16
|
+
resp = cloudwatch.get_metric_statistics(
|
17
|
+
:namespace => component_meta["namespace"],
|
18
|
+
:metric_name => metric["name"],
|
19
|
+
:dimensions => [{ :name => "QueueName",
|
20
|
+
:value => component_meta["queue_name"] }],
|
21
|
+
:start_time => Time.now - START_TIME,
|
22
|
+
:end_time => Time.now,
|
23
|
+
:period => 60,
|
24
|
+
:statistics => metric["statistics"],
|
25
|
+
:unit => metric["unit"]
|
26
|
+
)
|
27
|
+
name = component_meta["namespace"].downcase
|
28
|
+
name_metrics(resp, name, metric["statistics"], component_meta["queue_name"])
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def name_metrics(resp, name, statistics, queue_name)
|
34
|
+
resp.data["datapoints"].each do |data|
|
35
|
+
time = data["timestamp"].to_i
|
36
|
+
check_statistics(name, resp.data["label"], statistics, time, data, queue_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_statistics(name, label, statistics, time, data, queue_name)
|
41
|
+
statistics.each do |stat|
|
42
|
+
sender.send_tcp("#{metric_prefix}.#{name}.#{queue_name}.#{label.downcase}.#{stat.downcase}" " " "#{data[stat.downcase]}" " " "#{time}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Cloudwatch
|
2
|
+
module Sender
|
3
|
+
class MetricDefinition
|
4
|
+
def self.metric_type(components)
|
5
|
+
components["metric_types"].each do |component_meta|
|
6
|
+
namespace = component_meta["namespace"]
|
7
|
+
Cloudwatch::Sender::Fetcher::Base.new(components, namespace).retrieve component_meta
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudwatch-sender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DaveBlooman
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-06-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -71,10 +71,30 @@ description: Get metrics from Cloudwatch and send to Graphite/InfluxDB
|
|
71
71
|
email:
|
72
72
|
- david.blooman@gmail.com
|
73
73
|
- charlierevett@gmail.com
|
74
|
-
executables:
|
74
|
+
executables:
|
75
|
+
- cloudwatch-sender
|
75
76
|
extensions: []
|
76
77
|
extra_rdoc_files: []
|
77
|
-
files:
|
78
|
+
files:
|
79
|
+
- ".gitignore"
|
80
|
+
- ".ruby-version"
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- bin/cloudwatch-sender
|
86
|
+
- cloudwatch-sender.gemspec
|
87
|
+
- configs/example.yaml
|
88
|
+
- lib/cloudwatch/sender/base.rb
|
89
|
+
- lib/cloudwatch/sender/cli.rb
|
90
|
+
- lib/cloudwatch/sender/ec2.rb
|
91
|
+
- lib/cloudwatch/sender/fetcher/base.rb
|
92
|
+
- lib/cloudwatch/sender/fetcher/custom.rb
|
93
|
+
- lib/cloudwatch/sender/fetcher/ec2.rb
|
94
|
+
- lib/cloudwatch/sender/fetcher/sqs.rb
|
95
|
+
- lib/cloudwatch/sender/metric_definition.rb
|
96
|
+
- lib/cloudwatch/sender/version.rb
|
97
|
+
- lib/cloudwatch_sender.rb
|
78
98
|
homepage: https://github.com/BBC-News/cloudwatch-sender
|
79
99
|
licenses:
|
80
100
|
- MIT
|