Source code for duct.outputs.elasticsearch
"""
.. module:: elasticsearch
:synopsis: Elasticsearch event output
.. moduleauthor:: Colin Alston <colin@tamvera.com>
"""
import asyncio
import datetime
import logging
from duct.protocol import elasticsearch
from duct.objects import Output
log = logging.getLogger(__name__)
[docs]
class ElasticSearch(Output):
"""ElasticSearch HTTP API output
:param url: Elasticsearch URL (default: http://localhost:9200)
:type url: str
:param maxsize: Maximum queue backlog size (default: 250000, 0 disables)
:type maxsize: int
:param maxrate: Maximum rate of documents added to index (default: 100)
:type maxrate: int
:param interval: Queue check interval in seconds (default: 1.0)
:type interval: int
:param user: Optional basic auth username
:type user: str
:param password: Optional basic auth password
:type password: str
:param index: Index name format (default: duct-%Y.%m.%d)
:type index: str
"""
def __init__(self, *a):
Output.__init__(self, *a)
self._tick_task = None
self.inter = float(self.config.get('interval', 1.0))
self.maxsize = int(self.config.get('maxsize', 250000))
self.user = self.config.get('user')
self.password = self.config.get('password')
self.url = self.config.get('url', 'http://localhost:9200')
self.index = self.config.get('index', 'duct-%Y.%m.%d')
maxrate = int(self.config.get('maxrate', 100))
self.queueDepth = int(maxrate * self.inter) if maxrate > 0 else None
self.client = None
[docs]
async def createClient(self):
"""Sets up HTTP connector and starts queue drain task"""
self.client = elasticsearch.ElasticSearch(
self.url, self.user, self.password, self.index)
self._tick_task = asyncio.create_task(self._drain_loop())
async def _drain_loop(self):
try:
while True:
await asyncio.sleep(self.inter)
await self._tick()
except asyncio.CancelledError:
pass
[docs]
async def stop(self):
if self._tick_task:
self._tick_task.cancel()
try:
await self._tick_task
except asyncio.CancelledError:
pass
[docs]
async def sendEvents(self, events):
"""Send events to Elasticsearch in bulk"""
return await self.client.bulkIndex(
[self.transformEvent(event) for event in events])
async def _tick(self):
if not self.events:
return
if self.queueDepth and len(self.events) > self.queueDepth:
events = self.events[:self.queueDepth]
self.events = self.events[self.queueDepth:]
else:
events = self.events
self.events = []
try:
result = await self.sendEvents(events)
if result.get('errors', False):
log.warning('Elasticsearch bulk error: %s', repr(result))
except Exception as ex:
log.warning('Could not connect to Elasticsearch: %s', ex)
self.events.extend(events)
# Backward compatibility
ElasticSearchLog = ElasticSearch