cloudwatch-sender 0.1.0 → 0.1.1
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/.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
|