Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ Other ``gelf_chunker`` options are also available:
to send some content to Graylog. If this process fails to prevent
another chunk overflow a ``GELFTruncationFailureWarning`` is issued.

DNS Caching
^^^^^^^^^^^^

``GELFUDPHandler`` reuses the same socket to minimize DNS lookups (if required
to resolve the provided host) and system resources. It will re-resolve
every 5 minutes by default but you can override this using the ``sock_max_age``
argument:

.. code-block:: python

handler = graypy.GELFUDPHandler('example.com', 12201, sock_max_age=3600) # 1 hour


RabbitMQ Logging
----------------

Expand Down
34 changes: 31 additions & 3 deletions graypy/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ssl
import struct
import sys
import time
import traceback
import zlib
from logging.handlers import DatagramHandler, SocketHandler
Expand Down Expand Up @@ -583,7 +584,7 @@ def chunk_message(self, message):
class GELFUDPHandler(BaseGELFHandler, DatagramHandler):
"""GELF UDP handler"""

def __init__(self, host, port=12202, gelf_chunker=GELFWarningChunker(), **kwargs):
def __init__(self, host, port=12202, gelf_chunker=GELFWarningChunker(), sock_max_age=300, **kwargs):
"""Initialize the GELFUDPHandler

.. note::
Expand All @@ -601,17 +602,44 @@ def __init__(self, host, port=12202, gelf_chunker=GELFWarningChunker(), **kwargs
:param gelf_chunker: :class:`.handler.BaseGELFChunker` instance to
handle chunking larger GELF messages.
:type gelf_chunker: GELFWarningChunker

:param sock_max_age: time in seconds to reuse the same socket before
making a new one.
:type sock_max_age: int
"""
BaseGELFHandler.__init__(self, **kwargs)
DatagramHandler.__init__(self, host, port)
self.gelf_chunker = gelf_chunker
self.sock_max_age = sock_max_age
self.sock_expire_time = None

def makeSocket(self):
self.sock_expire_time = time.monotonic() + self.sock_max_age
sock = super().makeSocket()
sock.connect(self.address) # Performing a DNS lookup (if needed) and opening a socket here.
return sock

def send_chunk(self, s):
if self.sock is None:
self.createSocket()
if time.monotonic() > self.sock_expire_time:
# Creating a new socket if we're past our expire time: to handle DNS changes, etc...
self.sock.close()
self.createSocket()

if self.sock:
try:
self.sock.sendall(s)
except OSError:
self.sock.close()
self.sock = None # so we can call createSocket next time

def send(self, s):
if len(s) < self.gelf_chunker.chunk_size:
super(GELFUDPHandler, self).send(s)
self.send_chunk(s)
else:
for chunk in self.gelf_chunker.chunk_message(s):
super(GELFUDPHandler, self).send(chunk)
self.send_chunk(chunk)


class GELFTCPHandler(BaseGELFHandler, SocketHandler):
Expand Down