Skip to content

Commit

Permalink
Add count metrics exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
alain-andre committed Dec 2, 2022
1 parent 525fac9 commit 8930700
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 38 deletions.
87 changes: 63 additions & 24 deletions api/v01/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
require './api/v01/matrix'
require './api/v01/isoline'
require './api/v01/capability'
require './api/v01/entities/metrics'

require 'active_support/core_ext/string/conversions'

Expand Down Expand Up @@ -57,26 +58,53 @@ def count_time
end

def count_base_key(operation, period = :daily)
count_date = if period == :daily
count_time.to_s[0..9]
elsif period == :monthly
count_time.to_s[0..6]
elsif period == :yearly
count_time.to_s[0..3]
end
[
[:router, operation, count_date].compact,
count_base_key_no_key(operation, period),
[:key, params[:api_key]]
].map{ |a| a.join(':') }.join('_')
end

def count_base_key_no_key(operation, period = :daily)
count_date =
if period == :daily
count_time.to_s[0..9]
elsif period == :monthly
count_time.to_s[0..6]
elsif period == :yearly
count_time.to_s[0..3]
end
[:router, operation, count_date].compact
end

def count_key(operation)
@count_key ||= count_base_key(operation) + '_' + [
[:ip, (env['action_dispatch.remote_ip'] || request.ip).to_s],
[:asset, params[:asset]]
].map{ |a| a.join(':') }.join('_')
end

def split_key(key)
json = {}
key.split('_').each do |values|
rs = values.split(':')

case rs[0]
when "router"
json['service'] = rs[0]
json['endpoint'] = rs[1]
json['date'] = rs[2]
when "key"
json['key'] = rs[1]
when "ip"
json['ip'] = rs[1]
when "asset"
json['asset'] = rs[1]
end
end

json
end

def count(operation, raise_if_exceed = true, request_size = 1)
return unless redis_count

Expand Down Expand Up @@ -114,6 +142,31 @@ def count_incr(operation, options)
end
end if options[:transactions]
end

def metric(key)
hkey = split_key(key)

if redis_count.type(key) == 'hash'
hredis = redis_count.hgetall(key)

if hredis&.key?('hits')
{
count_asset: hkey['asset'],
count_date: hkey['date'],
count_endpoint: hkey['endpoint'],
count_hits: hredis['hits'],
count_ip: hkey['ip'],
count_key: hkey['key'],
count_service: hkey['service'],
count_transactions: hredis['transactions'],
}
else
::Api::Root.logger.warn("Metrics: #{key} has no hits") && {}
end
else
::Api::Root.logger.warn("Metrics: #{key} is not a hash") && {}
end
end
end

rescue_from :all, backtrace: ENV['APP_ENV'] != 'production' do |e|
Expand Down Expand Up @@ -155,25 +208,11 @@ def count_incr(operation, options)
resource :metrics do
desc 'Return Prometheus metrics', {}
get do
error!('Unauthorized', 401) unless OptimizerWrapper.access[params[:api_key]][:metrics] == true
error!('Unauthorized', 401) unless RouterWrapper.access[params[:api_key]][:metrics] == true

status 200
present(
redis_count.keys("*#{count_base_key_no_key('optimize').join(':')}*").flat_map{ |key|
hkey = split_key(key)
hredis = redis_count.hgetall(key)

{
count_asset: hkey['asset'],
count_date: hkey['date'],
count_endpoint: hkey['endpoint'],
count_hits: hredis['hits'],
count_ip: hkey['ip'],
count_key: hkey['key'],
count_service: hkey['service'],
count_transactions: hredis['transactions'],
}
}, with: Metrics
redis_count.keys("*#{count_base_key_no_key('*').join(':')}*").flat_map{ |key| metric(key) }, with: Metrics
)
end
end
Expand Down
1 change: 0 additions & 1 deletion api/v01/entities/metrics.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@@ -0,0 +1,36 @@
# Copyright © Mapotempo, 2015
#
# This file is part of Mapotempo.
Expand Down
34 changes: 21 additions & 13 deletions test/api/v01/api_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,33 @@ def test_should_not_access_if_expired
end

def test_metrics
clear_optim_redis_count
post '/0.1/vrp/submit?asset=myAsset', { api_key: 'demo', vrp: VRP.toy }.to_json, \
'CONTENT_TYPE' => 'application/json'
clear_router_redis_count
post '/0.1/routes', { api_key: 'demo', locs: '43.2805,5.3806,43.2804,5.3806,43.330672,5.375404' }

assert last_response.ok?, last_response.body

get '0.1/metrics', { api_key: 'demo'}
get '0.1/metrics.json', { api_key: 'demo'}
assert_equal 401, last_response.status

get '0.1/metrics', { api_key: 'metrics'}
get '0.1/metrics.json', { api_key: 'metrics'}
assert last_response.ok?, last_response.body
json = JSON.parse(last_response.body).first

assert_equal Date.today.strftime("%Y-%m-%d"), json["count_date"]
assert_equal "1", json["count_hits"]
assert_equal "1", json["count_transactions"]
assert_equal "127.0.0.1", json["count_ip"]
assert_equal "demo", json["count_key"]
assert_equal "myAsset", json["count_asset"]
assert_equal "optimizer", json["count_service"]
assert_equal "optimize", json["count_endpoint"]
assert_equal Date.today.strftime('%Y-%m-%d'), json['count_date']
assert_equal '1', json['count_hits']
assert_equal '2', json['count_transactions']
assert_equal '127.0.0.1', json['count_ip']
assert_equal 'demo', json['count_key']
assert_equal 'router', json['count_service']
assert_equal 'route', json['count_endpoint']

post '/0.1/matrix', {api_key: 'demo', src: '43.2804,5.3806,43.2804,5.3806' }

get '0.1/metrics.json', { api_key: 'metrics'}
assert last_response.ok?, last_response.body
json = JSON.parse(last_response.body)
assert_equal 2, json.count
assert_equal '1', json[1]['count_hits']
assert_equal '4', json[1]['count_transactions']
end
end
6 changes: 6 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ def random_location(centroid, max_radius)
[random_lat.round(5), random_lng.round(5)] # meter precision
end

def clear_router_redis_count
RouterWrapper.config[:redis_count].keys.select{ |key| key =~ /router:/ }.each do |to_remove|
RouterWrapper.config[:redis_count].del(to_remove)
end
end

module FakeRedis
def teardown
RouterWrapper.config[:redis_count].flushall
Expand Down

0 comments on commit 8930700

Please sign in to comment.