summaryrefslogtreecommitdiffstats
path: root/modules/graphite
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/graphite/.packaging/centos/7/rundeps1
-rw-r--r--modules/graphite/.packaging/centos/8/rundeps1
-rw-r--r--modules/graphite/.packaging/debian/10/rundeps1
-rw-r--r--modules/graphite/.packaging/debian/9/rundeps1
-rw-r--r--modules/graphite/.packaging/fedora/31/rundeps1
-rw-r--r--modules/graphite/.packaging/fedora/32/rundeps1
-rw-r--r--modules/graphite/.packaging/leap/15.2/NOTSUPPORTED6
-rwxr-xr-xmodules/graphite/.packaging/leap/15.2/pre-test.sh1
-rw-r--r--modules/graphite/.packaging/leap/15.2/rundeps6
-rw-r--r--modules/graphite/.packaging/test.config4
-rw-r--r--modules/graphite/.packaging/ubuntu/16.04/rundeps1
-rw-r--r--modules/graphite/.packaging/ubuntu/18.04/rundeps1
-rw-r--r--modules/graphite/.packaging/ubuntu/20.04/rundeps1
-rw-r--r--modules/graphite/README.rst49
-rw-r--r--modules/graphite/graphite.lua145
15 files changed, 220 insertions, 0 deletions
diff --git a/modules/graphite/.packaging/centos/7/rundeps b/modules/graphite/.packaging/centos/7/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/centos/7/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/.packaging/centos/8/rundeps b/modules/graphite/.packaging/centos/8/rundeps
new file mode 100644
index 0000000..182251d
--- /dev/null
+++ b/modules/graphite/.packaging/centos/8/rundeps
@@ -0,0 +1 @@
+lua5.1-cqueues
diff --git a/modules/graphite/.packaging/debian/10/rundeps b/modules/graphite/.packaging/debian/10/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/debian/10/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/.packaging/debian/9/rundeps b/modules/graphite/.packaging/debian/9/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/debian/9/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/.packaging/fedora/31/rundeps b/modules/graphite/.packaging/fedora/31/rundeps
new file mode 100644
index 0000000..182251d
--- /dev/null
+++ b/modules/graphite/.packaging/fedora/31/rundeps
@@ -0,0 +1 @@
+lua5.1-cqueues
diff --git a/modules/graphite/.packaging/fedora/32/rundeps b/modules/graphite/.packaging/fedora/32/rundeps
new file mode 100644
index 0000000..182251d
--- /dev/null
+++ b/modules/graphite/.packaging/fedora/32/rundeps
@@ -0,0 +1 @@
+lua5.1-cqueues
diff --git a/modules/graphite/.packaging/leap/15.2/NOTSUPPORTED b/modules/graphite/.packaging/leap/15.2/NOTSUPPORTED
new file mode 100644
index 0000000..b1ae77d
--- /dev/null
+++ b/modules/graphite/.packaging/leap/15.2/NOTSUPPORTED
@@ -0,0 +1,6 @@
+
+ERROR:test_packaging:Installing https://luarocks.org/cqueues-20190813.51-0.src.rock
+164 Error: Failed extracting rel-20190813.tar.gz
+
+Doesn't works on GitLab CI/CD, but works on localhost.
+gzip and tar packages are installed, all packages has same version as packages on localhost's docker container.
diff --git a/modules/graphite/.packaging/leap/15.2/pre-test.sh b/modules/graphite/.packaging/leap/15.2/pre-test.sh
new file mode 100755
index 0000000..9614066
--- /dev/null
+++ b/modules/graphite/.packaging/leap/15.2/pre-test.sh
@@ -0,0 +1 @@
+luarocks --lua-version 5.1 install cqueues --from=https://mah0x211.github.io/rocks/
diff --git a/modules/graphite/.packaging/leap/15.2/rundeps b/modules/graphite/.packaging/leap/15.2/rundeps
new file mode 100644
index 0000000..8323887
--- /dev/null
+++ b/modules/graphite/.packaging/leap/15.2/rundeps
@@ -0,0 +1,6 @@
+libopenssl-devel
+lua51-luarocks
+git
+tar
+gzip
+m4
diff --git a/modules/graphite/.packaging/test.config b/modules/graphite/.packaging/test.config
new file mode 100644
index 0000000..c23033b
--- /dev/null
+++ b/modules/graphite/.packaging/test.config
@@ -0,0 +1,4 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+modules.load('graphite')
+assert(graphite)
+quit()
diff --git a/modules/graphite/.packaging/ubuntu/16.04/rundeps b/modules/graphite/.packaging/ubuntu/16.04/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/ubuntu/16.04/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/.packaging/ubuntu/18.04/rundeps b/modules/graphite/.packaging/ubuntu/18.04/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/ubuntu/18.04/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/.packaging/ubuntu/20.04/rundeps b/modules/graphite/.packaging/ubuntu/20.04/rundeps
new file mode 100644
index 0000000..3da806b
--- /dev/null
+++ b/modules/graphite/.packaging/ubuntu/20.04/rundeps
@@ -0,0 +1 @@
+lua-cqueues
diff --git a/modules/graphite/README.rst b/modules/graphite/README.rst
new file mode 100644
index 0000000..2f86a6f
--- /dev/null
+++ b/modules/graphite/README.rst
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _mod-graphite:
+
+Graphite/InfluxDB/Metronome
+---------------------------
+
+The ``graphite`` sends statistics over the Graphite_ protocol to either Graphite_, Metronome_, InfluxDB_ or any compatible storage. This allows powerful visualization over metrics collected by Knot Resolver.
+
+.. tip:: The Graphite server is challenging to get up and running, InfluxDB_ combined with Grafana_ are much easier, and provide richer set of options and available front-ends. Metronome_ by PowerDNS alternatively provides a mini-graphite server for much simpler setups.
+
+Example configuration:
+
+Only the ``host`` parameter is mandatory.
+
+By default the module uses UDP so it doesn't guarantee the delivery, set ``tcp = true`` to enable Graphite over TCP. If the TCP consumer goes down or the connection with Graphite is lost, resolver will periodically attempt to reconnect with it.
+
+.. code-block:: lua
+
+ modules = {
+ graphite = {
+ prefix = hostname() .. worker.id, -- optional metric prefix
+ host = '127.0.0.1', -- graphite server address
+ port = 2003, -- graphite server port
+ interval = 5 * sec, -- publish interval
+ tcp = false -- set to true if you want TCP mode
+ }
+ }
+
+The module supports sending data to multiple servers at once.
+
+.. code-block:: lua
+
+ modules = {
+ graphite = {
+ host = { '127.0.0.1', '1.2.3.4', '::1' },
+ }
+ }
+
+Dependencies
+^^^^^^^^^^^^
+
+* `lua cqueues <https://25thandclement.com/~william/projects/cqueues.html>`_ package.
+
+
+.. _Graphite: https://graphite.readthedocs.io/en/latest/feeding-carbon.html
+.. _InfluxDB: https://influxdb.com/
+.. _Metronome: https://github.com/ahuPowerDNS/metronome
+.. _Grafana: http://grafana.org/
diff --git a/modules/graphite/graphite.lua b/modules/graphite/graphite.lua
new file mode 100644
index 0000000..8f6ba74
--- /dev/null
+++ b/modules/graphite/graphite.lua
@@ -0,0 +1,145 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+-- Load dependent modules
+if not stats then modules.load('stats') end
+
+-- This is leader-only module
+local M = {}
+local socket = require("cqueues.socket")
+local proto_txt = {
+ [socket.SOCK_DGRAM] = 'udp',
+ [socket.SOCK_STREAM] = 'tcp'
+}
+
+local function make_socket(host, port, stype)
+ local s, err, status
+ -- timeout before next interval begins (roughly)
+ local timeout_sec = (M.interval - 10) / sec
+
+ s = socket.connect({ host = host, port = port, type = stype })
+ s:setmode('bn', 'bn')
+ s:settimeout(timeout_sec)
+ status, err = pcall(s.connect, s, timeout_sec)
+ if status == true and err == nil then
+ err = 'connect timeout'
+ s:close()
+ status = false
+ end
+
+ if not status then
+ log('[graphite] connecting: %s@%d %s reason: %s',
+ host, port, proto_txt[stype], err)
+ return status, err
+ end
+ return s
+end
+
+-- Create connected UDP socket
+local function make_udp(host, port)
+ return make_socket(host, port, socket.SOCK_DGRAM)
+end
+
+-- Create connected TCP socket
+local function make_tcp(host, port)
+ return make_socket(host, port, socket.SOCK_STREAM)
+end
+
+-- Send the metrics in a table to multiple Graphite consumers
+local function publish_table(metrics, prefix, now)
+ local s
+ for i in ipairs(M.cli) do
+ local host = M.info[i]
+
+ if M.cli[i] == -1 then
+ if host.tcp then
+ s = make_tcp(host.addr, host.port)
+ else
+ s = make_udp(host.addr, host.port)
+ end
+ if s then
+ M.cli[i] = s
+ end
+ end
+
+ if M.cli[i] ~= -1 then
+ for key,val in pairs(metrics) do
+ local msg = key..' '..val..' '..now..'\n'
+ if prefix then
+ msg = prefix..'.'..msg
+ end
+
+ local ok, err = pcall(M.cli[i].write, M.cli[i], msg)
+ if not ok then
+ local tcp = M.cli[i]['connect'] ~= nil
+ if tcp and host.seen + 2 * M.interval / 1000 <= now then
+ local sock_type = (host.tcp and socket.SOCK_STREAM)
+ or socket.SOCK_DGRAM
+ log('[graphite] reconnecting: %s@%d %s reason: %s',
+ host.addr, host.port, proto_txt[sock_type], err)
+ s = make_tcp(host.addr, host.port)
+ if s then
+ M.cli[i] = s
+ host.seen = now
+ else
+ M.cli[i] = -1
+ break
+ end
+ end
+ end
+ end -- loop metrics
+ end
+ end -- loop M.cli
+end
+
+function M.init()
+ M.ev = nil
+ M.cli = {}
+ M.info = {}
+ M.interval = 5 * sec
+ M.prefix = string.format('kresd.%s.%s', hostname(), worker.id)
+ return 0
+end
+
+function M.deinit()
+ if M.ev then event.cancel(M.ev) end
+ return 0
+end
+
+-- @function Publish results to the Graphite server(s)
+function M.publish()
+ local now = os.time()
+ -- Publish built-in statistics
+ if not M.cli then error("no graphite server configured") end
+ publish_table(cache.stats(), M.prefix..'.cache', now)
+ publish_table(worker.stats(), M.prefix..'.worker', now)
+ -- Publish extended statistics if available
+ publish_table(stats.list(), M.prefix, now)
+ return 0
+end
+
+-- @function Make connection to Graphite server.
+function M.add_server(_, host, port, tcp)
+ table.insert(M.cli, -1)
+ table.insert(M.info, {addr = host, port = port, tcp = tcp, seen = 0})
+ return 0
+end
+
+function M.config(conf)
+ -- config defaults
+ if not conf then return 0 end
+ if not conf.port then conf.port = 2003 end
+ if conf.interval then M.interval = conf.interval end
+ if conf.prefix then M.prefix = conf.prefix end
+ if type(conf.host) == 'table' then
+ for _, val in pairs(conf.host) do
+ M:add_server(val, conf.port, conf.tcp)
+ end
+ else
+ M:add_server(conf.host, conf.port, conf.tcp)
+ end
+ -- start publishing stats
+ if M.ev then event.cancel(M.ev) end
+ M.ev = event.recurrent(M.interval, function() worker.coroutine(M.publish) end)
+ return 0
+end
+
+return M