Zabbix comes with an impressive list of supported metrics for virtually all platforms. It covers the monitoring of performance and availability of OS including CPU, memory, network, processes, files, kernel parameters and more. Zabbix also performs agent-less checks for well-known services such as FTP, SSH, IMAP, POP3, HTTP, TCP, etc.
Extending Zabbix functionality is a trivial task thanks to user parameters (agent metrics) and external checks (agent-less monitoring). It is just a matter of adding a new line into the configuration file of the agent and you have a dozen of new metrics supported. Depending on security settings you may also use system.run[], which does not require any changes on the agent side.
It works very well, but it has one major drawback, namely fork(). Zabbix has to fork a new process every time it handles a user metric, which is obviously not good for performance. It is not a big deal normally, however it could be a serious issue in case of monitoring of embedded systems, a large number of monitored parameters or heavy scripts with complex logic or long startup time.
Zabbix 2.2 comes with support of loadable modules for extending Zabbix agent and server without sacrificing performance.
Articles in 2.2 feature series:
- Part 1 – Automatic database upgrading
- Part 2 – Templated web monitoring
- Part 3 – Web scenario retries
- Part 4 – HTTP proxy for web monitoring
- Part 5 – Better value mapping
- Part 6 – Returning values from webpages
- Part 7 – Value extracting from logfiles and more
- Part 8 – Reusing content in web monitoring
- Part 9 – No more full page reload in latest data
- Part 10 – Support of loadable modules
- Part 11 – SNMP monitoring improvements
Support of loadable modules
What is a loadable module?
Basically it is a shared library used by Zabbix server or agent and loaded on startup. The library should contain certain functions, so that a Zabbix process may detect that the file is indeed a module it can load and work with.
Zabbix server and agent support two parameters to deal with modules:
- LoadModulePath – Full path to the location of agent modules
- LoadModule – Module to load at agent startup. Modules are used to extend the functionality of the server or agents. The modules must be located in a directory specified by LoadModulePath. It is allowed to include multiple LoadModule parameters.
For example, suppose we’d like to extend Zabbix agent:
LoadModulePath=/usr/local/lib/zabbix/agent/ LoadModule=mariadb.so LoadModule=apache.so LoadModule=kernel.so LoadModule=dummy.so
When Zabbix agent starts it loads the modules mariadb.so, apache.so, kernel.so and dummy.so from directory /usr/local/lib/zabbix/agent. It will fail if a module is missing, in case of bad permissions or if a shared library is not a Zabbix module.
Advantages
Loadable modules have a number of benefits. Great performance and ability to implement any logic are very important, but I think that the most important advantage is the ability to develop, use and share Zabbix modules. It contributes to trouble-free maintenance and helps to deliver new functionality easier and independently of Zabbix core code base.
Dummy module
Zabbix 2.2 includes a sample module written in C language. Let us have a look.
The module is located under src/modules/dummy:
alex@alex:~trunk/src/modules/dummy$ ls -l -rw-rw-r-- 1 alex alex 9019 Apr 24 17:54 dummy.c -rw-rw-r-- 1 alex alex 67 Apr 24 17:54 Makefile -rw-rw-r-- 1 alex alex 245 Apr 24 17:54 README
The module is well documented, it can be used as a template for your own modules.
Just run make in order to build dummy.so.
/* ** Zabbix ** Copyright (C) 2001-2013 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. **/ #include "sysinc.h" #include "module.h" /* the variable keeps timeout setting for item processing */ static int item_timeout = 0; int zbx_module_dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result); int zbx_module_dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result); int zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result); static ZBX_METRIC keys[] = /* KEY FLAG FUNCTION TEST PARAMETERS */ { {"dummy.ping", 0, zbx_module_dummy_ping, NULL}, {"dummy.echo", CF_HAVEPARAMS, zbx_module_dummy_echo, "a message"}, {"dummy.random", CF_HAVEPARAMS, zbx_module_dummy_random,"1,1000"}, {NULL} }; /****************************************************************************** * * * Function: zbx_module_api_version * * * * Purpose: returns version number of the module interface * * * * Return value: ZBX_MODULE_API_VERSION_ONE - the only version supported by * * Zabbix currently * * * ******************************************************************************/ int zbx_module_api_version() { return ZBX_MODULE_API_VERSION_ONE; } /****************************************************************************** * * * Function: zbx_module_item_timeout * * * * Purpose: set timeout value for processing of items * * * * Parameters: timeout - timeout in seconds, 0 - no timeout set * * * ******************************************************************************/ void zbx_module_item_timeout(int timeout) { item_timeout = timeout; } /****************************************************************************** * * * Function: zbx_module_item_list * * * * Purpose: returns list of item keys supported by the module * * * * Return value: list of item keys * * * ******************************************************************************/ ZBX_METRIC *zbx_module_item_list() { return keys; } int zbx_module_dummy_ping(AGENT_REQUEST *request, AGENT_RESULT *result) { SET_UI64_RESULT(result, 1); return SYSINFO_RET_OK; } int zbx_module_dummy_echo(AGENT_REQUEST *request, AGENT_RESULT *result) { char *param; if (1 != request->nparam) { /* set optional error message */ SET_MSG_RESULT(result, strdup("Invalid number of parameters")); return SYSINFO_RET_FAIL; } param = get_rparam(request, 0); SET_STR_RESULT(result, strdup(param)); return SYSINFO_RET_OK; } /****************************************************************************** * * * Function: zbx_module_dummy_random * * * * Purpose: a main entry point for processing of an item * * * * Parameters: request - structure that contains item key and parameters * * request->key - item key without parameters * * request->nparam - number of parameters * * request->timeout - processing should not take longer than * * this number of seconds * * request->params[N-1] - pointers to item key parameters * * * * result - structure that will contain result * * * * Return value: SYSINFO_RET_FAIL - function failed, item will be marked * * as not supported by zabbix * * SYSINFO_RET_OK - success * * * * Comment: get_rparam(request, N-1) can be used to get a pointer to the Nth * * parameter starting from 0 (first parameter). Make sure it exists * * by checking value of request->nparam. * * * ******************************************************************************/ int zbx_module_dummy_random(AGENT_REQUEST *request, AGENT_RESULT *result) { char *param1, *param2; int from, to; if (request->nparam != 2) { /* set optional error message */ SET_MSG_RESULT(result, strdup("Invalid number of parameters")); return SYSINFO_RET_FAIL; } param1 = get_rparam(request, 0); param2 = get_rparam(request, 1); /* there is no strict validation of parameters for simplicity sake */ from = atoi(param1); to = atoi(param2); if (from > to) { SET_MSG_RESULT(result, strdup("Incorrect range given")); return SYSINFO_RET_FAIL; } SET_UI64_RESULT(result, from + rand() % (to - from + 1)); return SYSINFO_RET_OK; } /****************************************************************************** * * * Function: zbx_module_init * * * * Purpose: the function is called on agent startup * * It should be used to call any initialization routines * * * * Return value: ZBX_MODULE_OK - success * * ZBX_MODULE_FAIL - module initialization failed * * * * Comment: the module won't be loaded in case of ZBX_MODULE_FAIL * * * ******************************************************************************/ int zbx_module_init() { /* initialization for dummy.random */ srand(time(NULL)); return ZBX_MODULE_OK; } /****************************************************************************** * * * Function: zbx_module_uninit * * * * Purpose: the function is called on agent shutdown * * It should be used to cleanup used resources if there are any * * * * Return value: ZBX_MODULE_OK - success * * ZBX_MODULE_FAIL - function failed * * * ******************************************************************************/ int zbx_module_uninit() { return ZBX_MODULE_OK; }
The module exports three new items:
dummy.ping – always returns ‘1’
dummy.echo[param1] – returns first parameter as it is, for example, dummy.echo[ABC] will return ABC
dummy.random[param1, param2] – returns a random number in a range of param1-param2, for example, dummy.random[1,1000000]
Limitations
There are a number of limitations. First of all, support of loadable modules is implemented for the Unix platform only. It means that it does not work for Windows agents.
In some cases a module may need to read module-related configuration parameters from zabbix_agentd.conf. It is not supported currently. If you need your module to use some configuration parameters you should probably implement parsing of a module-specific configuration file.
What’s next
The functionality is already available in the development version – see instructions for using development builds or obtaining the latest and greatest from SVN. Have a look, make your own module and report any issues if you are interested. And please consider sharing your great work with Zabbix community and good people around you.
I wish we already had plug-in enabled architecture for all parts of Zabbix functionality not limited only to data collection. It’s coming, stay tuned! 🙂
Is it only for zabbix_agentd or it could be written for zabbix_server?
It is for both extending functionality of the agent as well as for extending server-side agent-less monitoring (simple checks). This way you could write a server module which would check availability and/or performance of a remote service, for example.