Skip to content

Commit d09201b

Browse files
author
Vladimir Klochan
committed
Initial version.
1 parent 1720d0e commit d09201b

3 files changed

Lines changed: 109 additions & 0 deletions

File tree

logstash/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from handler import LogstashHandler

logstash/handler.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import json
2+
import traceback
3+
import socket
4+
from logging.handlers import DatagramHandler
5+
from datetime import datetime
6+
7+
8+
class LogstashHandler(DatagramHandler):
9+
"""Python logging handler for Logstash
10+
:param host: The host of the logstash server.
11+
:param port: The port of the logstash server (default 5959).
12+
:param message_type: The type of the message (default logstash).
13+
:param fqdn; Indicates whether to show fully qualified domain name or not (default False).
14+
"""
15+
16+
def __init__(self, host, port=5959, message_type='logstash', fqdn=False):
17+
self.message_type = message_type
18+
self.fqdn = fqdn
19+
DatagramHandler.__init__(self, host, port)
20+
21+
def makePickle(self, record):
22+
message_dict = self.build_message(record)
23+
return json.dumps(message_dict)
24+
25+
def build_message(self, record):
26+
add_debug_info = False
27+
28+
if self.fqdn:
29+
host = socket.getfqdn()
30+
else:
31+
host = socket.gethostname()
32+
33+
message_dict = {
34+
'@fields': {
35+
'levelname': record.levelname,
36+
'logger': record.name,
37+
},
38+
'@message': record.getMessage(),
39+
'@source': host,
40+
'@tags': [],
41+
'@timestamp': self.format_timestamp(record.created),
42+
'@type': self.message_type,
43+
}
44+
45+
if record.exc_info:
46+
add_debug_info = True
47+
self.add_message_field(message_dict, 'exc_info', self.format_exception(record.exc_info))
48+
49+
if add_debug_info:
50+
self.add_message_field(message_dict, 'pathname', record.pathname)
51+
self.add_message_field(message_dict, 'lineno', record.lineno)
52+
self.add_message_field(message_dict, 'process', record.process)
53+
self.add_message_field(message_dict, 'threadName', record.threadName)
54+
self.add_message_field(message_dict, 'lineno', record.lineno)
55+
# funName was added in 2.5
56+
if not getattr(record, 'funcName', None):
57+
self.add_message_field(message_dict, 'funcName', record.funcName)
58+
# processName was added in 2.6
59+
if not getattr(record, 'processName', None):
60+
self.add_message_field(message_dict, 'processName', record.processName)
61+
62+
message_dict = self.add_extra_fields(message_dict, record)
63+
64+
return message_dict
65+
66+
def add_message_field(self, message_dict, key, value):
67+
message_dict['@fields'][key] = repr(value)
68+
69+
def add_extra_fields(self, message_dict, record):
70+
# The list contains all the attributes listed in
71+
# http://docs.python.org/library/logging.html#logrecord-attributes
72+
skip_list = (
73+
'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
74+
'funcName', 'id', 'levelname', 'levelno', 'lineno', 'module',
75+
'msecs', 'msecs', 'message', 'msg', 'name', 'pathname', 'process',
76+
'processName', 'relativeCreated', 'thread', 'threadName')
77+
78+
for key, value in record.__dict__.items():
79+
if key not in skip_list:
80+
self.add_message_field(message_dict, key, value)
81+
82+
return message_dict
83+
84+
def format_exception(self, exc_info):
85+
return '\n'.join(traceback.format_exception(*exc_info)) if exc_info else ''
86+
87+
def format_timestamp(self, time):
88+
return datetime.utcfromtimestamp(time).isoformat()

setup.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from distutils.core import setup
2+
setup(
3+
name='python-logstash',
4+
packages=['logstash'],
5+
version='0.1.1',
6+
description='Python logging handler for Logstash.',
7+
author='Vladimir Klochan',
8+
author_email='vklochan@gmail.com',
9+
url='https://github.com/vklochan/python-logstash',
10+
classifiers=[
11+
'Development Status :: 4 - Beta',
12+
'Intended Audience :: Developers',
13+
'License :: Freeware',
14+
'Operating System :: OS Independent',
15+
'Programming Language :: Python',
16+
'Topic :: Internet :: WWW/HTTP',
17+
'Topic :: Software Development :: Libraries :: Python Modules',
18+
'Topic :: System :: Logging',
19+
]
20+
)

0 commit comments

Comments
 (0)