Communicating with Zabbix

Now you know how the Zabbix protocol works, so it is time to see some code that implements this protocol. To keep things easy, we have described an example of the zabbix_sender protocol—the simplest way to send data to Zabbix.

Zabbix uses JSON to describe the object contained in the data. There are a lot of efficient JSON libraries that can be used, but to make things easier here, those libraries will not be used.

Implementing the Zabbix_sender protocol in Java

Here, you will see a really simple implementation of the zabbix_sender protocol that, as you know, is the easy way to send traps to Zabbix.

The piece of code that follows has been kept as simple as possible, and the scope is to provide an example from which you can start to develop your own Zabbix monitoring component:

private String buildJSonString(String host, String item,Long timestamp, String value){
  return  "{"
    + ""request":"sender data",
"
    + ""data":[
"
    +          "{
"
      +         ""host":"" + host + "",
"
      +          ""key":"" + item + "",
"
      +          ""value":"" + value.replace("\", "\\") + "",
"
      +         ""clock":" + timestamp.toString()
    +         "}]}
" ;
  }

This piece of code simply returns the JSON message to send it as a body. You only need to provide the host and item or, better, the item key, value, and timestamp to include into the message, and it will return a JSON-formatted string object.

Now, once you have retrieved all your item values, you simply need to generate the JSON message, open a connection, and send the message. To open a connection against your Zabbix server, we can use the following lines of code:

String data = buildJSonString( host,item,value);
  zabbix = new Socket(zabbixServer, zabbixPort);
  zabbix.setSoTimeout(TIMEOUT);
  out = new OutputStreamWriter(zabbix.getOutputStream());
  int length = data.length;

In this code, as you see the program open a socket, define the timeout, and retrieve the message length, it is now ready to send the message. Please remember that the message is composed with <HEADER><DATALEN><MESSAGE>. A simple way to send the header and the data length is the following:

out.write(new byte[] {
  'Z', 'B', 'X', 'D',
  '1',
  (byte)(length & 0xFF),
  (byte)((length >> 8) & 0x00FF),
  (byte)((length >> 16) & 0x0000FF),
  (byte)((length >> 24) & 0x000000FF),
'','','',''});

This portion of code writes the message on the socket that actually contains the host, item, and value:

out.write(data);

Remember to flush the data, close the socket, and complete the delivery as follows:

out.flush();
out.close();

Now, we need to see what the Zabbix server will say about our item:

in = zabbix.getInputStream();
final int read = in.read(response);
String respStatus = (String) getValue(response);
if (read !=2 || respStatus.equals(ZBX_SUCCESS)) {
in.close();
}

If the response is that of a success, you can close InputStream.

This example is fully working, but it is only for educational purposes. There are different things to improve before considering it ready for production. Anyway, this is a good starting point. This example can be extended by handling multiple JSON objects on the data section, thus increasing the number of objects passed per connection. You need to limit the connection numbers and avoid flooding your Zabbix server with connections just to send an item. Items can be buffered and sent together; for instance, if you have a group of items with the same schedule, all of them can be sent together.

When you retrieve your items, it is important to keep track of the timestamps. To do so, you can add the timestamp to your item and know when it has actually retrieved this metric.

In the previous example, the timestamp is not sent since it is optional, but it is a good practice to include it, especially if you're buffering an item; when you send it, the items will have the right timestamp.

Implementing the Zabbix sender protocol in Python

Nowadays, a lot of applications are written in Python, and it is a programing language that is widely diffused and known. For this reason, this is an example of a fundamental threat that can be the starting point for your custom zabbix_sender in Python. This piece of code can be extended and integrated directly into your software. Having a functionality integrated into the application can be really interesting because the application itself can send its health status to your Zabbix server. Now, it is time to take a look at the piece of code and how it works.

First, you need to define the structure and import simplejson used here to add the host, key, item value, and clock in the JSON format:

import simplejson as smplj
items_data = []

Now, retrieve the timestamp from the items; if it is null, we will get the current timestamp:

clock = zbxit.clock or time.time()

Now, you can begin to create the JSON object to include it in the Zabbix message:

       items_data.append(('		{
'
                             '			"host":%s,
'
                             '			"key":%s,
'
                             '			"value":%s,
'
                             '			"clock":%s}') % (smplj.dump(zbxit.host), smplj.dump(zbxit.key), smplj.dump(zbxit.value), clock))

Now that your item has been transformed into a JSON object, it is time for the header:

    json_items = ('{
'
                '	"request":"sender data",
'
                '	"data":[
%s]
'
                '}') % (',
'.join(items_data))

The next step is to retrieve the length of our message to add it on the header:

    data_len = struct.pack('<Q', len(json_items))

As previously discussed, here the message is put on the form <HEADER><DATALEN>+<JSON ITEM> as follows:

    packet = 'ZBXD1' + data_len + json_items        

Then, the socket is going to be open and the packet will be sent:

        zabbix = socket.socket()
        zabbix.connect((zabbix_host, zabbix_port))
        zabbix.sendall(packet)

Once the packet has been sent, it is time to retrieve the Zabbix server response:

 resp_hdr = _recv_all(zabbix, 13)

Next check whether it is valid:

        if not resp_hdr.startswith('ZBXD1') or len(resp_hdr) != 13:
            return False
        resp_body_size = struct.unpack('<Q', resp_hdr[5:])[0]
        resp_body = zabbix.recv(resp_body_size)
        zabbix.close()
        resp = smplj.loads(resp_body)
         if resp.get('response') != 'success':
            return False
        return True

This piece of code is a good starting point to develop the Zabbix sender protocol in Python.

Some considerations about agent development

Now, you probably don't see when to begin the development of your software that sends a trap to Zabbix. But before beginning to write the code, it is fundamental to keep in mind the requirements and the problem.

Until now, you have two examples, and you can easily start to send a trap to the Zabbix server even if they are not completely engineered components.

As the first point, it is important to understand whether it is only needed to send the data to Zabbix at a specified time schedule that is not directed from the Zabbix server. Those two pieces of code implement the Zabbix sender protocol, but the frequency with which the items are retrieved and sent can't be defined from the Zabbix server. Here, it is important to keep in mind who will drive your software. Is it the Zabbix server or your software? To enable Zabbix to drive the sampling frequency, you need to implement the Zabbix agent protocol. The agent protocol is a bit more articulated and a bit more complex to implement. Anyway, the two examples proposed have all the components needed to properly handle the agent protocol.

There is another point to consider. Usually, developers have their own preference for a programming language. Here, it is important to use the right instrument to solve the problem. A practical example would be to monitor your Oracle database. So, your software will need to interact with commercial software; the easy and logical choice is to use Java. Now, all the Python fans will stick up their nose! Here, more than the preference, it is important keep in mind what is better supported from the monitored entity.

Oracle and databases in general produce standard industry-engineered drivers for Java to interact with them. Most of the database vendors provide and, more importantly, update, fix, and develop their JDBC drivers continuously. It is better to delegate a bit of work to vendors. Also, they know their products better, and you can get assistance on that.

Java has a lot of well-engineered components that will make your life easy in the difficult task of monitoring a database. For instance, the JDBC framework, together with the database driver, will provide efficient connection pooling that can be configured to:

  • Handle a minimum number, and a maximum number, of connections
  • Validate the connection before using it for your software
  • Send a keep-alive packet (useful to avoid firewall issues)
  • Handle a reap time, removing all the idle connections (reducing the total number of connections on the monitored server)

Those are only a few of the points covered by JDBC. All these points will help you to keep the monitoring lightweight and efficient.

Note

An example of software made to monitor databases in general is DBforBIX available at http://sourceforge.net/projects/dbforbix/ or http://www.smartmarmot.com/product/dbforbix/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.233.134