Ad Widget

Collapse

Python version of zabbix_sender

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • raymanfu
    Junior Member
    • Aug 2009
    • 5

    #1

    Python version of zabbix_sender

    Hi, I have been working on a direct method to update zabbix_sender style items from python. I got sick of making system calls to zabbix_sender and not really being able to detect when an item was not accepted by the server. I created the following class and there is example usage in the comments. Feedback on my naive python code is always appreciated :-)

    Code:
    import socket
    import struct
    import json
    import os
    import time
    import sys
    import re
    
    ZABBIX_SERVER="127.0.0.1"
    ZABBIX_PORT=10051
    
    class ZSend:
       def __init__(self, server=ZABBIX_SERVER, port=ZABBIX_PORT):
          self.zserver = server
          self.zport = port
          self.list = []
          self.inittime = int(round(time.time()))
          self.header = '''ZBXD\1%s%s'''
          self.datastruct = '''
    { "host":"%s",
      "key":"%s",
      "value":"%s",
      "clock":%s }'''
    
       def add_data(self,host,key,value,evt_time=None):
          if evt_time is None:
             evt_time = self.inittime
          self.list.append((host,key,value,evt_time))
    
       def print_vals(self):
          for (h,k,v,t1) in self.list:
             print "Host: %s, Key: %s, Value: %s, Event: %s" % (h,k,v,t1)
    
       def build_all(self):
          tmpdata = "{\"request\":\"sender data\",\"data\":["
          count = 0
          for (h,k,v,t1) in self.list:
             tmpdata = tmpdata + self.datastruct % (h,k,v,t1)
             count += 1
             if count < len(self.list):
                tmpdata = tmpdata + ","
          tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
          return (tmpdata)
    
       def build_single(self,dataset):
          tmpdata = "{\"request\":\"sender data\",\"data\":["
          (h,k,v,t1) = dataset
          tmpdata = tmpdata + self.datastruct % (h,k,v,t1)
          tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
          return (tmpdata)
    
       def send(self,mydata):
          socket.setdefaulttimeout(5)
          data_length = len(mydata)
          data_header = struct.pack('i', data_length) + '\0\0\0\0'
          data_to_send = self.header % (data_header, mydata)
          try:
             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             sock.connect((self.zserver,self.zport))
             sock.send(data_to_send)
          except Exception as err:
             sys.stderr.write("Error talking to server: %s\n" % err)
             return (255,err)
    
          response_header = sock.recv(5)
          if not response_header == 'ZBXD\1':
             sys.stderr.write("Invalid response from server." + \
                              "Malformed data?\n---\n%s\n---\n" % mydata)
             return (254,err)
          response_data_header = sock.recv(8)
          response_data_header = response_data_header[:4]
          response_len = struct.unpack('i', response_data_header)[0]
          response_raw = sock.recv(response_len)
          sock.close()
          response = json.loads(response_raw)
          match = re.match("^.*Failed\s(\d+)\s.*$",str(response))
          if match is None:
             sys.stderr.write("Unable to parse server response - " + \
                              "\n%s\n" % response)
          else:
             fails = int(match.group(1))
             if fails > 0:
                sys.stderr.write("Failures reported by zabbix when sending:" + \
                                 "\n%s\n" % mydata)
                return (1,response)
          return (0,response)
    
    
    #####################################
    # --- Examples of usage ---
    #####################################
    #
    # Initiating a Zsend object -
    # z = ZSend(server="10.0.0.10")
    # z = ZSend(server="server1",port="10051")
    # z = ZSend("server1","10051")
    # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
    #
    
    # --- Adding data to send later ---
    # Host, Key, Value are all necessary
    # z.add_data("host1","cpu.usage","12")
    #
    # Optionally you can provide a specific timestamp for the sample
    # z.add_data("host1","cpu.usage","13","1365787627")
    #
    # If you provide no timestamp, the initialization time of the class
    # is used.
    
    # --- Printing values ---
    # Not that useful, but if you would like to see your data in tuple form
    # with assumed timestamps
    # z.print_vals()
    
    # --- Building well formatted data to send ---
    # You can send all of the data in one batch -
    # z.build_all() will return a string of packaged data ready to send
    # z.build_single((host,key,value,timestamp)) will return a packaged single
    
    # --- Sending data ---
    # Typical example - build all the data and send it in one batch -
    #
    # z.send(z.build_all())
    #
    # Alternate example - build the data individually and send it one by one
    # so that we can see errors for anything that doesnt send properly -
    #
    # for i in z.list:
    #    (code,ret) = z.send(z.build_single(i))
    #    if code == 1:
    #       print "Problem during send!\n%s" % ret
    #    elif code == 0:
    #       print ret
    #
    #
    #####################################
    # Mini example of a working program #
    #####################################
    #
    # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
    # z.add_data("host1","cpu.usage","12")
    # z.print_vals()
    # for i in z.list:
    #    (code,ret) = z.send(z.build_single(i))
    #    if code == 1:
    #       print "Problem during send!\n%s" % ret
    #    elif code == 0:
    #       print ret
    #
    #####################################
  • Spindel
    Junior Member
    • Mar 2010
    • 4

    #2
    What license are you putting that out under? GPL? BSD? APL? Something else?

    Comment

    • raymanfu
      Junior Member
      • Aug 2009
      • 5

      #3
      I am not really that bothered, but the base of the code was thanks to this wonderful post - https://www.zabbix.com/forum/showthread.php?p=90132. Enrico Tröger's prefered license appears to be GNU GPLv2.

      I have updated the code a little to add some functionality and generally simplify usage. Please refer to the example code in the comments at the end for usage.

      Code:
      #! /usr/bin/python
      # Copyright 2013 Rob Cherry <zsend(at)lxrb(dot)com>
      # Based on work by Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
      # License: GNU GPLv2
      
      import socket
      import struct
      import json
      import os
      import time
      import sys
      import re
      
      ZABBIX_SERVER="127.0.0.1"
      ZABBIX_PORT=10051
      
      class ZSend:
         def __init__(self, server=ZABBIX_SERVER, port=ZABBIX_PORT, verbose=False):
            self.zserver = server
            self.zport = port
            self.verbose = verbose
            self.list = []
            self.inittime = int(round(time.time()))
            self.header = '''ZBXD\1%s%s'''
            self.datastruct = '''
      { "host":"%s",
        "key":"%s",
        "value":"%s",
        "clock":%s }'''
      
         def add_data(self,host,key,value,evt_time=None):
            if evt_time is None:
               evt_time = self.inittime
            self.list.append((host,key,value,evt_time))
      
         def print_vals(self):
            for (h,k,v,t) in self.list:
               print "Host: %s, Key: %s, Value: %s, Event: %s" % (h,k,v,t)
      
         def build_all(self):
            tmpdata = "{\"request\":\"sender data\",\"data\":["
            count = 0
            for (h,k,v,t) in self.list:
               tmpdata = tmpdata + self.datastruct % (h,k,v,t)
               count += 1
               if count < len(self.list):
                  tmpdata = tmpdata + ","
            tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
            return (tmpdata)
      
         def build_single(self,dataset):
            tmpdata = "{\"request\":\"sender data\",\"data\":["
            (h,k,v,t) = dataset
            tmpdata = tmpdata + self.datastruct % (h,k,v,t)
            tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
            return (tmpdata)
      
         def send(self,mydata):
            socket.setdefaulttimeout(5)
            data_length = len(mydata)
            data_header = struct.pack('i', data_length) + '\0\0\0\0'
            data_to_send = self.header % (data_header, mydata)
            try:
               sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
               sock.connect((self.zserver,self.zport))
               sock.send(data_to_send)
            except Exception as err:
               sys.stderr.write("Error talking to server: %s\n" % err)
               return (255,err)
      
            response_header = sock.recv(5)
            if not response_header == 'ZBXD\1':
               sys.stderr.write("Invalid response from server." + \
                                "Malformed data?\n---\n%s\n---\n" % mydata)
               return (254,err)
            response_data_header = sock.recv(8)
            response_data_header = response_data_header[:4]
            response_len = struct.unpack('i', response_data_header)[0]
            response_raw = sock.recv(response_len)
            sock.close()
            response = json.loads(response_raw)
            match = re.match("^.*Failed\s(\d+)\s.*$",str(response))
            if match is None:
               sys.stderr.write("Unable to parse server response - " + \
                                "\n%s\n" % response)
            else:
               fails = int(match.group(1))
               if fails > 0:
                  if self.verbose is True:
                     sys.stderr.write("Failures reported by zabbix when sending:" + \
                                      "\n%s\n" % mydata)
                  return (1,response)
            return (0,response)
      
         def bulk_send(self):
            data = self.build_all()
            result = self.send(data)
            return result
      
         def iter_send(self):
            retarray = []
            for i in self.list:
               (retcode,retstring) = self.send(self.build_single(i))
               retarray.append((retcode,i))
            return retarray
      
      
      #####################################
      # --- Examples of usage ---
      #####################################
      #
      # Initiating a Zsend object -
      # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
      # z = ZSend(verbose=True) # Prints all sending failures to stderr
      # z = ZSend(server="172.0.0.100",verbose=True)
      # z = ZSend(server="zabbix-server",port="10051")
      # z = ZSend("zabbix-server","10051")
      #
      
      # --- Adding data to send later ---
      # Host, Key, Value are all necessary
      # z.add_data("host","cpu.ready","12")
      #
      # Optionally you can provide a specific timestamp for the sample
      # z.add_data("host","cpu.ready","13","1365787627")
      #
      # If you provide no timestamp, the initialization time of the class
      # is used.
      
      # --- Printing values ---
      # Not that useful, but if you would like to see your data in tuple form
      # with assumed timestamps
      # z.print_vals()
      
      # --- Building well formatted data to send ---
      # You can send all of the data in one batch -
      # z.build_all() will return a string of packaged data ready to send
      # z.build_single((host,key,value,timestamp)) will return a packaged single
      
      # --- Sending data manually ---
      # Typical example 1 - build all the data and send it in one batch -
      #
      # z.send(z.build_all())
      #
      # Alternate example - build the data individually and send it one by one
      # so that we can see errors for anything that doesnt send properly -
      #
      # for i in z.list:
      #    (code,ret) = z.send(z.build_single(i))
      #    if code == 1:
      #       print "Problem during send!\n%s" % ret
      #    elif code == 0:
      #       print ret
      #
      # --- Sending data with built in functions ---
      #
      # Sending everything at once, with no concern about
      # individual item failure -
      #
      # (retcode,retstring) = z.bulk_send()
      # print "Result: %s -> %s" % (str(retcode),retstring)
      #
      # Sending every item individually so that we can capture
      # success or failure
      #
      # results = z.iter_send()
      # for (code,data) in results:
      #   (h,k,v,t) = data
      #   if code == 1:
      #      print "Failed to update key: %s for host: %s" % (k,h)
      #
      #
      #####################################
      # Mini example of a working program #
      #####################################
      #
      # import sys
      # sys.path.append("/path/to/Zsend.py")
      # from ZSend import ZSend
      #
      # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
      # z.add_data("host1","cpu.ready","12")
      # z.add_data("host1","cpu.ready","13",1366033479)
      # z.print_vals()
      #
      # results = z.iter_send()
      # for (code,data) in results:
      #   (h,k,v,t) = data
      #   if code == 1:
      #      print "Failed to update key: %s for host: %s" % (k,h)
      #
      #####################################

      Comment

      • Spindel
        Junior Member
        • Mar 2010
        • 4

        #4
        I think his post is using GPL because it was based on the zabbix_send source code. Which was the reason I'm asking.

        I'm a bit tied up (re)-creating a bit of a mess atm, I'll take a look on the code tonight.

        Comment

        • rmiddleswarth
          Junior Member
          • Feb 2011
          • 3

          #5
          Originally posted by raymanfu
          Hi, I have been working on a direct method to update zabbix_sender style items from python. I got sick of making system calls to zabbix_sender and not really being able to detect when an item was not accepted by the server. I created the following class and there is example usage in the comments. Feedback on my naive python code is always appreciated :-)

          Code:
          import socket
          import struct
          import json
          import os
          import time
          import sys
          import re
          
          ZABBIX_SERVER="127.0.0.1"
          ZABBIX_PORT=10051
          
          class ZSend:
             def __init__(self, server=ZABBIX_SERVER, port=ZABBIX_PORT):
                self.zserver = server
                self.zport = port
                self.list = []
                self.inittime = int(round(time.time()))
                self.header = '''ZBXD\1%s%s'''
                self.datastruct = '''
          { "host":"%s",
            "key":"%s",
            "value":"%s",
            "clock":%s }'''
          
             def add_data(self,host,key,value,evt_time=None):
                if evt_time is None:
                   evt_time = self.inittime
                self.list.append((host,key,value,evt_time))
          
             def print_vals(self):
                for (h,k,v,t1) in self.list:
                   print "Host: %s, Key: %s, Value: %s, Event: %s" % (h,k,v,t1)
          
             def build_all(self):
                tmpdata = "{\"request\":\"sender data\",\"data\":["
                count = 0
                for (h,k,v,t1) in self.list:
                   tmpdata = tmpdata + self.datastruct % (h,k,v,t1)
                   count += 1
                   if count < len(self.list):
                      tmpdata = tmpdata + ","
                tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
                return (tmpdata)
          
             def build_single(self,dataset):
                tmpdata = "{\"request\":\"sender data\",\"data\":["
                (h,k,v,t1) = dataset
                tmpdata = tmpdata + self.datastruct % (h,k,v,t1)
                tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
                return (tmpdata)
          
             def send(self,mydata):
                socket.setdefaulttimeout(5)
                data_length = len(mydata)
                data_header = struct.pack('i', data_length) + '\0\0\0\0'
                data_to_send = self.header % (data_header, mydata)
                try:
                   sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                   sock.connect((self.zserver,self.zport))
                   sock.send(data_to_send)
                except Exception as err:
                   sys.stderr.write("Error talking to server: %s\n" % err)
                   return (255,err)
          
                response_header = sock.recv(5)
                if not response_header == 'ZBXD\1':
                   sys.stderr.write("Invalid response from server." + \
                                    "Malformed data?\n---\n%s\n---\n" % mydata)
                   return (254,err)
                response_data_header = sock.recv(8)
                response_data_header = response_data_header[:4]
                response_len = struct.unpack('i', response_data_header)[0]
                response_raw = sock.recv(response_len)
                sock.close()
                response = json.loads(response_raw)
                match = re.match("^.*Failed\s(\d+)\s.*$",str(response))
                if match is None:
                   sys.stderr.write("Unable to parse server response - " + \
                                    "\n%s\n" % response)
                else:
                   fails = int(match.group(1))
                   if fails > 0:
                      sys.stderr.write("Failures reported by zabbix when sending:" + \
                                       "\n%s\n" % mydata)
                      return (1,response)
                return (0,response)
          
          
          #####################################
          # --- Examples of usage ---
          #####################################
          #
          # Initiating a Zsend object -
          # z = ZSend(server="10.0.0.10")
          # z = ZSend(server="server1",port="10051")
          # z = ZSend("server1","10051")
          # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
          #
          
          # --- Adding data to send later ---
          # Host, Key, Value are all necessary
          # z.add_data("host1","cpu.usage","12")
          #
          # Optionally you can provide a specific timestamp for the sample
          # z.add_data("host1","cpu.usage","13","1365787627")
          #
          # If you provide no timestamp, the initialization time of the class
          # is used.
          
          # --- Printing values ---
          # Not that useful, but if you would like to see your data in tuple form
          # with assumed timestamps
          # z.print_vals()
          
          # --- Building well formatted data to send ---
          # You can send all of the data in one batch -
          # z.build_all() will return a string of packaged data ready to send
          # z.build_single((host,key,value,timestamp)) will return a packaged single
          
          # --- Sending data ---
          # Typical example - build all the data and send it in one batch -
          #
          # z.send(z.build_all())
          #
          # Alternate example - build the data individually and send it one by one
          # so that we can see errors for anything that doesnt send properly -
          #
          # for i in z.list:
          #    (code,ret) = z.send(z.build_single(i))
          #    if code == 1:
          #       print "Problem during send!\n%s" % ret
          #    elif code == 0:
          #       print ret
          #
          #
          #####################################
          # Mini example of a working program #
          #####################################
          #
          # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
          # z.add_data("host1","cpu.usage","12")
          # z.print_vals()
          # for i in z.list:
          #    (code,ret) = z.send(z.build_single(i))
          #    if code == 1:
          #       print "Problem during send!\n%s" % ret
          #    elif code == 0:
          #       print ret
          #
          #####################################
          This has been working well for me under Zabbix 2.0 but seems to have broken with I upgrade to 2.2 any one know what needs to be changed to make this work with 2.2?

          Thanks
          Robert

          Comment

          • aklim007
            Junior Member
            • Jul 2014
            • 5

            #6
            Originally posted by rmiddleswarth
            This has been working well for me under Zabbix 2.0 but seems to have broken with I upgrade to 2.2 any one know what needs to be changed to make this work with 2.2?

            Thanks
            Robert
            Code:
            #! /usr/bin/python
            # -*- coding: utf-8
            # Copyright 2014 Klimenko Artyem <aklim007(at)gmail(dot)com>
            # Based on work by Rob Cherry <zsend(at)lxrb(dot)com>
            # > Based on work by Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
            # License: GNU GPLv2
            
            
            import socket
            import struct
            import json
            import time
            import sys
            import re
            
            ZABBIX_SERVER = "127.0.0.1"
            ZABBIX_PORT = 10051
            
            
            class ZSend:
                def __init__(self, server=ZABBIX_SERVER, port=ZABBIX_PORT, verbose=False):
                    self.zserver = server
                    self.zport = port
                    self.verbose = verbose
                    self.list = []
                    self.inittime = int(round(time.time()))
                    self.clock_flag = False
            
                def add_data(self, host, key, value, clock=None):
                    obj = {
                        'host': host,
                        'key': key,
                        'value': value,
                    }
                    if clock:
                        obj['clock'] = clock
                        self.clock_flag = True
                    self.list.append(obj)
            
                def print_vals(self):
                    for elem in self.list:
                        print u'{0}'.format(elem)
                    print u'Count: {0}'.format(len(self.list))
            
                def build_all(self):
                    send_data = {
                        "request": "sender data",
                        "data": [],
                    }
                    if self.clock_flag:
                        send_data['clock'] = self.inittime
                    send_data['data'] = self.list
                    return json.dumps(send_data)
            
                def build_single(self, data):
                    send_data = {
                        "request": "sender data",
                        "data": [],
                    }
                    if 'clock' in data:
                        send_data['clock'] = self.inittime
                    send_data['data'].append(data)
                    return json.dumps(send_data)
            
                def send(self, mydata):
                    socket.setdefaulttimeout(5)
                    data_length = len(mydata)
                    data_header = '{0}{1}'.format(struct.pack('i', data_length), '\0\0\0\0')
                    data_to_send = 'ZBXD\1{0}{1}'.format(data_header, mydata)
                    try:
                        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                        sock.connect((self.zserver, self.zport))
                        sock.send(data_to_send)
                    except Exception as err:
                        err_message = u'Error talking to server: {0}\n'.format(err)
                        sys.stderr.write(err_message)
                        return 255, err_message
            
                    response_header = sock.recv(5)
                    if not response_header == 'ZBXD\1':
                        err_message = u'Invalid response from server. Malformed data?\n---\n{0}\n---\n'.format(mydata)
                        sys.stderr.write(err_message)
                        return 254, err_message
                    response_data_header = sock.recv(8)
                    response_data_header = response_data_header[:4]
                    response_len = struct.unpack('i', response_data_header)[0]
                    response_raw = sock.recv(response_len)
                    sock.close()
                    response = json.loads(response_raw)
                    match = re.match('^.*failed.+?(\d+).*$', response['info'].lower() if 'info' in response else '')
                    if match is None:
                        err_message = u'Unable to parse server response - \n{0}\n'.format(response)
                        sys.stderr.write(err_message)
                        return 2, response
                    else:
                        fails = int(match.group(1))
                        if fails > 0:
                            if self.verbose is True:
                                err_message = u'Failures reported by zabbix when sending:\n{0}\n'.format(mydata)
                                sys.stderr.write(err_message)
                            return 1, response
                    return 0, response
            
                def bulk_send(self):
                    data = self.build_all()
                    result = self.send(data)
                    return result
            
                def iter_send(self):
                    retarray = []
                    for i in self.list:
                        (retcode, retstring) = self.send(self.build_single(i))
                        retarray.append((retcode, i))
                    return retarray
            
            
            # ####################################
            # --- Examples of usage ---
            #####################################
            #
            # Initiating a Zsend object -
            # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
            # z = ZSend(verbose=True) # Prints all sending failures to stderr
            # z = ZSend(server="172.0.0.100",verbose=True)
            # z = ZSend(server="zabbix-server",port=10051)
            # z = ZSend("zabbix-server", 10051)
            #
            
            # --- Adding data to send later ---
            # Host, Key, Value are all necessary
            # z.add_data("host","cpu.ready","12")
            #
            # Optionally you can provide a specific timestamp for the sample
            # z.add_data("host","cpu.ready","13",1365787627)
            #
            # If you provide no timestamp, the initialization time of the class
            # is used.
            
            # --- Printing values ---
            # Not that useful, but if you would like to see your data in tuple form
            # with assumed timestamps
            # z.print_vals()
            
            # --- Building well formatted data to send ---
            # You can send all of the data in one batch -
            # z.build_all() will return a string of packaged data ready to send
            # z.build_single((host,key,value,timestamp)) will return a packaged single
            
            # --- Sending data manually ---
            # Typical example 1 - build all the data and send it in one batch -
            #
            # z.send(z.build_all())
            #
            # Alternate example - build the data individually and send it one by one
            # so that we can see errors for anything that doesnt send properly -
            #
            # for i in z.list:
            #    (code,ret) = z.send(z.build_single(i))
            #    if code == 1:
            #       print "Problem during send!\n%s" % ret
            #    elif code == 0:
            #       print ret
            #
            # --- Sending data with built in functions ---
            #
            # Sending everything at once, with no concern about
            # individual item failure -
            #
            # (retcode,retstring) = z.bulk_send()
            # print "Result: %s -> %s" % (str(retcode),retstring)
            #
            # Sending every item individually so that we can capture
            # success or failure
            #
            # results = z.iter_send()
            # for (code,data) in results:
            #   (h,k,v,t) = data
            #   if code == 1:
            #      print "Failed to update key: %s for host: %s" % (k,h)
            #
            #
            #####################################
            # Mini example of a working program #
            #####################################
            #
            # import sys
            # sys.path.append("/path/to/Zsend.py")
            # from ZSend import ZSend
            #
            # z = ZabbixSender() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
            # z.add_data("host1","cpu.ready","12")
            # z.add_data("host1","cpu.ready","13",1366033479)
            # z.print_vals()
            #
            # results = z.iter_send()
            # for (code,data) in results:
            #   (h,k,v,t) = data
            #   if code == 1:
            #      print "Failed to update key: %s for host: %s" % (k,h)
            #
            #####################################

            Comment

            • guorui
              Junior Member
              • Aug 2014
              • 1

              #7
              Great ! Maybe I will write a java version zabbix_sender.

              Originally posted by raymanfu
              I am not really that bothered, but the base of the code was thanks to this wonderful post - https://www.zabbix.com/forum/showthread.php?p=90132. Enrico Tröger's prefered license appears to be GNU GPLv2.

              I have updated the code a little to add some functionality and generally simplify usage. Please refer to the example code in the comments at the end for usage.

              Code:
              #! /usr/bin/python
              # Copyright 2013 Rob Cherry <zsend(at)lxrb(dot)com>
              # Based on work by Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
              # License: GNU GPLv2
              
              import socket
              import struct
              import json
              import os
              import time
              import sys
              import re
              
              ZABBIX_SERVER="127.0.0.1"
              ZABBIX_PORT=10051
              
              class ZSend:
                 def __init__(self, server=ZABBIX_SERVER, port=ZABBIX_PORT, verbose=False):
                    self.zserver = server
                    self.zport = port
                    self.verbose = verbose
                    self.list = []
                    self.inittime = int(round(time.time()))
                    self.header = '''ZBXD\1%s%s'''
                    self.datastruct = '''
              { "host":"%s",
                "key":"%s",
                "value":"%s",
                "clock":%s }'''
              
                 def add_data(self,host,key,value,evt_time=None):
                    if evt_time is None:
                       evt_time = self.inittime
                    self.list.append((host,key,value,evt_time))
              
                 def print_vals(self):
                    for (h,k,v,t) in self.list:
                       print "Host: %s, Key: %s, Value: %s, Event: %s" % (h,k,v,t)
              
                 def build_all(self):
                    tmpdata = "{\"request\":\"sender data\",\"data\":["
                    count = 0
                    for (h,k,v,t) in self.list:
                       tmpdata = tmpdata + self.datastruct % (h,k,v,t)
                       count += 1
                       if count < len(self.list):
                          tmpdata = tmpdata + ","
                    tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
                    return (tmpdata)
              
                 def build_single(self,dataset):
                    tmpdata = "{\"request\":\"sender data\",\"data\":["
                    (h,k,v,t) = dataset
                    tmpdata = tmpdata + self.datastruct % (h,k,v,t)
                    tmpdata = tmpdata + "], \"clock\":%s}" % self.inittime
                    return (tmpdata)
              
                 def send(self,mydata):
                    socket.setdefaulttimeout(5)
                    data_length = len(mydata)
                    data_header = struct.pack('i', data_length) + '\0\0\0\0'
                    data_to_send = self.header % (data_header, mydata)
                    try:
                       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                       sock.connect((self.zserver,self.zport))
                       sock.send(data_to_send)
                    except Exception as err:
                       sys.stderr.write("Error talking to server: %s\n" % err)
                       return (255,err)
              
                    response_header = sock.recv(5)
                    if not response_header == 'ZBXD\1':
                       sys.stderr.write("Invalid response from server." + \
                                        "Malformed data?\n---\n%s\n---\n" % mydata)
                       return (254,err)
                    response_data_header = sock.recv(8)
                    response_data_header = response_data_header[:4]
                    response_len = struct.unpack('i', response_data_header)[0]
                    response_raw = sock.recv(response_len)
                    sock.close()
                    response = json.loads(response_raw)
                    match = re.match("^.*Failed\s(\d+)\s.*$",str(response))
                    if match is None:
                       sys.stderr.write("Unable to parse server response - " + \
                                        "\n%s\n" % response)
                    else:
                       fails = int(match.group(1))
                       if fails > 0:
                          if self.verbose is True:
                             sys.stderr.write("Failures reported by zabbix when sending:" + \
                                              "\n%s\n" % mydata)
                          return (1,response)
                    return (0,response)
              
                 def bulk_send(self):
                    data = self.build_all()
                    result = self.send(data)
                    return result
              
                 def iter_send(self):
                    retarray = []
                    for i in self.list:
                       (retcode,retstring) = self.send(self.build_single(i))
                       retarray.append((retcode,i))
                    return retarray
              
              
              #####################################
              # --- Examples of usage ---
              #####################################
              #
              # Initiating a Zsend object -
              # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
              # z = ZSend(verbose=True) # Prints all sending failures to stderr
              # z = ZSend(server="172.0.0.100",verbose=True)
              # z = ZSend(server="zabbix-server",port="10051")
              # z = ZSend("zabbix-server","10051")
              #
              
              # --- Adding data to send later ---
              # Host, Key, Value are all necessary
              # z.add_data("host","cpu.ready","12")
              #
              # Optionally you can provide a specific timestamp for the sample
              # z.add_data("host","cpu.ready","13","1365787627")
              #
              # If you provide no timestamp, the initialization time of the class
              # is used.
              
              # --- Printing values ---
              # Not that useful, but if you would like to see your data in tuple form
              # with assumed timestamps
              # z.print_vals()
              
              # --- Building well formatted data to send ---
              # You can send all of the data in one batch -
              # z.build_all() will return a string of packaged data ready to send
              # z.build_single((host,key,value,timestamp)) will return a packaged single
              
              # --- Sending data manually ---
              # Typical example 1 - build all the data and send it in one batch -
              #
              # z.send(z.build_all())
              #
              # Alternate example - build the data individually and send it one by one
              # so that we can see errors for anything that doesnt send properly -
              #
              # for i in z.list:
              #    (code,ret) = z.send(z.build_single(i))
              #    if code == 1:
              #       print "Problem during send!\n%s" % ret
              #    elif code == 0:
              #       print ret
              #
              # --- Sending data with built in functions ---
              #
              # Sending everything at once, with no concern about
              # individual item failure -
              #
              # (retcode,retstring) = z.bulk_send()
              # print "Result: %s -> %s" % (str(retcode),retstring)
              #
              # Sending every item individually so that we can capture
              # success or failure
              #
              # results = z.iter_send()
              # for (code,data) in results:
              #   (h,k,v,t) = data
              #   if code == 1:
              #      print "Failed to update key: %s for host: %s" % (k,h)
              #
              #
              #####################################
              # Mini example of a working program #
              #####################################
              #
              # import sys
              # sys.path.append("/path/to/Zsend.py")
              # from ZSend import ZSend
              #
              # z = ZSend() # Defaults to using ZABBIX_SERVER,ZABBIX_PORT
              # z.add_data("host1","cpu.ready","12")
              # z.add_data("host1","cpu.ready","13",1366033479)
              # z.print_vals()
              #
              # results = z.iter_send()
              # for (code,data) in results:
              #   (h,k,v,t) = data
              #   if code == 1:
              #      print "Failed to update key: %s for host: %s" % (k,h)
              #
              #####################################

              Comment

              • kmomberg
                Junior Member
                • Oct 2013
                • 3

                #8
                New version on GitHub

                I took what you guys created, and did some changes according to my needs. Now you can download the "pyZabbixSender" module from GitHub:

                Python implementation of zabbix_sender. Contribute to kmomberg/pyZabbixSender development by creating an account on GitHub.


                Thanks for the base you provided, as it was very important to allow me creating this.

                I tested the module under python 2.5.1 and python 2.7
                Python 2.5 don't include json, so you can use simplejson instead.

                Hope this help new visitors as it helped me .

                Comment

                • BDiE8VNy
                  Senior Member
                  • Apr 2010
                  • 680

                  #9
                  What's the difference of using py-zabbix?

                  Comment

                  • kmomberg
                    Junior Member
                    • Oct 2013
                    • 3

                    #10
                    I can mention two differences that are important, at least for me:
                    1. Its compatibility with Python 2.5 as I have systems still using that version of python (here you need to use simplejson)
                    2. The possibility to automatically split data packet before sending it to the server, allowing you to use slow connections, where a big packet can end in a socket timeout.


                    Another worth to mention difference, is the possibility to debug your data flow using the "sendDataOneByOne" method, that allows you to identify any misspelled trap or host name with easy.

                    Hope this help

                    Comment

                    • BDiE8VNy
                      Senior Member
                      • Apr 2010
                      • 680

                      #11
                      Well, then how about adding it to Docs/api/libraries on zabbix.org?

                      Comment

                      • kmomberg
                        Junior Member
                        • Oct 2013
                        • 3

                        #12
                        Done

                        I added an entry at https://www.zabbix.org/wiki/Docs/api/libraries as sugested.

                        I also improved documentation on gitHub's wiki for the project (I was waiting this to be completed before include the link)

                        Comment

                        Working...