import logging
import json
import zlib
import traceback
import struct
import random
import socket
from logging.handlers import DatagramHandler


WAN_CHUNK, LAN_CHUNK = 1420, 8154


class GELFHandler(DatagramHandler):
    def __init__(self, host, port, chunk_size=WAN_CHUNK):
        self.chunk_size = chunk_size
        DatagramHandler.__init__(self, host, port)

    def send(self, s):
        if len(s) < self.chunk_size:
            DatagramHandler.send(self, s)
        else:
            for chunk in ChunkedGELF(s, self.chunk_size):
                DatagramHandler.send(self, chunk)

    def makePickle(self, record):
        message_dict = self.make_message_dict(record)
        return zlib.compress(json.dumps(message_dict))

    def convert_level_to_syslog(self, level):
        return {
            logging.CRITICAL: 2,
            logging.ERROR: 3,
            logging.WARNING: 4,
            logging.INFO: 6,
            logging.DEBUG: 7,
        }.get(level, level)

    def get_full_message(self, exc_info):
        return traceback.format_exc(exc_info) if exc_info else ''

    def make_message_dict(self, record):
        return self.add_extra_fields({
            'version': "1.0",
            'host': socket.gethostname(),
            'short_message': record.getMessage(),
            'full_message': self.get_full_message(record.exc_info),
            'timestamp': record.created,
            'level': self.convert_level_to_syslog(record.levelno),
            'facility': record.name,
            'file': record.pathname,
            'line': record.lineno,
            '_function': record.funcName,
            '_pid': record.process,
            '_thread_name': record.threadName,
        }, record)

    def add_extra_fields(self, message_dict, record):
        # record.processName was added in Python 2.6.2
        pn = getattr(record, 'processName', None)
        if pn is not None:
            message_dict['_process_name'] = pn

        # skip_list is used to filter additional fields in a log message.
        # It contains all attributes listed in
        # http://docs.python.org/library/logging.html#logrecord-attributes
        # plus exc_text, which is only found in the logging module source,
        # and id, which is prohibited by the GELF format.
        skip_list = (
            'args', 'asctime', 'created', 'exc_info',  'exc_text', 'filename',
            'funcName', 'id', 'levelname', 'levelno', 'lineno', 'module',
            'msecs', 'msecs', 'message', 'msg', 'name', 'pathname', 'process',
            'processName', 'relativeCreated', 'thread', 'threadName')

        for key, value in record.__dict__.items():
            if key not in skip_list and not key.startswith('_'):
                message_dict['_%s' % key] = value

        return message_dict


class ChunkedGELF(object):
    def __init__(self, message, size):
        self.message = message
        self.size = size
        self.pieces = struct.pack('>H', (len(message) / size) + 1)
        self.id = struct.pack('Q', random.randint(0, 0xFFFFFFFFFFFFFFFF)) * 4

    def message_chunks(self):
        return (self.message[i:i+self.size] for i
                    in range(0, len(self.message), self.size))

    def encode(self, sequence, chunk):
        return ''.join([
            '\x1e\x0f',
            self.id,
            struct.pack('>H', sequence),
            self.pieces,
            chunk
        ])

    def __iter__(self):
        for sequence, chunk in enumerate(self.message_chunks()):
            yield self.encode(sequence, chunk)

@@ -265,18 +265,90 @@
 AN_CHUNK
-):
+, debugging_fields=True):%0A        self.debugging_fields = debugging_fields
 %0A       
@@ -1206,51 +1206,18 @@
     
-return self.add_extra_fields(%7B%0A            
+fields = %7B
 'ver
@@ -1531,24 +1531,100 @@
 ecord.name,%0A
+        %7D%0A        if self.debugging_fields:%0A            fields.update(%7B%0A    
             
@@ -1660,16 +1660,20 @@
         
+    
 'line': 
@@ -1699,16 +1699,20 @@
         
+ 
+   
 '_functi
@@ -1745,16 +1745,20 @@
         
+    
 '_pid': 
@@ -1785,16 +1785,20 @@
         
+  
+  
 '_thread
@@ -1836,74 +1836,19 @@
     
-%7D, record)%0A%0A    def add_extra_fields(self, message_dict, record):%0A
+    %7D)%0A    
     
@@ -1906,16 +1906,20 @@
         
+    
 pn = get
@@ -1952,16 +1952,20 @@
 , None)%0A
+    
         
@@ -1995,28 +1995,26 @@
         
-message_dict
+    fields
 %5B'_proce
@@ -2028,16 +2028,123 @@
 '%5D = pn%0A
+        return self.add_extra_fields(fields, record)%0A%0A    def add_extra_fields(self, message_dict, record):
 %0A       

Allow additional fields about logger usage to be disabled.