--- ------------------------------------------------------------------------------ --- flm_to_mdm.lua -- -- Example code to demonstrate how to migrate an FLM setup to MDM -- -- This work is licensed under a Creative Commons Attribution 3.0 Unported Licence --- -------------------------------------------------------------------------------- local gh = require "geneos.helpers" local gs = require "geneos.sampler" local lat = require "geneos.latency" -- Execute the config file, which creates a global variable "config" local config_file = gs.params["config.filename"] or "./flm_to_mdm_config.lua" dofile(config_file) -- Config validation assert(config.feeds.baseFeed, "No base feed configured") assert(#config.feeds.compFeeds > 0, "At least one comparison feed required") assert(#config.fields.names > 0, "At least one field name required") assert(#config.instruments.names > 0, "At least one instrument required") -- create and init context with the base local ctx = lat.newContext():setBase(config.feeds.baseFeed.name, config.feeds.baseFeed) -- add in all comparison feeds for _,feed in pairs(config.feeds.compFeeds) do ctx:addFeed(feed.name, feed) end -- start the latency module ctx:start() local viewLatency = assert(gs.createView("LATENCY", {"feed", "status", "peakLagMs", "averageLagMs", "stddevLagMs", "updateRate", "minLagMs", "numMatches" })) viewLatency.headline.baselineFeed = config.feeds.baseFeed.name assert(viewLatency:publish()) -- create a list of feed names for column headers local detailsCols = { "item", config.feeds.baseFeed.name } for _,feed in pairs(config.feeds.compFeeds) do detailsCols[#detailsCols+1]=feed.name end local viewDetails = assert(gs.createView("DETAILS", detailsCols)) for i=1, #config.instruments.names do viewDetails.row[config.instruments.names[i]] = {} end assert(viewDetails:publish()) -- create the values view local valuesCols = { "instr_feed" } for i=1, #config.fields.names do valuesCols[#valuesCols+1]=config.fields.names[i] end local viewValues = assert(gs.createView("VALUES", valuesCols)) assert(viewValues:publish()) local function formatMillisec(value) -- Format nil value as blank string return value and string.format("%0.2f", value*1000) or "" end local updateLatencyView = function(index, name, seconds, isBase) local metrics = assert(ctx:getMetrics(index)) local row = {} row.status = ctx:getFeedStatus(index) row.updateRate = 0.0 if metrics.numTicks > 0 then row.updateRate = string.format("%0.2f", metrics.numTicks / seconds) end if not isBase then row.peakLagMs = formatMillisec(metrics.latMax) row.averageLagMs = formatMillisec(metrics:getAverage()) row.stddevLagMs = formatMillisec(metrics:getStdDev()) row.minLagMs = formatMillisec(metrics.latMin) row.numMatches = metrics.matches end viewLatency.row[name] = row end local updateDetailsView = function(index, name, isBase) if not isBase then for i=1, #config.instruments.names do local inst_name = config.instruments.names[i] local metrics = assert(ctx:getMetrics(index, inst_name)) viewDetails.row[inst_name][name] = formatMillisec(metrics:getAverage()) end end end local updateValuesView = function(index, feed_name) -- for each instrument for ins=1, #config.instruments.names do local rowname = string.format("%s_%s", config.instruments.names[ins], feed_name) local lasttick = ctx:getLastTick(index, config.instruments.names[ins]) viewValues.row[rowname] = lasttick and lasttick.field or {} end end local updateViews = function(index, name, seconds, isBase) updateLatencyView(index, name, seconds, isBase) updateDetailsView(index, name, isBase) updateValuesView (index, name) end local last = gh.gettimeofday() gs.doSample = function() local now = gh.gettimeofday() local seconds = now - last last = now ctx:sample() -- update the base feed updateViews(0, config.feeds.baseFeed.name, seconds, true) -- update each comparison feed for i=1, #config.feeds.compFeeds do local feedName = config.feeds.compFeeds[i].name updateViews(i, feedName, seconds) end assert(viewLatency:publish()) assert(viewDetails:publish()) assert(viewValues :publish()) end