From dfb8248e5a787841dee85805e79d89ae93d7529a Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Mon, 16 Feb 2015 18:58:13 -0600 Subject: [PATCH 01/16] Added Luvit support for postgresql --- README.md | 5 + index.lua | 25 ++ modules/boundary.lua | 15 ++ modules/luvit-postgres/postgresLuvit.lua | 194 +++++++++++++++ modules/luvit-postgres/postgresffi.lua | 288 +++++++++++++++++++++++ modules/pginfo.lua | 92 ++++++++ param.json | 8 + plugin.json | 3 + 8 files changed, 630 insertions(+) create mode 100644 index.lua create mode 100644 modules/boundary.lua create mode 100644 modules/luvit-postgres/postgresLuvit.lua create mode 100644 modules/luvit-postgres/postgresffi.lua create mode 100644 modules/pginfo.lua create mode 100644 param.json diff --git a/README.md b/README.md index 782a2ce..f2eef05 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,12 @@ Extracts metrics from a PostgreSQL database instance. |:----------|:-----:|:-------:|:-------:|:----:| | Supported | v | v | v | v | +For Boundary Meter V4.0 (to update/download - curl -fsS -d '{"token":"api."}' -H 'Content-Type: application/json' https://meter.boundary.com/setup_meter > setup_meter.sh && chmod +x setup_meter.sh && ./setup_meter.sh) +| Runtime | node.js | Python | Java | +|:---------|:-------:|:------:|:----:| +| Required | | | | +For Boundary Meter less than V4.0 | Runtime | node.js | Python | Java | |:---------|:-------:|:------:|:----:| | Required | | + | | diff --git a/index.lua b/index.lua new file mode 100644 index 0000000..22170d9 --- /dev/null +++ b/index.lua @@ -0,0 +1,25 @@ +local boundary = require('boundary') +local pginfo = require('pginfo') + +-- Default params +local host = "localhost" +local port = 5432 +local user = "postgres" +local pwd = "" +local database = "postgres" +local source = "" + +-- Fetching params +if (boundary.param ~= nil) then + host = boundary.param['host'] or host + port = boundary.param['port'] or port + user = boundary.param['user'] or user + pwd = boundary.param['pwd'] or pwd + database = boundary.param['database'] or database + source = boundary.param['source'] or source +end + +print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") + +local dbcon = pginfo:new(host, port, user, pwd, database, source) +print(dbcon:get_databases()) diff --git a/modules/boundary.lua b/modules/boundary.lua new file mode 100644 index 0000000..e1bcb43 --- /dev/null +++ b/modules/boundary.lua @@ -0,0 +1,15 @@ +-- Copyright 2015 Boundary +-- @brief convenience variables and functions for Lua scripts +-- @file boundary.lua +local fs = require('fs') +local json = require('json') + +local boundary = {param = nil} + +-- import param.json data into a Lua table (boundary.param) +local json_blob +if (pcall(function () json_blob = fs.readFileSync("param.json") end)) then + pcall(function () boundary.param = json.parse(json_blob) end) +end + +return boundary diff --git a/modules/luvit-postgres/postgresLuvit.lua b/modules/luvit-postgres/postgresLuvit.lua new file mode 100644 index 0000000..378f82d --- /dev/null +++ b/modules/luvit-postgres/postgresLuvit.lua @@ -0,0 +1,194 @@ +-------------------------------------------------------------------------- +-- This module is a luvit binding for the postgresql api. +-- +-- Copyright (C) 2012 Moritz Kühner, Germany. +-- 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. +-------------------------------------------------------------------------- + +local postgres = require("./postgresffi") +local timer = require('timer') +local object = require('core').Object +local table = require("table") + + +--[[Loads the library at POSTGRESQL_LIBRARY_PATH if not nil + defaults to "/usr/lib/libpq.so.5". + + To use this set the global with a string pointing at the right + path befor requiring this library. +]] +postgres.init(POSTGRESQL_LIBRARY_PATH) + + +--Timeout for the poll timer +local POLLTIMER_INTERVALL = 5 + + +local LuvPostgres = object:extend() + +local function callIfNotNil(callback, ...) + if callback ~= nil then + callback(...) + end +end + +--[[Constructor the coninfo string is passed to PQconnectStart. +]] +function LuvPostgres:initialize(coninfo, callback) + self.con = postgres.newAsync(coninfo) + + --[[ This is an dirty hack to update the connection state. The correct + solution should watch the socket descriptor and update upon + network activity + ]] + self.watcher = timer.setInterval(POLLTIMER_INTERVALL, function() + local state = self.con:dialUpState() + if 0 == state then + timer.clearTimer(self.watcher) + self.established = true + callIfNotNil(callback) + elseif 1 == state then + timer.clearTimer(self.watcher) + callIfNotNil(callback, self.con:getError()) + end + end) +end + + +-- internal function to retrieve a fragment of the result +local function getFragment(connection) + local ok, ready = pcall(connection.readReady, connection) + + if not ok then + --error occured + return nil, ready + elseif not ready then + --no input ready + return {} + end + + local ok, result , status = pcall(connection.getAvailable, connection) + if not ok then + --error occured + return nil, ready + end + + local isOver = false + if status <= 7 then + --query is over + if connection:getAvailable() ~= nil then + --internal error occured + return nil, "Internal binding error. Query is not over!" + end + + if status == 5 or status == 7 then + --error occured + return nil, connection:getError() + end + isOver = true + end + + return result, isOver +end + +--[[Sends a query to the sql server + + Callback is called with error and the entire resultset. + Read postgresffi.getAvailable for a description of the format. +]] +function LuvPostgres:sendQuery(query, callback) + if not self.established then + callIfNotNil(callback, "Can't send query. Connection is not established!") + return + end + self.con:sendQuery(query) + + local resultAccu = {} + --[[ This is an dirty hack to update the connection state. The correct + solution should watch the socket descriptor and update upon + network activity + ]] + self.watcher = timer.setInterval(POLLTIMER_INTERVALL, function() + local result, over = getFragment(self.con) + + if not result then + timer.clearTimer(self.watcher) + callIfNotNil(callback, over) + else + local cntRow = #result + for i = 1, cntRow do + table.insert(resultAccu, result[i]) + end + + if over then + resultAccu[0] = result[0] + timer.clearTimer(self.watcher) + callIfNotNil(callback, nil, resultAccu) + end + end + end) +end + +--[[Sends a query to the sql server and returns intermediate results + + Callback is called with error and subset of the result and to mark the end a boolean true. + Read postgresffi.getAvailable for a description of the format. +]] +function LuvPostgres:sendQueryIntermediate(query, callback) + if not self.established then + callIfNotNil(callback, "Can't send query. Connection is not established!") + return + end + self.con:sendQuery(query) + + --[[ This is an dirty hack to update the connection state. The correct + solution should watch the socket descriptor and update upon + network activity + ]] + self.watcher = timer.setInterval(POLLTIMER_INTERVALL, function() + local result, over = getFragment(self.con) + if not result then + timer.clearTimer(self.watcher) + callIfNotNil(callback, over) + else + if over then + timer.clearTimer(self.watcher) + end + callIfNotNil(callback, nil, result, over) + end + end) +end + + +--[[Returns a escaped version of the string than can be savely + used in a query without danger of SQL injection or nil and + a message on error +]] +function LuvPostgres:escape(query) + local ok, value = pcall(self.con.escape, self.con, query) + if ok then + return value + end + return nil, value +end + + + +return LuvPostgres diff --git a/modules/luvit-postgres/postgresffi.lua b/modules/luvit-postgres/postgresffi.lua new file mode 100644 index 0000000..9972660 --- /dev/null +++ b/modules/luvit-postgres/postgresffi.lua @@ -0,0 +1,288 @@ +-------------------------------------------------------------------------- +-- This module is a luajit ffi binding for the postgresql api +-- with a spacial emphasis on the non blocking functions. +-- +-- Copyright (C) 2012 Moritz Kühner, Germany. +-- 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. +-------------------------------------------------------------------------- + +PSqlConnection = {} +local PSqlConnection_mt = { __index = PSqlConnection } + +local ffi = require("ffi") +local libpq = nil + +--definitions of the c api +--se http://www.postgresql.org/docs/9.2/static/libpq-async.html +ffi.cdef[[ +typedef struct PGconn_s PGconn; +typedef struct PGresult_s PGresult; + +typedef enum +{ + PGRES_POLLING_FAILED = 0, + PGRES_POLLING_READING, /* These two indicate that one may */ + PGRES_POLLING_WRITING, /* use select before polling again. */ + PGRES_POLLING_OK +} PostgresPollingStatusType; + +typedef enum +{ + PGRES_EMPTY_QUERY = 0, /* empty query string was executed */ + PGRES_COMMAND_OK, /* a query command that doesn't return + * anything was executed properly by the + * backend */ + PGRES_TUPLES_OK, /* a query command that returns tuples was + * executed properly by the backend, PGresult + * contains the result tuples */ + PGRES_COPY_OUT, /* Copy Out data transfer in progress */ + PGRES_COPY_IN, /* Copy In data transfer in progress */ + PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the + * backend */ + PGRES_NONFATAL_ERROR, /* notice or warning message */ + PGRES_FATAL_ERROR, /* query failed */ + PGRES_COPY_BOTH, /* Copy In/Out data transfer in progress */ + PGRES_SINGLE_TUPLE /* single tuple from larger resultset */ +} ExecStatusType; + +typedef enum +{ + CONNECTION_OK, + CONNECTION_BAD, + /* Non-blocking mode only below here */ + + /* + * The existence of these should never be relied upon - they should only + * be used for user feedback or similar purposes. + */ + CONNECTION_STARTED, /* Waiting for connection to be made. */ + CONNECTION_MADE, /* Connection OK; waiting to send. */ + CONNECTION_AWAITING_RESPONSE, /* Waiting for a response from the + * postmaster. */ + CONNECTION_AUTH_OK, /* Received authentication; waiting for + * backend startup. */ + CONNECTION_SETENV, /* Negotiating environment. */ + CONNECTION_SSL_STARTUP, /* Negotiating SSL. */ + CONNECTION_NEEDED /* Internal state: connect() needed */ +} ConnStatusType; + +PGconn *PQconnectStart(const char *conninfo); + +//Returns the status of the connection. +ConnStatusType PQstatus(const PGconn *conn); + +PostgresPollingStatusType PQconnectPoll(PGconn *conn); + +int PQsetnonblocking(PGconn *conn, int arg); + +int PQsendQuery(PGconn *conn, const char *command); + +char *PQerrorMessage(const PGconn *conn); + +int PQconsumeInput(PGconn *conn); + +int PQisBusy(PGconn *conn); + +PGresult *PQgetResult(PGconn *conn); + +ExecStatusType PQresultStatus(const PGresult *res); + +//Returns the number of rows (tuples) in the query result. +int PQntuples(const PGresult *res); + +//Returns the number of columns (fields) in each row of the query result. +int PQnfields(const PGresult *res); + +//Returns the column name associated with the given column number. Column numbers start at 0. +//The caller should not free the result directly. +//It will be freed when the associated PGresult handle is passed to PQclear. +char *PQfname(const PGresult *res, int column_number); + +//Returns a single field value of one row of a PGresult. +//Row and column numbers start at 0. The caller should not +//free the result directly. It will be freed when the associated +//PGresult handle is passed to PQclear. +char *PQgetvalue(const PGresult *res, int row_number, int column_number); + +//Tests a field for a null value. Row and column numbers start at 0. +int PQgetisnull(const PGresult *res, int row_number, int column_number); + +//Returns the actual length of a field value in bytes. Row and column numbers start at 0. +int PQgetlength(const PGresult *res, int row_number, int column_number); + +//Returns the actual length of a field value in bytes. Row and column numbers start at 0. +int PQgetlength(const PGresult *res, int row_number, int column_number); + +//PQescapeLiteral escapes a string for use within an SQL command. +//This memory should be freed using PQfreemem() when the result is no longer needed. +char *PQescapeLiteral(PGconn *conn, const char *str, size_t length); + +void PQfreemem(void *ptr); + +//Frees the storage associated with a PGresult. +void PQclear(PGresult *res); + +//Closes the connection to the server. Also frees memory used by the PGconn object. +void PQfinish(PGconn *conn); + +//returns the filedescriptor for this connection +int PQsocket(PGconn *conn); +]] + + +--[[Loads the shared library of postgres + libpath is the path to the library (ie. the .so or .dll) of postgres + defaults to "/usr/lib/libpq.so.5" if omitted +]] + + +function PSqlConnection.init(libpath) + libpq = ffi.load(libpath or "/usr/lib/libpq.so.5", true) +end + + +--[[Creates a new connection to a Postgres SQL in + async mode. The string conninfo is passed to + PQconnectStart. +]] +function PSqlConnection.newAsync(conninfo) + local new_inst = {} + setmetatable( new_inst, PSqlConnection_mt ) + assert(conninfo) + new_inst.PGconn = ffi.gc(libpq.PQconnectStart(conninfo), libpq.PQfinish) + return new_inst +end + + +--[[Returns the dialUpState +]] +function PSqlConnection:dialUpState() + assert(libpq.PQconnectPoll(self.PGconn) ~= "PGRES_POLLING_FAILED", self:getError()) + return libpq.PQstatus(self.PGconn) +end + + +--[[Returns the last errormessage +]] +function PSqlConnection:getError() + return ffi.string(libpq.PQerrorMessage(self.PGconn)) +end + + +--[[Sends a query to the server + All old data has to be collecet befor an new + query can be send (getAvailable returns nil) + + Node: Multiple querys in one will be treated as one transaction. + read PostgreSQL doc 31.3.1 +]] +function PSqlConnection:sendQuery(query) + assert(not self.queryInProcess, "Error: Old query isn't finished") + local ret = libpq.PQsendQuery(self.PGconn, query) + if ret == 0 then + error(self:getError()) + end + self.queryInProcess = true +end + + +--[[Returns true if getAvailable can be called without + blocking +]] +function PSqlConnection:readReady() + local ret = libpq.PQconsumeInput(self.PGconn) + if ret == 0 then + error(self:getError()) + end + return libpq.PQisBusy(self.PGconn) == 0 +end + + +--[[Returns a tables of all avilable data or nil if no more data is availible + The table is structured with the column names in row 0 and the data afterwards + ie. [1][1] is the first row in the first column and [0][1] is the name of that column + | 1 | 2 | ... +------------------------------------------- + 0 | column name 1 | column name 2 | ... +-------------------------------------------- + 1 | data column 1 | data ...... +]] +function PSqlConnection:getAvailable() + local result = libpq.PQgetResult(self.PGconn) + if result ~= nil then + local status = libpq.PQresultStatus(result) + local rows = libpq.PQntuples(result) + local columns = libpq.PQnfields(result) + + local tab = {} + tab[0] = {} + + for j = 1, columns do + tab[0][j] = ffi.string(libpq.PQfname(result, j-1)) + end + + for i = 1, rows do + tab[i] = {} + + for j = 1, columns do + local value = nil + if 0 == libpq.PQgetisnull(result, i-1, j-1) then + value = ffi.string( + libpq.PQgetvalue(result, i-1, j-1), + libpq.PQgetlength(result, i-1, j-1) + ) + end + + tab[i][j] = value + end + end + + libpq.PQclear(result) + + return tab, status + else + self.queryInProcess = nil + return nil + end +end + +--[[Returns the socketdescriptor +]] +function PSqlConnection:getSocket() + return libpq.PQsocket(self.PGconn) +end + + +--[[Returns a escaped version of the string than can be savely + used in a query without danger of SQL injection +]] +function PSqlConnection:escape(data) + local strData = tostring(data) + local result = libpq.PQescapeLiteral(self.PGconn, strData, #strData) + if result ~= nil then + local strResult = ffi.string(result) + libpq.PQfreemem(result) + return strResult + else + error(self:getError()) + end +end + +return PSqlConnection diff --git a/modules/pginfo.lua b/modules/pginfo.lua new file mode 100644 index 0000000..872ce39 --- /dev/null +++ b/modules/pginfo.lua @@ -0,0 +1,92 @@ +i-------------------------------------------------------------------------- +-- Module to extract Postgres Process Information for Boundary Lua Postgres Plugin +-- +-- Author: Yegor Dia +-- Email: yegordia at gmail.com +-- +-------------------------------------------------------------------------- + +local object = require('core').Object +local ffi = require("ffi") + +--[[ Check os for binding library path +]] +if ffi.os == "Windows" then + _G.POSTGRESQL_LIBRARY_PATH = ".\\windows-bindings\\lib\\x64\\pq" +end +postgresLuvit = require('luvit-postgres/postgresLuvit') + + +local function callIfNotNil(callback, ...) + if callback ~= nil then + callback(...) + end +end + +local PgInfo = object:extend() + +--[[ Initialize PgInfo with connection parameters +]] +function PgInfo:initialize(host, port, user, pwd, database, source) + self.connection_string = string.format("host=%s port=%s dbname=%s user=%s password=%s", host, port, database, user, pwd) + p(string.format("connection string: %s", self.connection_string)) + return self +end + +--[[ Establishing method required to be used before every query +]] +function PgInfo:establish(queries_callback) + self.con = postgresLuvit:new(self.connection_string, function(err) + assert(not err, err) + callIfNotNil(queries_callback, self.con) + end) +end + +--[[ Test function +]] +function PgInfo:test() + self:establish(function(connection) + + connection:sendQuery("DROP TABLE IF EXISTS test",function(err, res) + assert(not err, err) + + connection:sendQuery("CREATE TABLE test (id bigserial primary key, content text, addedAt timestamp)",function(err, res) + assert(not err, err) + + connection:sendQuery("INSERT INTO test (content, addedAt) VALUES (" .. + connection:escape([["); DROP TABLE test; --]]) .. + ", now() )",function(err, res) + assert(not err, err) + + connection:sendQuery("SELECT * FROM test",function(err, res) + assert(not err, err) + p(res) + end) + end) + end) + end) + + end) +end + +--[[ Get list of databases +]] +function PgInfo:get_databases() + self:establish(function(connection) + + connection:sendQuery("SELECT datname FROM pg_database;",function(err, res) + assert(not err, err) + local dbs = {} + for i, name in ipairs(res) do + if name ~= "datname" then + table.insert(dbs, name) + end + end + + return dbs + end) + + end) +end + +return PgInfo diff --git a/param.json b/param.json new file mode 100644 index 0000000..1cab3fc --- /dev/null +++ b/param.json @@ -0,0 +1,8 @@ +{ + "host":"localhost", + "port":5432, + "user":"postgres", + "pwd":"123qwe", + "database":"postgres", + "source":"" +} diff --git a/plugin.json b/plugin.json index 61a72c3..689b667 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,9 @@ { "description" : "Awaiting Certification - Collects statistics from PostgreSQL Database", "command" : "python postgres_plugin.py $(host) $(port) $(database) $(username) $(password) $(source)", + “postExtract” : “”, + "command_lua" : "boundary-meter index.lua $(host) $(port) $(database) $(username) $(password) $(source)", + “postExtract_lua” : “”, "icon" : "icon.png", "metrics" : [ "POSTGRESQL_EXCLUSIVE_LOCKS", From 44e14123035f6ae200acefa77e96be138f29f87a Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Mon, 16 Feb 2015 19:00:43 -0600 Subject: [PATCH 02/16] Forgot to add Windows Bindings --- windows-bindings/lib/x64/pq.dll | Bin 0 -> 124928 bytes windows-bindings/lib/x86/pq.dll | Bin 0 -> 100352 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 windows-bindings/lib/x64/pq.dll create mode 100644 windows-bindings/lib/x86/pq.dll diff --git a/windows-bindings/lib/x64/pq.dll b/windows-bindings/lib/x64/pq.dll new file mode 100644 index 0000000000000000000000000000000000000000..311c7c76b42827bb722bf9f63af5595e5a8a15a9 GIT binary patch literal 124928 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 literal 0 HcmV?d00001 diff --git a/windows-bindings/lib/x86/pq.dll b/windows-bindings/lib/x86/pq.dll new file mode 100644 index 0000000000000000000000000000000000000000..7d665e74fed49a95a6c46d2d4d57d2e3a62f8795 GIT binary patch literal 100352 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 R@G}K|rohh>_ Date: Mon, 16 Feb 2015 19:02:07 -0600 Subject: [PATCH 03/16] Fixed README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f2eef05..06d041f 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,13 @@ Extracts metrics from a PostgreSQL database instance. | Supported | v | v | v | v | For Boundary Meter V4.0 (to update/download - curl -fsS -d '{"token":"api."}' -H 'Content-Type: application/json' https://meter.boundary.com/setup_meter > setup_meter.sh && chmod +x setup_meter.sh && ./setup_meter.sh) + | Runtime | node.js | Python | Java | |:---------|:-------:|:------:|:----:| | Required | | | | For Boundary Meter less than V4.0 + | Runtime | node.js | Python | Java | |:---------|:-------:|:------:|:----:| | Required | | + | | From 152d621709cbc33076bbaf67b7c885cd79d36bec Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Mon, 16 Feb 2015 19:05:09 -0600 Subject: [PATCH 04/16] README Updated further --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06d041f..8394cd2 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,14 @@ Extracts metrics from a PostgreSQL database instance. |:----------|:-----:|:-------:|:-------:|:----:| | Supported | v | v | v | v | -For Boundary Meter V4.0 (to update/download - curl -fsS -d '{"token":"api."}' -H 'Content-Type: application/json' https://meter.boundary.com/setup_meter > setup_meter.sh && chmod +x setup_meter.sh && ./setup_meter.sh) +#### For Boundary Meter V4.0 +(to update/download - curl -fsS -d '{"token":"api."}' -H 'Content-Type: application/json' https://meter.boundary.com/setup_meter > setup_meter.sh && chmod +x setup_meter.sh && ./setup_meter.sh) | Runtime | node.js | Python | Java | |:---------|:-------:|:------:|:----:| | Required | | | | -For Boundary Meter less than V4.0 +#### For Boundary Meter less than V4.0 | Runtime | node.js | Python | Java | |:---------|:-------:|:------:|:----:| @@ -27,6 +28,7 @@ For Boundary Meter less than V4.0 ### Plugin Setup +#### For Boundary Meter Versions Less than V4.0 #### Installation of the PsycoPG2 Library Using `pip` 1. Install [pip](http://pip.readthedocs.org/en/latest/installing.html) if not already installed @@ -42,6 +44,9 @@ For Boundary Meter less than V4.0 ``` ### Plugin Configuration Fields + +#### For All Versions + |Field Name|Description | |:-------|:-------------------------------------------------| |host |database host name or IP | @@ -53,6 +58,8 @@ For Boundary Meter less than V4.0 ### Metrics Collected +#### For All Versions + |Metric Name |Description | |:----------------------------------------------|:----------------------------------------------| |PostgreSQL - Locks Exclusive |PostgreSQL - Locks Exclusive | From b64b235cacec2e637c2b90639ac4587f9d3c1cd4 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Mon, 16 Feb 2015 20:55:06 -0600 Subject: [PATCH 05/16] Removed unnecessary boundary.lua file --- modules/boundary.lua | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 modules/boundary.lua diff --git a/modules/boundary.lua b/modules/boundary.lua deleted file mode 100644 index e1bcb43..0000000 --- a/modules/boundary.lua +++ /dev/null @@ -1,15 +0,0 @@ --- Copyright 2015 Boundary --- @brief convenience variables and functions for Lua scripts --- @file boundary.lua -local fs = require('fs') -local json = require('json') - -local boundary = {param = nil} - --- import param.json data into a Lua table (boundary.param) -local json_blob -if (pcall(function () json_blob = fs.readFileSync("param.json") end)) then - pcall(function () boundary.param = json.parse(json_blob) end) -end - -return boundary From cf887c62fa4d53afae038b4345534d1c9bc837e3 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Wed, 18 Feb 2015 09:03:59 -0600 Subject: [PATCH 06/16] Updated to Use new init.la entry point Also to have new code and updates to the modules. --- index.lua | 25 ---- init.lua | 75 ++++++++++ modules/luvit-postgres/postgresLuvit.lua | 2 +- modules/luvit-postgres/postgresffi.lua | 2 +- modules/pginfo.lua | 166 ++++++++++++++++++++--- plugin.json | 16 ++- 6 files changed, 233 insertions(+), 53 deletions(-) delete mode 100644 index.lua create mode 100644 init.lua diff --git a/index.lua b/index.lua deleted file mode 100644 index 22170d9..0000000 --- a/index.lua +++ /dev/null @@ -1,25 +0,0 @@ -local boundary = require('boundary') -local pginfo = require('pginfo') - --- Default params -local host = "localhost" -local port = 5432 -local user = "postgres" -local pwd = "" -local database = "postgres" -local source = "" - --- Fetching params -if (boundary.param ~= nil) then - host = boundary.param['host'] or host - port = boundary.param['port'] or port - user = boundary.param['user'] or user - pwd = boundary.param['pwd'] or pwd - database = boundary.param['database'] or database - source = boundary.param['source'] or source -end - -print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") - -local dbcon = pginfo:new(host, port, user, pwd, database, source) -print(dbcon:get_databases()) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..07b967f --- /dev/null +++ b/init.lua @@ -0,0 +1,75 @@ +local boundary = require('boundary') +local pginfo = require('pginfo') + +-- Default params +local host = "localhost" +local port = 5432 +local user = "postgres" +local pwd = "" +local database = "postgres" +local source = "" + +-- Fetching params +if (boundary.param ~= nil) then + host = boundary.param['host'] or host + port = boundary.param['port'] or port + user = boundary.param['user'] or user + pwd = boundary.param['pwd'] or pwd + database = boundary.param['database'] or database + source = boundary.param['source'] or source +end + +print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") + +local dbcon = pginfo:new(host, port, user, pwd, database, source) + + +local function poll() + dbcon:establish(function(connection) + dbcon:get_databases(connection, function(dbs) + dbcon:get_bg_writer_stats(connection, function(writer_stats) + dbcon:get_lock_stats_mode(connection, function(db_locks) + dbcon:get_database_stats(connection, function(db_stats) + + --lock stats + p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) + p(string.format("POSTGRESQL_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['RowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareRowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_UPDATE_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareUpdateExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_LOCKS %s %s", db_locks['all']['Share'], source)) + p(string.format("POSTGRESQL_ACCESS_SHARE_LOCKS %s %s", db_locks['all']['AccessShare'], source)) + + --checkpoint/bgwriter stats + p(string.format("POSTGRESQL_CHECKPOINT_WRITE_TIME %s %s", writer_stats['checkpoint_write_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_TIMED %s %s", writer_stats['checkpoints_timed'], source)) + p(string.format("POSTGRESQL_BUFFERS_ALLOCATED %s %s", writer_stats['buffers_alloc'], source)) + p(string.format("POSTGRESQL_BUFFERS_CLEAN %s %s", writer_stats['buffers_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND_FSYNC %s %s", writer_stats['buffers_backend_fsync'], source)) + p(string.format("POSTGRESQL_CHECKPOINT_SYNCHRONIZATION_TIME %s %s", writer_stats['checkpoint_sync_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_REQUESTED %s %s", writer_stats['checkpoints_req'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND %s %s", writer_stats['buffers_backend'], source)) + p(string.format("POSTGRESQL_MAXIMUM_WRITTEN_CLEAN %s %s", writer_stats['maxwritten_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_CHECKPOINT %s %s", writer_stats['buffers_checkpoint'], source)) + + --Global DB Stats + p(string.format("POSTGRESQL_BLOCKS_READ %s %s", db_stats['totals']['blks_read'], source)) + p(string.format("POSTGRESQL_DISK_SIZE %s %s", db_stats['totals']['disk_size'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_COMMITTED %s %s", db_stats['totals']['xact_commit'], source)) + p(string.format("POSTGRESQL_TUPLES_DELETED %s %s", db_stats['totals']['tup_deleted'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_ROLLEDBACK %s %s", db_stats['totals']['xact_rollback'], source)) + p(string.format("POSTGRESQL_BLOCKS_HIT %s %s", db_stats['totals']['blks_hit'], source)) + p(string.format("POSTGRESQL_TUPLES_RETURNED %s %s", db_stats['totals']['tup_returned'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + p(string.format("POSTGRESQL_TUPLES_UPDATED %s %s", db_stats['totals']['tup_updated'], source)) + p(string.format("POSTGRESQL_TUPLES_INSERTED %s %s", db_stats['totals']['tup_inserted'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + + end) + end) + end) + end) + end) +end + +poll() + diff --git a/modules/luvit-postgres/postgresLuvit.lua b/modules/luvit-postgres/postgresLuvit.lua index 378f82d..56fcf68 100644 --- a/modules/luvit-postgres/postgresLuvit.lua +++ b/modules/luvit-postgres/postgresLuvit.lua @@ -191,4 +191,4 @@ end -return LuvPostgres +return LuvPostgres \ No newline at end of file diff --git a/modules/luvit-postgres/postgresffi.lua b/modules/luvit-postgres/postgresffi.lua index 9972660..613a30d 100644 --- a/modules/luvit-postgres/postgresffi.lua +++ b/modules/luvit-postgres/postgresffi.lua @@ -285,4 +285,4 @@ function PSqlConnection:escape(data) end end -return PSqlConnection +return PSqlConnection \ No newline at end of file diff --git a/modules/pginfo.lua b/modules/pginfo.lua index 872ce39..d70c1b7 100644 --- a/modules/pginfo.lua +++ b/modules/pginfo.lua @@ -1,4 +1,4 @@ -i-------------------------------------------------------------------------- +-------------------------------------------------------------------------- -- Module to extract Postgres Process Information for Boundary Lua Postgres Plugin -- -- Author: Yegor Dia @@ -23,30 +23,68 @@ local function callIfNotNil(callback, ...) end end +local function createDictWithKeys(keys, default_val) + local dict = {} + local default = nil + + if default_val ~= nil then + default = default_val + end + + for i, name in ipairs(keys) do + dict[name] = default + end + return dict +end + +local function createDictWithKeysAndValues(keys, values) + local dict = {} + + for i, name in ipairs(keys) do + dict[name] = values[i] + end + return dict +end + +local function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + local PgInfo = object:extend() --[[ Initialize PgInfo with connection parameters ]] function PgInfo:initialize(host, port, user, pwd, database, source) self.connection_string = string.format("host=%s port=%s dbname=%s user=%s password=%s", host, port, database, user, pwd) - p(string.format("connection string: %s", self.connection_string)) + --p(string.format("connection string: %s", self.connection_string)) + self.lock_modes = {'AccessExclusive', 'Exclusive', 'ShareRowExclusive', 'Share', 'ShareUpdateExclusive', 'RowExclusive', 'RowShare', 'AccessShare'} + self.connection = nil return self end --[[ Establishing method required to be used before every query ]] function PgInfo:establish(queries_callback) - self.con = postgresLuvit:new(self.connection_string, function(err) + self.connection = postgresLuvit:new(self.connection_string, function(err) assert(not err, err) - callIfNotNil(queries_callback, self.con) + callIfNotNil(queries_callback, self.connection) end) end --[[ Test function ]] -function PgInfo:test() - self:establish(function(connection) - +function PgInfo:test(connection, callback) connection:sendQuery("DROP TABLE IF EXISTS test",function(err, res) assert(not err, err) @@ -60,33 +98,123 @@ function PgInfo:test() connection:sendQuery("SELECT * FROM test",function(err, res) assert(not err, err) - p(res) + callIfNotNil(callback) end) end) end) end) - - end) end --[[ Get list of databases ]] -function PgInfo:get_databases() - self:establish(function(connection) - +function PgInfo:get_databases(connection, callback) connection:sendQuery("SELECT datname FROM pg_database;",function(err, res) assert(not err, err) - local dbs = {} - for i, name in ipairs(res) do - if name ~= "datname" then - table.insert(dbs, name) + local dbs = res + + callIfNotNil(callback, dbs) + end) +end + + +--[[ Returns the number of active lock discriminated by lock mode +]] +function PgInfo:get_lock_stats_mode(connection, callback) + connection:sendQuery("SELECT TRIM(mode, 'Lock'), granted, COUNT(*) FROM pg_locks " .. "GROUP BY TRIM(mode, 'Lock'), granted;", function(err, res) + assert(not err, err) + info_dict = { wait = createDictWithKeys(self.lock_modes, 0), all = createDictWithKeys(self.lock_modes, 0)} + + for i, value in ipairs(res) do + local mode = value[1] + local granted = value[2] == "t" + local count = value[3] + + info_dict['all'][mode] = info_dict['all'][mode] + count + if not granted then + info_dict['wait'][mode] = info_dict['wait'][mode] + count end end + + callIfNotNil(callback, info_dict) + end) +end + + +--[[ Global Background Writer and Checkpoint Activity stats +]] +function PgInfo:get_bg_writer_stats(connection, callback) + connection:sendQuery("SELECT * FROM pg_stat_bgwriter;", function(err, res) + assert(not err, err) + info_dict = {} + + for i=1, table.getn(res[0]) do + local name = res[0][i] + local result = res[1][i] + info_dict[name] = result + end - return dbs + callIfNotNil(callback, info_dict) end) +end + +--[[ Returns database block read, transaction and tuple stats for each + database +]] +function PgInfo:get_database_stats(connection, callback) + local headers = {'datname', 'numbackends', 'xact_commit', 'xact_rollback', + 'blks_read', 'blks_hit', 'tup_returned', 'tup_fetched', + 'tup_inserted', 'tup_updated', 'tup_deleted', 'disk_size'} + local query_headers = deepcopy(headers) + table.remove(query_headers, table.getn(query_headers)) + + local query_string = string.format("SELECT %s, pg_database_size(datname) FROM pg_stat_database;", table.concat(query_headers, ", ")) + connection:sendQuery(query_string, function(err, res) + assert(not err, err) + info_dict = {} + info_dict['databases'] = self:create_stats_dict(headers, res) + info_dict['totals'] = self:create_totals_dict(headers, res) + callIfNotNil(callback, info_dict) end) end -return PgInfo + +--[[ Utility method that returns database stats as a nested dictionary +]] +function PgInfo:create_stats_dict(headers, rows) + local db_stats = {} + table.remove(headers, 1) + for index, row in ipairs(rows) do + local key = row[1] + table.remove(row, 1) + local stats = createDictWithKeysAndValues(headers, row) + db_stats[key] = stats + end + return db_stats +end + + +--[[ Utility method that returns totals for database statistics +]] +function PgInfo:create_totals_dict(headers, rows) + local totals_dict = {} + local totals = {} + for key,row in ipairs(rows) do + local key = row[1] + + for i=1, table.getn(row) do + if totals[i] ~= nil then + totals[i] = totals[i] + row[i] + else + totals[i] = row[i] + end + end + end + + for index, header in ipairs(headers) do + totals_dict[header] = totals[index] + end + return totals_dict +end + +return PgInfo \ No newline at end of file diff --git a/plugin.json b/plugin.json index 689b667..d8f95b9 100644 --- a/plugin.json +++ b/plugin.json @@ -1,11 +1,12 @@ { - "description" : "Awaiting Certification - Collects statistics from PostgreSQL Database", - "command" : "python postgres_plugin.py $(host) $(port) $(database) $(username) $(password) $(source)", - “postExtract” : “”, - "command_lua" : "boundary-meter index.lua $(host) $(port) $(database) $(username) $(password) $(source)", - “postExtract_lua” : “”, - "icon" : "icon.png", - "metrics" : [ + "description" : "Awaiting Certification - Collects statistics from PostgreSQL Database", + "icon" : "icon.png", + "command" : "python postgres_plugin.py $(host) $(port) $(database) $(username) $(password) $(source)", + “command_lua” : “boundary-meter init.lua”, + “postExtract_lua” : “”, + "ignore" : "node_modules", + + "metrics" : [ "POSTGRESQL_EXCLUSIVE_LOCKS", "POSTGRESQL_ROW_EXCLUSIVE_LOCKS", "POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS", @@ -33,6 +34,7 @@ "POSTGRESQL_TUPLES_RETURNED", "POSTGRESQL_TUPLES_UPDATED" ], + "dashboards": [ { "name":"PostgreSQL Lock Stats", "layout": "d-w=3&d-h=2&d-pad=5&d-bg=none&d-g-POSTGRESQL_EXCLUSIVE_LOCKS=0-0-1-1&d-g-POSTGRESQL_ROW_EXCLUSIVE_LOCKS=0-1-1-1&d-g-POSTGRESQL_SHARE_ROW_EXCLUSIVE=1-1-1-1&d-g-POSTGRESQL_SHARE_UPDATE_EXCLUSIVE=2-1-1-1&d-g-POSTGRESQL_SHARE_LOCKS=2-0-1-1&d-g-POSTGRESQL_ACCESS_SHARE_LOCKS=1-0-1-1" }, { "name":"PostgreSQL Reader Stats", "layout": "d-w=3&d-h=3&d-pad=5&d-bg=none&d-g-POSTGRESQL_CHECKPOINT_WRITE_TIME=0-0-1-1&d-g-POSTGRESQL_CHECKPOINTS_TIMED=0-1-1-1&d-g-POSTGRESQL_BUFFERS_ALLOCATED=0-2-1-1&d-g-POSTGRESQL_BUFFERS_CLEAN=1-0-1-1&d-g-POSTGRESQL_BUFFERS_BACKEND_FSYNC=1-1-1-1&d-g-POSTGRESQL_BUFFERS_BACKEND=1-2-1-1&d-g-POSTGRESQL_CHECKPOINTS_REQUESTED=2-2-1-1&d-g-POSTGRESQL_CHECKPOINT_SYNC_TIME=2-1-1-1&d-g-POSTGRESQL_BUFFERS_CHECKPOINT=2-0-1-1" }, From 923d1af16bf4ded7e8f2ac36a895d6d6d801c07a Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Thu, 5 Mar 2015 09:47:55 -0600 Subject: [PATCH 07/16] Made fixes to python script --- plugin.json | 2 +- postgres_plugin.py | 34 ++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/plugin.json b/plugin.json index d8f95b9..00b2cd9 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "description" : "Awaiting Certification - Collects statistics from PostgreSQL Database", "icon" : "icon.png", - "command" : "python postgres_plugin.py $(host) $(port) $(database) $(username) $(password) $(source)", + "command" : "python postgres_plugin.py", “command_lua” : “boundary-meter init.lua”, “postExtract_lua” : “”, "ignore" : "node_modules", diff --git a/postgres_plugin.py b/postgres_plugin.py index a5a3493..6823db5 100755 --- a/postgres_plugin.py +++ b/postgres_plugin.py @@ -3,18 +3,24 @@ import json from postgresql import PgInfo from os import path +import time -if (len(sys.argv) != 7): - sys.stderr.write("usage: {0} host port database user password source\n".format(path.basename(sys.argv[0]))) - sys.exit(1) +#get params from file +paramFile="param.json" -#grab connection info's. This is expected in the Format host/port/db/user/pwd -_host = sys.argv[1] -_port = sys.argv[2] -_database = sys.argv[3] -_user = sys.argv[4] -_password = sys.argv[5] -_source = sys.argv[6] +if path.isfile(paramFile): + with open(paramFile) as data_file: + params = json.load(data_file) + _host = params["host"] + _port = params["port"] + _database = params["database"] + _user = params["username"] + _password = params["password"] + _source = params["source"] + +else: + sys.stderr.write("Either params file is missing or is not readable") + sys.exit(1) def poll(): _dbconn = PgInfo(_host, _port, _database, _user, _password) @@ -61,9 +67,9 @@ def poll(): print("POSTGRESQL_TUPLES_FETCHED {0} {1}".format(dbStats['totals']['tup_fetched'], _source)) print("POSTGRESQL_TUPLES_UPDATED {0} {1}".format(dbStats['totals']['tup_updated'], _source)) print("POSTGRESQL_TUPLES_INSERTED {0} {1}".format(dbStats['totals']['tup_inserted'], _source)) - print("POSTGRESQL_TUPLES_FETCHED {0} {1}".format(dbStats['totals']['tup_fetched'], _source)) -poll() - - + sys.stdout.flush() +while True: + poll() + time.sleep(1) From 917d54af775d5eb4a215f5a7bc9408eb0981e1b4 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Mon, 9 Mar 2015 13:11:56 -0500 Subject: [PATCH 08/16] Fixed strange quotes in json --- plugin.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin.json b/plugin.json index 00b2cd9..1655d83 100644 --- a/plugin.json +++ b/plugin.json @@ -2,8 +2,8 @@ "description" : "Awaiting Certification - Collects statistics from PostgreSQL Database", "icon" : "icon.png", "command" : "python postgres_plugin.py", - “command_lua” : “boundary-meter init.lua”, - “postExtract_lua” : “”, + "command_lua" : "boundary-meter init.lua", + "postExtract_lua" : "", "ignore" : "node_modules", "metrics" : [ From d1f4c9451ae06861c878c3443d007b9d5752468a Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 09:17:52 -0500 Subject: [PATCH 09/16] Updated init.la, moved livid posters modules to the modules directory --- README.md | 14 +- init.lua | 122 ++++++++++-------- modules/pginfo.lua | 4 +- .../{luvit-postgres => }/postgresLuvit.lua | 0 modules/{luvit-postgres => }/postgresffi.lua | 0 5 files changed, 77 insertions(+), 63 deletions(-) rename modules/{luvit-postgres => }/postgresLuvit.lua (100%) rename modules/{luvit-postgres => }/postgresffi.lua (100%) diff --git a/README.md b/README.md index 8394cd2..acfca73 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,16 @@ Extracts metrics from a PostgreSQL database instance. |:----------|:-----:|:-------:|:-------:|:----:| | Supported | v | v | v | v | -#### For Boundary Meter V4.0 -(to update/download - curl -fsS -d '{"token":"api."}' -H 'Content-Type: application/json' https://meter.boundary.com/setup_meter > setup_meter.sh && chmod +x setup_meter.sh && ./setup_meter.sh) +#### Boundary Meter Versions V4.0 Or Greater -| Runtime | node.js | Python | Java | -|:---------|:-------:|:------:|:----:| -| Required | | | | +To get the new meter: + + curl -fsS \ + -d "{\"token\":\"\"}" \ + -H "Content-Type: application/json" \ + "https://meter.boundary.com/setup_meter" > setup_meter.sh + chmod +x setup_meter.sh + ./setup_meter.sh #### For Boundary Meter less than V4.0 diff --git a/init.lua b/init.lua index 07b967f..e0ef2c0 100644 --- a/init.lua +++ b/init.lua @@ -1,75 +1,85 @@ local boundary = require('boundary') local pginfo = require('pginfo') +local table = require('table') +local string = require('string') -- Default params -local host = "localhost" -local port = 5432 -local user = "postgres" -local pwd = "" -local database = "postgres" -local source = "" +local connections = { +[0] = { + host = "localhost", + port = 5432, + user = "postgres", + password = "123qwe", + database = "postgres", + source = "" +}} -- Fetching params if (boundary.param ~= nil) then - host = boundary.param['host'] or host - port = boundary.param['port'] or port - user = boundary.param['user'] or user - pwd = boundary.param['pwd'] or pwd - database = boundary.param['database'] or database - source = boundary.param['source'] or source + connections = boundary.param or connections end print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") +local dbcon = nil -local dbcon = pginfo:new(host, port, user, pwd, database, source) +local function poll(connections) + if table.getn(connections) > 0 then + local query = connections[1] + local host = query.host + local port = query.port + local user = query.user + local password = query.password + local database = query.database + local source = query.source + table.remove(connections, 1) + local dbcon = pginfo:new(host, port, user, password, database, source) + dbcon:establish(function(connection) + dbcon:get_databases(connection, function(dbs) + dbcon:get_bg_writer_stats(connection, function(writer_stats) + dbcon:get_lock_stats_mode(connection, function(db_locks) + dbcon:get_database_stats(connection, function(db_stats) + + --lock stats + p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) + p(string.format("POSTGRESQL_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['RowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareRowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_UPDATE_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareUpdateExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_LOCKS %s %s", db_locks['all']['Share'], source)) + p(string.format("POSTGRESQL_ACCESS_SHARE_LOCKS %s %s", db_locks['all']['AccessShare'], source)) + + --checkpoint/bgwriter stats + p(string.format("POSTGRESQL_CHECKPOINT_WRITE_TIME %s %s", writer_stats['checkpoint_write_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_TIMED %s %s", writer_stats['checkpoints_timed'], source)) + p(string.format("POSTGRESQL_BUFFERS_ALLOCATED %s %s", writer_stats['buffers_alloc'], source)) + p(string.format("POSTGRESQL_BUFFERS_CLEAN %s %s", writer_stats['buffers_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND_FSYNC %s %s", writer_stats['buffers_backend_fsync'], source)) + p(string.format("POSTGRESQL_CHECKPOINT_SYNCHRONIZATION_TIME %s %s", writer_stats['checkpoint_sync_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_REQUESTED %s %s", writer_stats['checkpoints_req'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND %s %s", writer_stats['buffers_backend'], source)) + p(string.format("POSTGRESQL_MAXIMUM_WRITTEN_CLEAN %s %s", writer_stats['maxwritten_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_CHECKPOINT %s %s", writer_stats['buffers_checkpoint'], source)) -local function poll() - dbcon:establish(function(connection) - dbcon:get_databases(connection, function(dbs) - dbcon:get_bg_writer_stats(connection, function(writer_stats) - dbcon:get_lock_stats_mode(connection, function(db_locks) - dbcon:get_database_stats(connection, function(db_stats) - - --lock stats - p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) - p(string.format("POSTGRESQL_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['RowExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareRowExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_UPDATE_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareUpdateExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_LOCKS %s %s", db_locks['all']['Share'], source)) - p(string.format("POSTGRESQL_ACCESS_SHARE_LOCKS %s %s", db_locks['all']['AccessShare'], source)) - - --checkpoint/bgwriter stats - p(string.format("POSTGRESQL_CHECKPOINT_WRITE_TIME %s %s", writer_stats['checkpoint_write_time'], source)) - p(string.format("POSTGRESQL_CHECKPOINTS_TIMED %s %s", writer_stats['checkpoints_timed'], source)) - p(string.format("POSTGRESQL_BUFFERS_ALLOCATED %s %s", writer_stats['buffers_alloc'], source)) - p(string.format("POSTGRESQL_BUFFERS_CLEAN %s %s", writer_stats['buffers_clean'], source)) - p(string.format("POSTGRESQL_BUFFERS_BACKEND_FSYNC %s %s", writer_stats['buffers_backend_fsync'], source)) - p(string.format("POSTGRESQL_CHECKPOINT_SYNCHRONIZATION_TIME %s %s", writer_stats['checkpoint_sync_time'], source)) - p(string.format("POSTGRESQL_CHECKPOINTS_REQUESTED %s %s", writer_stats['checkpoints_req'], source)) - p(string.format("POSTGRESQL_BUFFERS_BACKEND %s %s", writer_stats['buffers_backend'], source)) - p(string.format("POSTGRESQL_MAXIMUM_WRITTEN_CLEAN %s %s", writer_stats['maxwritten_clean'], source)) - p(string.format("POSTGRESQL_BUFFERS_CHECKPOINT %s %s", writer_stats['buffers_checkpoint'], source)) - - --Global DB Stats - p(string.format("POSTGRESQL_BLOCKS_READ %s %s", db_stats['totals']['blks_read'], source)) - p(string.format("POSTGRESQL_DISK_SIZE %s %s", db_stats['totals']['disk_size'], source)) - p(string.format("POSTGRESQL_TRANSACTIONS_COMMITTED %s %s", db_stats['totals']['xact_commit'], source)) - p(string.format("POSTGRESQL_TUPLES_DELETED %s %s", db_stats['totals']['tup_deleted'], source)) - p(string.format("POSTGRESQL_TRANSACTIONS_ROLLEDBACK %s %s", db_stats['totals']['xact_rollback'], source)) - p(string.format("POSTGRESQL_BLOCKS_HIT %s %s", db_stats['totals']['blks_hit'], source)) - p(string.format("POSTGRESQL_TUPLES_RETURNED %s %s", db_stats['totals']['tup_returned'], source)) - p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) - p(string.format("POSTGRESQL_TUPLES_UPDATED %s %s", db_stats['totals']['tup_updated'], source)) - p(string.format("POSTGRESQL_TUPLES_INSERTED %s %s", db_stats['totals']['tup_inserted'], source)) - p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) - + --Global DB Stats + p(string.format("POSTGRESQL_BLOCKS_READ %s %s", db_stats['totals']['blks_read'], source)) + p(string.format("POSTGRESQL_DISK_SIZE %s %s", db_stats['totals']['disk_size'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_COMMITTED %s %s", db_stats['totals']['xact_commit'], source)) + p(string.format("POSTGRESQL_TUPLES_DELETED %s %s", db_stats['totals']['tup_deleted'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_ROLLEDBACK %s %s", db_stats['totals']['xact_rollback'], source)) + p(string.format("POSTGRESQL_BLOCKS_HIT %s %s", db_stats['totals']['blks_hit'], source)) + p(string.format("POSTGRESQL_TUPLES_RETURNED %s %s", db_stats['totals']['tup_returned'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + p(string.format("POSTGRESQL_TUPLES_UPDATED %s %s", db_stats['totals']['tup_updated'], source)) + p(string.format("POSTGRESQL_TUPLES_INSERTED %s %s", db_stats['totals']['tup_inserted'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + + poll(connections) + end) end) end) end) end) - end) + end end -poll() - +poll(connections) diff --git a/modules/pginfo.lua b/modules/pginfo.lua index d70c1b7..5891e6f 100644 --- a/modules/pginfo.lua +++ b/modules/pginfo.lua @@ -14,7 +14,7 @@ local ffi = require("ffi") if ffi.os == "Windows" then _G.POSTGRESQL_LIBRARY_PATH = ".\\windows-bindings\\lib\\x64\\pq" end -postgresLuvit = require('luvit-postgres/postgresLuvit') +postgresLuvit = require('postgresLuvit') local function callIfNotNil(callback, ...) @@ -217,4 +217,4 @@ function PgInfo:create_totals_dict(headers, rows) return totals_dict end -return PgInfo \ No newline at end of file +return PgInfo diff --git a/modules/luvit-postgres/postgresLuvit.lua b/modules/postgresLuvit.lua similarity index 100% rename from modules/luvit-postgres/postgresLuvit.lua rename to modules/postgresLuvit.lua diff --git a/modules/luvit-postgres/postgresffi.lua b/modules/postgresffi.lua similarity index 100% rename from modules/luvit-postgres/postgresffi.lua rename to modules/postgresffi.lua From 3b3d91f6bf3235671430e45393e55ff9bd640e53 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 09:32:17 -0500 Subject: [PATCH 10/16] Removed bathing in postgresLuvit.lua --- modules/postgresLuvit.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/postgresLuvit.lua b/modules/postgresLuvit.lua index 56fcf68..1de1b8b 100644 --- a/modules/postgresLuvit.lua +++ b/modules/postgresLuvit.lua @@ -22,7 +22,7 @@ -- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- -local postgres = require("./postgresffi") +local postgres = require("postgresffi") local timer = require('timer') local object = require('core').Object local table = require("table") @@ -191,4 +191,4 @@ end -return LuvPostgres \ No newline at end of file +return LuvPostgres From 805dfda2628ae8ea7ed805b34f681985b1005df1 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 09:50:01 -0500 Subject: [PATCH 11/16] Make the connections be multiple in plugin.json --- plugin.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin.json b/plugin.json index 1655d83..cbf55a8 100644 --- a/plugin.json +++ b/plugin.json @@ -41,6 +41,8 @@ { "name":"PostgreSQL DB Stats", "layout": "d-w=3&d-h=4&d-pad=5&d-bg=none&d-g-POSTGRESQL_BUFFERS_CHECKPOINT=0-0-1-1&d-g-POSTGRESQL_BLOCKS_READ=1-0-1-1&d-g-POSTGRESQL_DISK_SIZE=2-0-1-1&d-g-POSTGRESQL_TRANSACTIONS_COMMITTED=0-1-1-1&d-g-POSTGRESQL_TUPLES_DELETED=1-1-1-1&d-g-POSTGRESQL_TRANSACTIONS_ROLLEDBACK=2-1-1-1&d-g-POSTGRESQL_BLOCKS_HIT=0-2-1-1&d-g-POSTGRESQL_TUPLES_RETURNED=1-2-1-1&d-g-POSTGRESQL_TUPLES_FETCHED=2-2-1-1&d-g-POSTGRESQL_TUPLES_UPDATED=0-3-1-1&d-g-POSTGRESQL_TUPLES_INSERTED=2-3-1-1" } ], + + "paramArray" : { "itemTitle" : ["source"], "schemaTitle" : "Host"}, "paramSchema" : [ { "title" : "host", From fe81644132479a1ed89733281329b40e78dba378 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 15:50:39 -0500 Subject: [PATCH 12/16] Changed init.lua to actually poll --- init.lua | 86 +++++++++++++++++++++++++++++------------------------ plugin.json | 2 +- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/init.lua b/init.lua index e0ef2c0..c96c459 100644 --- a/init.lua +++ b/init.lua @@ -2,6 +2,7 @@ local boundary = require('boundary') local pginfo = require('pginfo') local table = require('table') local string = require('string') +local timer = require('timer') -- Default params local connections = { @@ -12,6 +13,7 @@ local connections = { password = "123qwe", database = "postgres", source = "" + pollInterval = 5000 }} -- Fetching params @@ -31,55 +33,61 @@ local function poll(connections) local password = query.password local database = query.database local source = query.source + local pollInterval = query.pollInterval table.remove(connections, 1) local dbcon = pginfo:new(host, port, user, password, database, source) dbcon:establish(function(connection) dbcon:get_databases(connection, function(dbs) - dbcon:get_bg_writer_stats(connection, function(writer_stats) - dbcon:get_lock_stats_mode(connection, function(db_locks) - dbcon:get_database_stats(connection, function(db_stats) + getStats(connection, source) + timer.setInterval(pollInterval, getStats, connection, source) + poll(connections) + end) + end) + end +end + +local function getStats(connection, source) + dbcon:get_bg_writer_stats(connection, function(writer_stats) + dbcon:get_lock_stats_mode(connection, function(db_locks) + dbcon:get_database_stats(connection, function(db_stats) - --lock stats - p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) - p(string.format("POSTGRESQL_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['RowExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareRowExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_UPDATE_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareUpdateExclusive'], source)) - p(string.format("POSTGRESQL_SHARE_LOCKS %s %s", db_locks['all']['Share'], source)) - p(string.format("POSTGRESQL_ACCESS_SHARE_LOCKS %s %s", db_locks['all']['AccessShare'], source)) + --lock stats + p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) + p(string.format("POSTGRESQL_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['RowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_ROW_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareRowExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_UPDATE_EXCLUSIVE_LOCKS %s %s", db_locks['all']['ShareUpdateExclusive'], source)) + p(string.format("POSTGRESQL_SHARE_LOCKS %s %s", db_locks['all']['Share'], source)) + p(string.format("POSTGRESQL_ACCESS_SHARE_LOCKS %s %s", db_locks['all']['AccessShare'], source)) - --checkpoint/bgwriter stats - p(string.format("POSTGRESQL_CHECKPOINT_WRITE_TIME %s %s", writer_stats['checkpoint_write_time'], source)) - p(string.format("POSTGRESQL_CHECKPOINTS_TIMED %s %s", writer_stats['checkpoints_timed'], source)) - p(string.format("POSTGRESQL_BUFFERS_ALLOCATED %s %s", writer_stats['buffers_alloc'], source)) - p(string.format("POSTGRESQL_BUFFERS_CLEAN %s %s", writer_stats['buffers_clean'], source)) - p(string.format("POSTGRESQL_BUFFERS_BACKEND_FSYNC %s %s", writer_stats['buffers_backend_fsync'], source)) - p(string.format("POSTGRESQL_CHECKPOINT_SYNCHRONIZATION_TIME %s %s", writer_stats['checkpoint_sync_time'], source)) - p(string.format("POSTGRESQL_CHECKPOINTS_REQUESTED %s %s", writer_stats['checkpoints_req'], source)) - p(string.format("POSTGRESQL_BUFFERS_BACKEND %s %s", writer_stats['buffers_backend'], source)) - p(string.format("POSTGRESQL_MAXIMUM_WRITTEN_CLEAN %s %s", writer_stats['maxwritten_clean'], source)) - p(string.format("POSTGRESQL_BUFFERS_CHECKPOINT %s %s", writer_stats['buffers_checkpoint'], source)) + --checkpoint/bgwriter stats + p(string.format("POSTGRESQL_CHECKPOINT_WRITE_TIME %s %s", writer_stats['checkpoint_write_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_TIMED %s %s", writer_stats['checkpoints_timed'], source)) + p(string.format("POSTGRESQL_BUFFERS_ALLOCATED %s %s", writer_stats['buffers_alloc'], source)) + p(string.format("POSTGRESQL_BUFFERS_CLEAN %s %s", writer_stats['buffers_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND_FSYNC %s %s", writer_stats['buffers_backend_fsync'], source)) + p(string.format("POSTGRESQL_CHECKPOINT_SYNCHRONIZATION_TIME %s %s", writer_stats['checkpoint_sync_time'], source)) + p(string.format("POSTGRESQL_CHECKPOINTS_REQUESTED %s %s", writer_stats['checkpoints_req'], source)) + p(string.format("POSTGRESQL_BUFFERS_BACKEND %s %s", writer_stats['buffers_backend'], source)) + p(string.format("POSTGRESQL_MAXIMUM_WRITTEN_CLEAN %s %s", writer_stats['maxwritten_clean'], source)) + p(string.format("POSTGRESQL_BUFFERS_CHECKPOINT %s %s", writer_stats['buffers_checkpoint'], source)) - --Global DB Stats - p(string.format("POSTGRESQL_BLOCKS_READ %s %s", db_stats['totals']['blks_read'], source)) - p(string.format("POSTGRESQL_DISK_SIZE %s %s", db_stats['totals']['disk_size'], source)) - p(string.format("POSTGRESQL_TRANSACTIONS_COMMITTED %s %s", db_stats['totals']['xact_commit'], source)) - p(string.format("POSTGRESQL_TUPLES_DELETED %s %s", db_stats['totals']['tup_deleted'], source)) - p(string.format("POSTGRESQL_TRANSACTIONS_ROLLEDBACK %s %s", db_stats['totals']['xact_rollback'], source)) - p(string.format("POSTGRESQL_BLOCKS_HIT %s %s", db_stats['totals']['blks_hit'], source)) - p(string.format("POSTGRESQL_TUPLES_RETURNED %s %s", db_stats['totals']['tup_returned'], source)) - p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) - p(string.format("POSTGRESQL_TUPLES_UPDATED %s %s", db_stats['totals']['tup_updated'], source)) - p(string.format("POSTGRESQL_TUPLES_INSERTED %s %s", db_stats['totals']['tup_inserted'], source)) - p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) - - poll(connections) - end) - end) - end) + --Global DB Stats + p(string.format("POSTGRESQL_BLOCKS_READ %s %s", db_stats['totals']['blks_read'], source)) + p(string.format("POSTGRESQL_DISK_SIZE %s %s", db_stats['totals']['disk_size'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_COMMITTED %s %s", db_stats['totals']['xact_commit'], source)) + p(string.format("POSTGRESQL_TUPLES_DELETED %s %s", db_stats['totals']['tup_deleted'], source)) + p(string.format("POSTGRESQL_TRANSACTIONS_ROLLEDBACK %s %s", db_stats['totals']['xact_rollback'], source)) + p(string.format("POSTGRESQL_BLOCKS_HIT %s %s", db_stats['totals']['blks_hit'], source)) + p(string.format("POSTGRESQL_TUPLES_RETURNED %s %s", db_stats['totals']['tup_returned'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + p(string.format("POSTGRESQL_TUPLES_UPDATED %s %s", db_stats['totals']['tup_updated'], source)) + p(string.format("POSTGRESQL_TUPLES_INSERTED %s %s", db_stats['totals']['tup_inserted'], source)) + p(string.format("POSTGRESQL_TUPLES_FETCHED %s %s", db_stats['totals']['tup_fetched'], source)) + end) end) - end + end) end poll(connections) diff --git a/plugin.json b/plugin.json index cbf55a8..d36d46c 100644 --- a/plugin.json +++ b/plugin.json @@ -42,7 +42,7 @@ ], - "paramArray" : { "itemTitle" : ["source"], "schemaTitle" : "Host"}, + "paramArray" : { "itemTitle" : ["source"], "schemaTitle" : "Database"}, "paramSchema" : [ { "title" : "host", From 788bec4dc6d486d1fe00d5e5da2603f50ee67970 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 15:59:08 -0500 Subject: [PATCH 13/16] Fixed syntax error --- init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init.lua b/init.lua index c96c459..5909cdf 100644 --- a/init.lua +++ b/init.lua @@ -12,8 +12,8 @@ local connections = { user = "postgres", password = "123qwe", database = "postgres", - source = "" - pollInterval = 5000 + source = "", + pollInterval = 5000 }} -- Fetching params From 340e9c0f5d250b6e0ebb476f617885c572cdfcdf Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 16:06:30 -0500 Subject: [PATCH 14/16] Took out local variables --- init.lua | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/init.lua b/init.lua index 5909cdf..28ef6ca 100644 --- a/init.lua +++ b/init.lua @@ -22,35 +22,27 @@ if (boundary.param ~= nil) then end print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") -local dbcon = nil local function poll(connections) if table.getn(connections) > 0 then local query = connections[1] - local host = query.host - local port = query.port - local user = query.user - local password = query.password - local database = query.database - local source = query.source - local pollInterval = query.pollInterval + local dbcon = pginfo:new(query.host, query.port, query.user, query.password, query.database, query.source) table.remove(connections, 1) - local dbcon = pginfo:new(host, port, user, password, database, source) dbcon:establish(function(connection) dbcon:get_databases(connection, function(dbs) - getStats(connection, source) - timer.setInterval(pollInterval, getStats, connection, source) + getStats(connection, query.source) + timer.setInterval(query.pollInterval, getStats, dbcon, connection, query.source) poll(connections) end) end) end end -local function getStats(connection, source) - dbcon:get_bg_writer_stats(connection, function(writer_stats) - dbcon:get_lock_stats_mode(connection, function(db_locks) - dbcon:get_database_stats(connection, function(db_stats) +local function getStats(conobj, pgcon, source) + conobj:get_bg_writer_stats(pgcon, function(writer_stats) + conobj:get_lock_stats_mode(pgcon, function(db_locks) + conobj:get_database_stats(pgcon, function(db_stats) --lock stats p(string.format("POSTGRESQL_EXCLUSIVE_LOCKS %s %s", db_locks['all']['Exclusive'], source)) From 0bf55ce8cff45790010700ce6bd99bb5393cc5e5 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Fri, 13 Mar 2015 16:09:09 -0500 Subject: [PATCH 15/16] Had to move getStats --- init.lua | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/init.lua b/init.lua index 28ef6ca..15a3f6c 100644 --- a/init.lua +++ b/init.lua @@ -23,22 +23,6 @@ end print("_bevent:Boundary LUA Postgres plugin up : version 1.0|t:info|tags:lua,plugin") -local function poll(connections) - if table.getn(connections) > 0 then - local query = connections[1] - local dbcon = pginfo:new(query.host, query.port, query.user, query.password, query.database, query.source) - table.remove(connections, 1) - - dbcon:establish(function(connection) - dbcon:get_databases(connection, function(dbs) - getStats(connection, query.source) - timer.setInterval(query.pollInterval, getStats, dbcon, connection, query.source) - poll(connections) - end) - end) - end -end - local function getStats(conobj, pgcon, source) conobj:get_bg_writer_stats(pgcon, function(writer_stats) conobj:get_lock_stats_mode(pgcon, function(db_locks) @@ -82,4 +66,20 @@ local function getStats(conobj, pgcon, source) end) end +local function poll(connections) + if table.getn(connections) > 0 then + local query = connections[1] + local dbcon = pginfo:new(query.host, query.port, query.user, query.password, query.database, query.source) + table.remove(connections, 1) + + dbcon:establish(function(connection) + dbcon:get_databases(connection, function(dbs) + getStats(connection, query.source) + timer.setInterval(query.pollInterval, getStats, dbcon, connection, query.source) + poll(connections) + end) + end) + end +end + poll(connections) From 026c45336625ce3f89ce853b3434f42ff7d92ce9 Mon Sep 17 00:00:00 2001 From: TheBigHNF Date: Tue, 21 Apr 2015 15:28:17 -0500 Subject: [PATCH 16/16] Fixed README --- README.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index acfca73..b8497ce 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,19 @@ -Boundary PostgreSQL Plugin --------------------------- -**Awaiting Certification** +# Boundary PostgreSQL Plugin Extracts metrics from a PostgreSQL database instance. -### Prerequisites +## Prerequisites + +### Supported OS | OS | Linux | Windows | SmartOS | OS X | |:----------|:-----:|:-------:|:-------:|:----:| | Supported | v | v | v | v | -#### Boundary Meter Versions V4.0 Or Greater - -To get the new meter: +#### Boundary Meter Versions V4.0 or later - curl -fsS \ - -d "{\"token\":\"\"}" \ - -H "Content-Type: application/json" \ - "https://meter.boundary.com/setup_meter" > setup_meter.sh - chmod +x setup_meter.sh - ./setup_meter.sh +- To install new meter go to Settings->Installation or [see instructons|https://help.boundary.com/hc/en-us/sections/200634331-Installation]. +- To upgrade the meter to the latest version - [see instructons|https://help.boundary.com/hc/en-us/articles/201573102-Upgrading-the-Boundary-Meter]. #### For Boundary Meter less than V4.0