forked from fluent/fluent-logger-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhandler.py
More file actions
117 lines (95 loc) · 3.44 KB
/
handler.py
File metadata and controls
117 lines (95 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# -*- coding: utf-8 -*-
import logging
import socket
import sys
try:
import simplejson as json
except ImportError: # pragma: no cover
import json
try:
basestring
except NameError: # pragma: no cover
basestring = (str, bytes)
from fluent import sender
class FluentRecordFormatter(logging.Formatter, object):
""" A structured formatter for Fluent.
Best used with server storing data in an ElasticSearch cluster for example.
:param fmt: a dict with format string as values to map to provided keys.
"""
def __init__(self, fmt=None, datefmt=None):
super(FluentRecordFormatter, self).__init__(None, datefmt)
if not fmt:
self._fmt_dict = {
'sys_host': '%(hostname)s',
'sys_name': '%(name)s',
'sys_module': '%(module)s',
}
else:
self._fmt_dict = fmt
self.hostname = socket.gethostname()
def format(self, record):
# Only needed for python2.6
if sys.version_info[0:2] <= (2, 6) and self.usesTime():
record.asctime = self.formatTime(record, self.datefmt)
# Compute attributes handled by parent class.
super(FluentRecordFormatter, self).format(record)
# Add ours
record.hostname = self.hostname
# Apply format
data = dict([(key, value % record.__dict__)
for key, value in self._fmt_dict.items()])
self._structuring(data, record.msg)
return data
def usesTime(self):
return any([value.find('%(asctime)') >= 0
for value in self._fmt_dict.values()])
def _structuring(self, data, msg):
""" Melds `msg` into `data`.
:param data: dictionary to be sent to fluent server
:param msg: :class:`LogRecord`'s message to add to `data`.
`msg` can be a simple string for backward compatibility with
:mod:`logging` framework, a JSON encoded string or a dictionary
that will be merged into dictionary generated in :meth:`format.
"""
if isinstance(msg, dict):
self._add_dic(data, msg)
elif isinstance(msg, basestring):
try:
self._add_dic(data, json.loads(str(msg)))
except ValueError:
self._add_dic(data, {'message': msg})
else:
self._add_dic(data, {'message': msg})
@staticmethod
def _add_dic(data, dic):
for key, value in dic.items():
if isinstance(key, basestring):
data[str(key)] = value
class FluentHandler(logging.Handler):
'''
Logging Handler for fluent.
'''
def __init__(self,
tag,
host='localhost',
port=24224,
timeout=3.0,
verbose=False,
name_as_label=True):
self.tag = tag
self.name_as_label = name_as_label
self.sender = sender.FluentSender(tag,
host=host, port=port,
timeout=timeout, verbose=verbose)
logging.Handler.__init__(self)
def emit(self, record):
data = self.format(record)
label = record.name if self.name_as_label else None
self.sender.emit(label, data)
def close(self):
self.acquire()
try:
self.sender._close()
logging.Handler.close(self)
finally:
self.release()