fluent-plugin-prometheus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ log_format ltsv 'time:$time_iso8601\t'
2
+ 'remote_addr:$remote_addr\t'
3
+ 'request_method:$request_method\t'
4
+ 'request_length:$request_length\t'
5
+ 'request_uri:$request_uri\t'
6
+ 'uri:$uri\t'
7
+ 'status:$status\t'
8
+ 'bytes_sent:$bytes_sent\t'
9
+ 'body_bytes_sent:$body_bytes_sent\t'
10
+ 'referer:$http_referer\t'
11
+ 'useragent:$http_user_agent\t'
12
+ 'request_time:$request_time\t'
13
+ 'upstream_response_time:$upstream_response_time';
14
+
15
+ server {
16
+ access_log /var/log/nginx/access_proxy.log ltsv;
17
+ listen 9999;
18
+ location / {
19
+ proxy_pass https://www.google.com;
20
+ }
21
+ }
22
+
@@ -0,0 +1,10 @@
1
+ # A job to scrape an endpoint of Fluentd running on localhost.
2
+ job: {
3
+ name: "fluentd"
4
+ scrape_interval: "5s"
5
+
6
+ target_group: {
7
+ target: "http://localhost:24231/metrics"
8
+ }
9
+ }
10
+
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'fluent/plugin/filter_prometheus'
3
+ require_relative 'shared'
4
+
5
+ describe Fluent::PrometheusFilter do
6
+ let(:tag) { 'prometheus.test' }
7
+ let(:driver) { Fluent::Test::FilterTestDriver.new(Fluent::PrometheusFilter, tag).configure(config, true) }
8
+ let(:registry) { ::Prometheus::Client.registry }
9
+
10
+ describe '#configure' do
11
+ it_behaves_like 'output configuration'
12
+ end
13
+
14
+ describe '#run' do
15
+ let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100} }
16
+ let(:es) { driver.run { driver.emit(message, Time.now) }.filtered }
17
+
18
+ context 'simple config' do
19
+ include_context 'simple_config'
20
+
21
+ it 'adds a new counter metric' do
22
+ expect(registry.metrics.map(&:name)).not_to include(name)
23
+ es
24
+ expect(registry.metrics.map(&:name)).to include(name)
25
+ end
26
+
27
+ it 'should keep original message' do
28
+ expect(es.first[1]).to eq(message)
29
+ end
30
+ end
31
+
32
+ it_behaves_like 'instruments record'
33
+ end
34
+ end if defined?(Fluent::PrometheusFilter)
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'fluent/plugin/out_prometheus'
3
+ require_relative 'shared'
4
+
5
+ describe Fluent::PrometheusOutput do
6
+ let(:tag) { 'prometheus.test' }
7
+ let(:driver) { Fluent::Test::OutputTestDriver.new(Fluent::PrometheusOutput, tag).configure(config) }
8
+ let(:registry) { ::Prometheus::Client.registry }
9
+
10
+ describe '#configure' do
11
+ it_behaves_like 'output configuration'
12
+ end
13
+
14
+ describe '#run' do
15
+ let(:message) { {"foo" => 100, "bar" => 100, "baz" => 100} }
16
+ let(:es) { driver.run { driver.emit(message, Time.now) } }
17
+
18
+ context 'simple config' do
19
+ include_context 'simple_config'
20
+
21
+ it 'adds a new counter metric' do
22
+ expect(registry.metrics.map(&:name)).not_to include(name)
23
+ es
24
+ expect(registry.metrics.map(&:name)).to include(name)
25
+ end
26
+ end
27
+
28
+ it_behaves_like 'instruments record'
29
+ end
30
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+ require 'fluent/plugin/in_prometheus'
3
+
4
+ require 'net/http'
5
+
6
+ describe Fluent::PrometheusInput do
7
+ CONFIG = %[
8
+ type prometheus
9
+ ]
10
+
11
+ LOCAL_CONFIG = %[
12
+ type prometheus
13
+ bind 127.0.0.1
14
+ ]
15
+
16
+ let(:config) { CONFIG }
17
+ let(:port) { 24231 }
18
+ let(:driver) { Fluent::Test::InputTestDriver.new(Fluent::PrometheusInput).configure(config) }
19
+
20
+ describe '#configure' do
21
+ describe 'bind' do
22
+ let(:config) { CONFIG + %[
23
+ bind 127.0.0.1
24
+ ] }
25
+ it 'should be configurable' do
26
+ expect(driver.instance.bind).to eq('127.0.0.1')
27
+ end
28
+ end
29
+
30
+ describe 'port' do
31
+ let(:config) { CONFIG + %[
32
+ port 8888
33
+ ] }
34
+ it 'should be configurable' do
35
+ expect(driver.instance.port).to eq(8888)
36
+ end
37
+ end
38
+
39
+ describe 'metrics_path' do
40
+ let(:config) { CONFIG + %[
41
+ metrics_path /_test
42
+ ] }
43
+ it 'should be configurable' do
44
+ expect(driver.instance.metrics_path).to eq('/_test')
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#run' do
50
+ context '/metrics' do
51
+ let(:config) { LOCAL_CONFIG }
52
+ it 'returns 200' do
53
+ driver.run do
54
+ Net::HTTP.start("127.0.0.1", port) do |http|
55
+ req = Net::HTTP::Get.new("/metrics")
56
+ res = http.request(req)
57
+ expect(res.code).to eq('200')
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ context '/foo' do
64
+ let(:config) { LOCAL_CONFIG }
65
+ it 'does not return 200' do
66
+ driver.run do
67
+ Net::HTTP.start("127.0.0.1", port) do |http|
68
+ req = Net::HTTP::Get.new("/foo")
69
+ res = http.request(req)
70
+ expect(res.code).not_to eq('200')
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,210 @@
1
+
2
+ BASE_CONFIG = %[
3
+ type prometheus
4
+ ]
5
+
6
+
7
+ SIMPLE_CONFIG = BASE_CONFIG + %[
8
+ type prometheus
9
+ <metric>
10
+ name simple_foo
11
+ type counter
12
+ desc Something foo.
13
+ key foo
14
+ </metric>
15
+ ]
16
+
17
+ FULL_CONFIG = BASE_CONFIG + %[
18
+ <metric>
19
+ name full_foo
20
+ type counter
21
+ desc Something foo.
22
+ key foo
23
+ <labels>
24
+ key foo1
25
+ </labels>
26
+ </metric>
27
+ <metric>
28
+ name full_bar
29
+ type gauge
30
+ desc Something bar.
31
+ key bar
32
+ <labels>
33
+ key foo2
34
+ </labels>
35
+ </metric>
36
+ <metric>
37
+ name full_baz
38
+ type summary
39
+ desc Something baz.
40
+ key baz
41
+ <labels>
42
+ key foo3
43
+ </labels>
44
+ </metric>
45
+ <labels>
46
+ test_key test_value
47
+ </labels>
48
+ ]
49
+
50
+ PLACEHOLDER_CONFIG = BASE_CONFIG + %[
51
+ <metric>
52
+ name placeholder_foo
53
+ type counter
54
+ desc Something foo.
55
+ key foo
56
+ <labels>
57
+ foo ${foo}
58
+ </labels>
59
+ </metric>
60
+ <labels>
61
+ tag ${tag}
62
+ hostname ${hostname}
63
+ </labels>
64
+ ]
65
+
66
+ COUNTER_WITHOUT_KEY_CONFIG = BASE_CONFIG + %[
67
+ <metric>
68
+ name without_key_foo
69
+ type counter
70
+ desc Something foo.
71
+ </metric>
72
+ ]
73
+
74
+ shared_context 'simple_config' do
75
+ let(:orig_name) { 'simple_foo' }
76
+ let(:config) { SIMPLE_CONFIG.gsub(orig_name, name.to_s) }
77
+ let(:name) { "#{orig_name}_#{Time.now.to_f}".to_sym }
78
+ let(:counter) { registry.get(name) }
79
+ end
80
+
81
+ shared_context 'full_config' do
82
+ let(:config) { FULL_CONFIG }
83
+ let(:counter) { registry.get(:full_foo) }
84
+ let(:gauge) { registry.get(:full_bar) }
85
+ let(:summary) { registry.get(:full_baz) }
86
+ end
87
+
88
+ shared_context 'placeholder_config' do
89
+ let(:orig_name) { 'placeholder_foo' }
90
+ let(:config) { PLACEHOLDER_CONFIG.gsub(orig_name, name.to_s) }
91
+ let(:name) { "#{orig_name}_#{Time.now.to_f}".to_sym }
92
+ let(:counter) { registry.get(name) }
93
+ end
94
+
95
+ shared_context 'counter_without_key_config' do
96
+ let(:orig_name) { 'without_key_foo' }
97
+ let(:config) { COUNTER_WITHOUT_KEY_CONFIG.gsub(orig_name, name.to_s) }
98
+ let(:name) { "#{orig_name}_#{Time.now.to_f}".to_sym }
99
+ let(:counter) { registry.get(name) }
100
+ end
101
+
102
+ shared_examples_for 'output configuration' do
103
+ context 'base config' do
104
+ let(:config) { BASE_CONFIG }
105
+ it 'does not raise error' do
106
+ expect{driver}.not_to raise_error
107
+ end
108
+ end
109
+
110
+ describe 'configure simple configuration' do
111
+ include_context 'simple_config'
112
+ it { expect{driver}.not_to raise_error }
113
+ end
114
+
115
+ describe 'configure full configuration' do
116
+ include_context 'full_config'
117
+ it { expect{driver}.not_to raise_error }
118
+ end
119
+
120
+ describe 'configure placeholder configuration' do
121
+ include_context 'placeholder_config'
122
+ it { expect{driver}.not_to raise_error }
123
+ end
124
+
125
+ describe 'configure counter without key configuration' do
126
+ include_context 'counter_without_key_config'
127
+ it { expect{driver}.not_to raise_error }
128
+ end
129
+
130
+ context 'unknown type' do
131
+ let(:config) { BASE_CONFIG + %[
132
+ <metric>
133
+ type foo
134
+ </metric>
135
+ ] }
136
+ it 'raises ConfigError' do
137
+ expect{driver}.to raise_error Fluent::ConfigError
138
+ end
139
+ end
140
+ end
141
+
142
+ shared_examples_for 'instruments record' do
143
+ context 'full config' do
144
+ include_context 'full_config'
145
+
146
+ before :each do
147
+ es
148
+ end
149
+
150
+ it 'adds all metrics' do
151
+ expect(registry.metrics.map(&:name)).to include(:full_foo)
152
+ expect(registry.metrics.map(&:name)).to include(:full_bar)
153
+ expect(registry.metrics.map(&:name)).to include(:full_baz)
154
+ expect(counter).to be_kind_of(::Prometheus::Client::Metric)
155
+ expect(gauge).to be_kind_of(::Prometheus::Client::Metric)
156
+ expect(summary).to be_kind_of(::Prometheus::Client::Metric)
157
+ end
158
+
159
+ it 'instruments counter metric' do
160
+ expect(counter.type).to eq(:counter)
161
+ expect(counter.get({test_key: 'test_value', key: 'foo1'})).to be_kind_of(Integer)
162
+ end
163
+
164
+ it 'instruments gauge metric' do
165
+ expect(gauge.type).to eq(:gauge)
166
+ expect(gauge.get({test_key: 'test_value', key: 'foo2'})).to eq(100)
167
+ end
168
+
169
+ it 'instruments summary metric' do
170
+ expect(summary.type).to eq(:summary)
171
+ expect(summary.get({test_key: 'test_value', key: 'foo3'})).to be_kind_of(Hash)
172
+ expect(summary.get({test_key: 'test_value', key: 'foo3'})[0.99]).to eq(100)
173
+ end
174
+ end
175
+
176
+ context 'placeholder config' do
177
+ include_context 'placeholder_config'
178
+
179
+ before :each do
180
+ es
181
+ end
182
+
183
+ it 'expands placeholders with record values' do
184
+ expect(registry.metrics.map(&:name)).to include(name)
185
+ expect(counter).to be_kind_of(::Prometheus::Client::Metric)
186
+ key, _ = counter.values.find {|k,v| v == 100 }
187
+ expect(key).to be_kind_of(Hash)
188
+ expect(key[:tag]).to eq(tag)
189
+ expect(key[:hostname]).to be_kind_of(String)
190
+ expect(key[:hostname]).not_to eq("${hostname}")
191
+ expect(key[:hostname]).not_to be_empty
192
+ expect(key[:foo]).to eq("100")
193
+ end
194
+ end
195
+
196
+ context 'counter_without config' do
197
+ include_context 'counter_without_key_config'
198
+
199
+ before :each do
200
+ es
201
+ end
202
+
203
+ it 'just increments by 1' do
204
+ expect(registry.metrics.map(&:name)).to include(name)
205
+ expect(counter).to be_kind_of(::Prometheus::Client::Metric)
206
+ _, value = counter.values.find {|k,v| k == {} }
207
+ expect(value).to eq(1)
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'fluent/test'
3
+ require 'fluent/plugin/prometheus'
4
+
5
+ # Disable Test::Unit
6
+ Test::Unit::AutoRunner.need_auto_run = false
7
+
8
+ Fluent::Test.setup
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-prometheus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Masahiro Sano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: prometheus-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: test-unit
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: A fluent plugin that collects metrics and exposes for Prometheus.
98
+ email:
99
+ - sabottenda@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - Gemfile.fluentd.0.10
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - fluent-plugin-prometheus.gemspec
113
+ - lib/fluent/plugin/filter_prometheus.rb
114
+ - lib/fluent/plugin/in_prometheus.rb
115
+ - lib/fluent/plugin/in_prometheus_monitor.rb
116
+ - lib/fluent/plugin/out_prometheus.rb
117
+ - lib/fluent/plugin/prometheus.rb
118
+ - misc/fluentd_sample.conf
119
+ - misc/nginx_proxy.conf
120
+ - misc/prometheus.conf
121
+ - spec/fluent/plugin/filter_prometheus_spec.rb
122
+ - spec/fluent/plugin/out_prometheus_spec.rb
123
+ - spec/fluent/plugin/prometheus_spec.rb
124
+ - spec/fluent/plugin/shared.rb
125
+ - spec/spec_helper.rb
126
+ homepage: https://github.com/kazegusuri/fluent-plugin-prometheus
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.2.3
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: A fluent plugin that collects metrics and exposes for Prometheus.
150
+ test_files:
151
+ - spec/fluent/plugin/filter_prometheus_spec.rb
152
+ - spec/fluent/plugin/out_prometheus_spec.rb
153
+ - spec/fluent/plugin/prometheus_spec.rb
154
+ - spec/fluent/plugin/shared.rb
155
+ - spec/spec_helper.rb