comparison lemuriformes/log.py @ 15:0d1b8bb1d97b

SQL + data related functionality
author Jeff Hammel <k0scist@gmail.com>
date Sun, 10 Dec 2017 17:16:52 -0800
parents
children
comparison
equal deleted inserted replaced
14:756dbd3e391e 15:0d1b8bb1d97b
1 """
2 ElasticSearch-style logging
3 """
4
5 import json
6 import sys
7 import time
8 from .cli import ConfigurationParser
9
10 stdout = sys.stdout
11
12 try:
13 # python 2
14 string = (str, unicode)
15 except NameError:
16 # python 3
17 string = (str, )
18
19
20 def read_logfile(f):
21 """
22 read a JSON-per-line log file's contents and return the value
23
24 f -- log file pointer or name
25 """
26
27 if isinstance(f, string):
28 with open(f) as _f:
29 return read_logfile(_f)
30 lines = f.read().strip().splitlines()
31 return [json.loads(line) for line in lines]
32
33
34 class ElasticLogger(object):
35 """Elasticsearch-compatible log dispatcher"""
36
37 def __init__(self, logfilepath=None, **data):
38 """
39 logfilepath -- path to logfile
40 data -- data to be included with each logging event
41 """
42
43 self.logfilepath = logfilepath
44 self.data = data
45
46 def write(self, f, **data):
47 """
48 write JSON `data` to file-like object `f`
49 """
50
51 f.write(json.dumps(data, sort_keys=True) + '\n')
52 f.flush()
53
54 def __call__(self, message, **kw):
55
56 # create log data JSON blob
57 now = time.time()
58 data = self.data.copy() # shallow copy
59 data.update({'time': now,
60 'message': message})
61 data.update(kw)
62
63 # log to stdout
64 self.write(stdout, **data)
65
66 if self.logfilepath:
67 # log to a file
68 with open(self.logfilepath, 'a') as logfile:
69 self.write(logfile, **data)
70
71
72 class ElasticLoggerParser(ConfigurationParser):
73
74 def add_arguments(self):
75 self.add_argument('-l', '--log', '--logfile', dest='logfile',
76 help="where to log events to in addition to stdout")
77 self.add_argument('--tag', dest='tags', nargs='+', default=(),
78 type=self.keyvalue, metavar="KEY=VALUE",
79 help="set of key, values to tag all log lines with")
80
81 def logger(self):
82 """return elastic logger instance"""
83
84 assert self.options is not None
85 return ElasticLogger(self.options.logfile,
86 **dict(self.options.tags))
87
88
89 def main(args=sys.argv[1:]):
90 """example CLI program"""
91
92 # parse command line
93 parser = ElasticLoggerParser(description="my elastic diary")
94 options = parser.parse_args()
95
96 # example: timestamped diary
97 logger = parser.logger()
98
99 # main loop
100 try:
101 while True:
102 logger(raw_input())
103 except KeyboardInterrupt:
104 pass
105
106
107 if __name__ == '__main__':
108 main()