Unable to get >1000 events from API query
Subject: |
Unable to get >1000 events from API query |
Author: |
Austin Culbertson |
Posted: |
2018-10-30 18:10 |
I'm unable to get more than 1000 events from an API query at a time. Is this a hard-limit in the source code, a bug, or am I doing something wrong? I'm wondering if perhaps I need to index my events and then iteratively grab the NEXT batch of 1000 events after the events I've received. The API documentation doesn't seem to cover this scenario, however (imagine that).
Here is the important information:
API Core:
import urllib
import urllib2
import json
import sys, getopt
ROUTERS = { 'MessagingRouter': 'messaging',
'EventsRouter': 'evconsole',
'ProcessRouter': 'process',
'ServiceRouter': 'service',
'DeviceRouter': 'device',
'NetworkRouter': 'network',
'TemplateRouter': 'template',
'DetailNavRouter': 'detailnav',
'ReportRouter': 'report',
'MibRouter': 'mib',
'ZenPackRouter': 'zenpack' }
class ZenossAPIUnsuccessful(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class ZenossAPI():
def __init__(self, debug=False, **kwargs):
self.ZENOSS_USERNAME = kwargs['ZENOSS_USERNAME']
self.ZENOSS_PASSWORD = kwargs['ZENOSS_PASSWORD']
self.ZENOSS_INSTANCE = kwargs['ZENOSS_INSTANCE']
"""
Initialize the API connection, log in, and store authentication cookie
"""
self.urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
if debug: self.urlOpener.add_handler(urllib2.HTTPHandler(debuglevel=1))
self.reqCount = 1
loginParams = urllib.urlencode(dict(
__ac_name = self.ZENOSS_USERNAME,
__ac_password = self.ZENOSS_PASSWORD,
submitted = 'true',
came_from = self.ZENOSS_INSTANCE + '/zport/dmd'))
self.urlOpener.open(self.ZENOSS_INSTANCE + '/zport/acl_users/cookieAuthHelper/login',
loginParams)
def _router_request(self, router, method, data=[]):
if router not in ROUTERS:
raise Exception('Router "' + router + '" not available.')
req = urllib2.Request(self.ZENOSS_INSTANCE + '/zport/dmd/' +
ROUTERS[router] + '_router')
req.add_header('Content-type', 'application/json; charset=utf-8')
reqData = json.dumps([dict(
action=router,
method=method,
data=data,
type='rpc',
tid=self.reqCount)])
self.reqCount += 1
return json.loads(self.urlOpener.open(req, reqData).read())
def create_event_on_device(self, device, summary, severity, component, evclasskey, evclass):
if severity not in ('Critical', 'Error', 'Warning', 'Info', 'Debug', 'Clear'):
raise Exception('Severity "' + severity +'" is not valid.')
data = dict(device=device, summary=summary, severity=severity,
component=component, evclasskey=evclasskey, evclass=evclass)
return self._router_request('EventsRouter', 'add_event', [data])
def query_events(self, limit=0, start=0, sort='lastTime', dir='desc', params=None, exclusion_filter=None, keys=None, page=None, archive=False, uid=None, detailFormat=False):
data = dict(page=page, limit=limit, start=start,
sort=sort, dir=dir, params=params, exclusion_filter=exclusion_filter,
keys=keys, uid=uid, detailFormat=detailFormat, archive=archive)
return self._router_request('EventsRouter', 'query', [data])
queryEvents Script (using API)
import json
from ZenossAPIPack.ZenossAPI import ZenossAPI
from ZenossAPIPack.ZenossAPI import ZenossAPIUnsuccessful
import time
status = {
"New": 0,
"Ackd": 1,
"Suppressed": 2,
"Closed": 3,
"Cleared": 4,
"Dropped": 5,
"Aged" : 6
}
severities = {
0: "Clear",
1: "Debug",
2: "Info",
3: "Warning",
4: "Error",
5: "Critical"
}
ZENOSS_INSTANCE = "http://<labIp>:8080"
ZENOSS_USERNAME = "
ZENOSS_PASSWORD = "
kwargs = {"ZENOSS_INSTANCE": ZENOSS_INSTANCE,
"ZENOSS_USERNAME": ZENOSS_USERNAME,
"ZENOSS_PASSWORD": ZENOSS_PASSWORD}
z = ZenossAPI(**kwargs)
def write_event_results(results, file): <snip>
current_query_params = {
"limit": 9999,
"params": {"eventState": [0,1,2,3,4,5], "firstTime": "2018-10-01 00:00:00"}
}
arch_query_params = {
"limit": 9999,
"params": {"eventState": [0,1,2,3,4,5], "firstTime": "2018-10-01 00:00:00"},
"archive": True
}
query_results = z.query_events(**current_query_params)
print "Total Console Events: " + str(query_results['result']['totalCount'])
print "Total Console Events in Results: " + str(len(query_results['result']['events']))
event_results = query_results['result']['events']
write_event_results(event_results, file)
query_results = ''
event_results = ''
query_results = z.query_events(**arch_query_params)
print "Total Archived Events: " + str(query_results['result']['totalCount'])
print "Total Archived Events in Results: " + str(len(query_results['result']['events']))
write_event_results(event_results, file)
Output of command:
[aculbertson@zenoss-01.lab1 zenossAPI]$ ./queryEvents.py
Total Console Events: 26437
Total Console Events in Results: 1000
Total Archived Events: 64801
Total Archived Events in Results: 1000
------------------------------
Austin Culbertson
NOC Monitoring Engineer
------------------------------
Subject: |
RE: Unable to get >1000 events from API query |
Author: |
Jane Curry |
Posted: |
2018-10-31 06:36 |
The problem is that the limit parameter is hardcoded in the Zenoss code to 1000. If you want more than that, you need to cycle throught the total number of events, 1000 at a time. In the following code, l is the limit parameter.
if type(l) != str:
l = 1000
else:
l=int(l)
events = getEventsWithJSON()
pp = pprint.PrettyPrinter(indent=4)
fields = ['eventState', 'DeviceClass', 'count', 'device', 'Location', 'Systems', 'severity', 'firstTime', 'lastTime', 'summary']
print 'Summary events \n'
print 'eventState, DeviceClass, count, device, Location, Systems, severity, firstTime, lastTime, summary \n'
sumout = events.get_events(filter=option_dict, sort=s, dir=d, arch=False, lim=l)
#print 'sumout is %s \n' % (sumout)
print 'Length of sumout is %s\n' % (len(sumout['events']))
if l > 1000:
# Zenoss only returns 1000 events even if limit > 1000 so need to cycle
cycles = min(sumout['totalCount'] / 1000 + 1 , l / 1000 + 1 )
cyclelim=1000
for c in range(0,cycles):
print "On cycle %d of %d" % (c,cycles)
print 'cyclelim is %s \n' % (cyclelim)
cycle_count = c * 1000 #use the batches of 1000 to set the offset for each iteration
sumoutchunk = events.get_events(filter=option_dict, sort=s, dir=d, arch=False, lim=cyclelim, start=cycle_count)
#print 'Length of sumout is %s\n' % (len(sumoutchunk['events']))
printEvents(sumoutchunk)
cyclelim = min((1000, (l - (c + 1) *1000))
else:
printEvents(sumout)
Cheers,
Jane
------------------------------
Jane Curry
Skills 1st United Kingdom
jane.curry@skills-1st.co.uk
------------------------------
Subject: |
RE: Unable to get >1000 events from API query |
Author: |
Austin Culbertson |
Posted: |
2018-10-31 11:37 |
Thank you so much, Jane! This answers my question perfectly. What would Zenoss do without you :)
------------------------------
Austin Culbertson
NOC Monitoring Engineer
------------------------------
Subject: |
RE: Unable to get >1000 events from API query |
Author: |
Steve Aiello |
Posted: |
2018-10-31 11:33 |
I see you are already using an API library, an alternative would be the
ZenApiLib. This has a built-in method to deal with paged API methods that returns a generator object that can be iterated over.
Example Output:
Total Console Events: 427
Total Console Events in Results: 427
Total Archived Events: 67722
Total Archived Events in Results: 67722
Example Code:
import zenApiLib
evtRouter = zenApiLib.zenConnector(routerName = 'EventsRouter')
evtRouter.config['timeout'] = 45
current_query_params = {
"limit": 1000,
"params": {"eventState": [0,1,2,3,4,5], "firstTime": "2018-10-01 00:00:00"}
}
arch_query_params = {
"limit": 1000,
"params": {"eventState": [0,1,2,3,4,5], "firstTime": "2018-10-01 00:00:00"},
"archive": True
}
event_results = []
for pagedResults in evtRouter.pagingMethodCall('query', **current_query_params):
if not pagedResults['result']['success']:
raise Exception(pagedResults['msg'])
for event in pagedResults['result']['events']:
pass
event_results += pagedResults['result']['events']
print "Total Console Events: {}".format(pagedResults['result']['totalCount'])
print "Total Console Events in Results: {}".format(len(event_results))
event_results = []
for pagedResults in evtRouter.pagingMethodCall('query', **arch_query_params):
if not pagedResults['result']['success']:
raise Exception(pagedResults['msg'])
for event in pagedResults['result']['events']:
pass
event_results += pagedResults['result']['events']
print "Total Archived Events: {}".format(pagedResults['result']['totalCount'])
print "Total Archived Events in Results: {}".format(len(event_results))
------------------------------
Steve Aiello
Zenoss
------------------------------