blob: 47d322b47473e3618e3f25ef51c08d6e7500c72e [file] [log] [blame]
-- Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
--
-- Permission is hereby granted, free of charge, to any person obtaining a
-- copy of this software and associated documentation files (the "Software"),
-- to deal in the Software without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons to whom the
-- Software is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
-- Base class for analytics with functions for calculating counts,timers
-- and updating the cache with data on every service call.
--
--
--
-- Usage in Nginx conf:
--
-- location api-gateway-stats {
-- allow 127.0.0.1;
-- deny all;
-- content_by_lua '
-- local MetricsBuffer = require "metrics.MetricsBuffer"
-- local metrics = MetricsBuffer:new()
-- local json = assert( metrics:toJson(), "Could not read metrics")
-- ngx.say( json )
-- ';
-- }
local cjson = require "cjson"
local M = {}
function M:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
--- Increments a counter with the given <value>
-- @param metric The name of the metrics
-- @param value The value to intecrement with
--
function M:count(metric, value)
local localMetrics = ngx.shared.stats_counters
local r
if ( localMetrics == nil ) then
ngx.log(ngx.ERROR, "Please define 'lua_shared_dict stats_counters 50m;' in http block")
return nil
end
value = tonumber(value) or 0
if value == 0 then -- to exit when nil/zero
return 0
end
r = localMetrics:incr(metric, value)
if ( r == nil ) then
localMetrics:add(metric, value)
return value
end
return r
end
--- Adds a new timer value. Unline counters, timers are averaged when flushed
-- @param metric The name of the metrics
-- @param value A new value for the timer
--
function M:timer(metric, value)
local localMetrics = ngx.shared.stats_timers
local r, counter
if ( localMetrics == nil ) then
ngx.log(ngx.ERROR, "Please define 'lua_shared_dict stats_timers 50m;' in http block")
return nil
end
value = tonumber(value) or -2
-- Timers are counting only the positive values, by convention
if ( value < 0 ) then
return value
end
r, counter = localMetrics:get(metric)
if ( r == nil ) then
localMetrics:set(metric, value, 0, 1)
return value
end
-- FIXES: attempt to perform arithmetic on local 'counter' (a nil value)
if ( counter == nil ) then
counter = 0
end
-- Adding the timers and increamenting the counter to compute avg later
counter = counter + 1
r = r + value
localMetrics:set(metric, r, 0, counter)
return r
end
function M:getJsonFor( metric_type )
-- convert shared_dict to table
local localMetrics = ngx.shared[metric_type]
if ( localMetrics == nil ) then
return nil
end
local keys = localMetrics:get_keys(1024)
local counter
local jsonObj = {}
local count = 0
for i,metric in pairs(keys) do
local value, counter = localMetrics:get(metric)
if(counter == nil) then
counter = 0
end
-- check if avg needs to be computed
if(counter == 1 or counter == 0) then
jsonObj[metric] = value
end
if(counter >= 2) then
jsonObj[metric] = math.floor(value/counter)
end
-- mark item as expired
localMetrics:set(metric, 0, 0.001,0)
count = i
end
return cjson.encode(jsonObj),count,jsonObj
end
function M:toJson( flushExpiredMetrics )
local counters, count_counters, counterObject = self:getJsonFor("stats_counters")
local timers, count_timers, timerObject = self:getJsonFor("stats_timers")
local flush = flushExpiredMetrics or true
-- ngx.log(ngx.INFO, "Wrote " .. count_counters .. " counters and " .. count_timers .. " timers.")
if ( flush == true ) then
self:flushExpiredKeys()
end
return "{\"counters\":" .. counters .. ",\"timers\":" .. timers .. "}", counterObject, timerObject
end
function M:flushExpiredKeys()
local metrics = ngx.shared.stats_counters
if ( metrics ~= nil ) then
metrics:flush_expired()
end
metrics = ngx.shared.stats_timers
if ( metrics ~= nil ) then
metrics:flush_expired()
end
end
return M