Skip to content

Commit

Permalink
[prometheus] create prometheus exporter skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
mikz committed Feb 28, 2018
1 parent af14a54 commit 619bc40
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Error loading policy chain configuration JSON with null value [PR #626](https://github.com/3scale/apicast/pull/626)
- Splitted `resolv.conf` in lines,to avoid commented lines [PR #618](https://github.com/3scale/apicast/pull/618)

## Added

- New `metrics` phase that runs when prometheus is collecting metrics [PR #629](https://github.com/3scale/apicast/pull/629)

## [3.2.0-beta1] - 2018-02-20

## Added
Expand Down
6 changes: 5 additions & 1 deletion doc/policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ APIcast.

A policy tells APIcast what it should do in each of the nginx phases: `init`,
`init_worker`, `rewrite`, `access`,`content`, `balancer`, `header_filter`, `body_filter`,
`post_action`, and `log`.
`post_action`, `log`, and `metrics`.

Policies can share data between them. They do that through what we call the
`context`. Policies can read from and modify that context in every phase.

All phases except `init`, `init_worker` and `metrics` can be evaluated when
proxying a request. `metrics` is evaluated when [Prometheus](https://prometheus.io)
gets data from the metrics endpoint. `init` and `init_worker` are evaluated
when starting the gateway.

## Policy chains

Expand Down
1 change: 1 addition & 0 deletions gateway/Roverfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ luassert 1.7.10-0||testing
luasystem 0.2.1-0||testing
markdown 0.33-1||development
mediator_lua 1.1.2-0||testing
nginx-lua-prometheus 0.20171117-4||production
penlight 1.5.4-1||production,development,testing
router 2.1-0||production
say 1.3-1||testing
1 change: 1 addition & 0 deletions gateway/apicast-scm-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies = {
'liquid',
'argparse',
'penlight',
'nginx-lua-prometheus',
}
build = {
type = "make",
Expand Down
18 changes: 18 additions & 0 deletions gateway/conf/nginx.conf.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ http {
{% include "conf.d/apicast.conf" %}
}

{% if port.metrics %}
lua_shared_dict prometheus_metrics 16M;
server {
access_log off;
listen {{ port.metrics }};
server_name metrics prometheus _;

location /metrics {
content_by_lua_block { require('apicast.executor'):metrics() }
}

location /nginx_status {
internal;
stub_status;
}
}
{% endif %}

{% for file in "sites.d/*.conf" | filesystem %}
{% include file %}
{% endfor %}
Expand Down
3 changes: 2 additions & 1 deletion gateway/config/development.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ return {
lua_code_cache = 'on',
configuration_loader = 'lazy',
configuration_cache = 0,
configuration = data_url('application/json', configuration)
configuration = data_url('application/json', configuration),
port = { metrics = 9421 }, -- see https://github.com/prometheus/prometheus/wiki/Default-port-allocations
}
8 changes: 8 additions & 0 deletions gateway/src/apicast/executor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require('apicast.loader') -- to load code from deprecated paths
local PolicyChain = require('apicast.policy_chain')
local policy = require('apicast.policy')
local linked_list = require('apicast.linked_list')
local prometheus = require('apicast.prometheus')

local setmetatable = setmetatable

Expand Down Expand Up @@ -58,4 +59,11 @@ function _M:context(phase)
return shared_build_context(self)
end

local metrics = _M.metrics
--- Render metrics from all policies.
function _M:metrics(...)
metrics(self, ...)
return prometheus:collect()
end

return _M.new(PolicyChain.default())
2 changes: 1 addition & 1 deletion gateway/src/apicast/policy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ local PHASES = {
'rewrite', 'access',
'content', 'balancer',
'header_filter', 'body_filter',
'post_action', 'log'
'post_action', 'log', 'metrics',
}

local setmetatable = setmetatable
Expand Down
23 changes: 23 additions & 0 deletions gateway/src/apicast/prometheus.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
local prometheus = require('nginx.prometheus')
local assert = assert
local dict = 'prometheus_metrics'

if ngx.shared[dict] then
local init = prometheus.init(dict)

local metrics = { }
local __call = function(_, type, name, ...)
local metric_name = assert(name, 'missing metric name')

if not metrics[metric_name] then
metrics[metric_name] = init[assert(type, 'missing metric type')](init, metric_name, ...)
end

return metrics[metric_name]
end

return setmetatable({ }, { __call = __call, __index = init })
else
local noop = function() end
return setmetatable({ collect = noop }, { __call = noop })
end
2 changes: 1 addition & 1 deletion spec/policy_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('policy', function()
'rewrite', 'access',
'content', 'balancer',
'header_filter', 'body_filter',
'post_action', 'log'
'post_action', 'log', 'metrics'
}

describe('.new', function()
Expand Down
52 changes: 52 additions & 0 deletions spec/prometheus_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

describe('prometheus', function()
before_each(function() package.loaded['apicast.prometheus'] = nil end)

describe('shared dictionary is missing', function()
before_each(function() ngx.shared.prometheus_metrics = nil end)

it('can be called', function()
assert.is_nil(require('apicast.prometheus')())
end)

it('can be collected', function()
assert.is_nil(require('apicast.prometheus'):collect())
end)
end)

describe('shared dictionary is there', function()
before_each(function()
ngx.shared.prometheus_metrics = {
set = function() end,
get_keys = function() return {} end
}
end)

local prometheus
local Prometheus

before_each(function()
prometheus = assert(require('apicast.prometheus'))
Prometheus = getmetatable(prometheus).__index
end)

for _,metric_type in pairs{ 'counter', 'gauge', 'histogram' } do
describe(metric_type, function()
it('can be called', function()
stub(Prometheus, metric_type)

prometheus(metric_type, 'some_metric')

assert.stub(Prometheus[metric_type]).was.called_with(Prometheus, 'some_metric')
end)
end)
end


it('can be collected', function()
ngx.header = { }
assert.is_nil(require('apicast.prometheus'):collect())
end)
end)

end)

0 comments on commit 619bc40

Please sign in to comment.