]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/log.py
Merge pull request #118 from svenauhagen/feature/offload
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / log.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2016-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Julien Fortin, julien@cumulusnetworks.com
5 #
6
7 import sys
8 import json
9 import struct
10 import select
11 import logging
12 import logging.handlers
13
14 from cStringIO import StringIO
15
16
17 class Log:
18 LOGGER_NAME = sys.argv[0].split('/')[-1]
19
20 def __init__(self):
21 """
22 - On start the daemon will log on syslog.
23 - For each client commands we might need to adjust the target
24 (stderr/stdout):
25 if -v --verbose or -d --debug are provided we override
26 sys.stdout and sys.stderr with string buffers to be able to send
27 back the content of these buffer on the UNIX socket back to the
28 client.
29 if -l or --syslog we make sure to use syslog.
30 """
31
32 self.stdout_buffer = None
33 self.stderr_buffer = None
34
35 self.root = logging.getLogger()
36 self.root.name = Log.LOGGER_NAME
37 self.root.setLevel(logging.INFO)
38
39 self.root_info = self.root.info
40 self.root_debug = self.root.debug
41 self.root_error = self.root.error
42 self.root_warning = self.root.warning
43 self.root_critical = self.root.critical
44
45 self.root.info = self.info
46 self.root.debug = self.debug
47 self.root.error = self.error
48 self.root.warning = self.warning
49 self.root.critical = self.critical
50
51 logging.addLevelName(logging.CRITICAL, 'critical')
52 logging.addLevelName(logging.WARNING, 'warning')
53 logging.addLevelName(logging.ERROR, 'error')
54 logging.addLevelName(logging.DEBUG, 'debug')
55 logging.addLevelName(logging.INFO, 'info')
56
57 self.syslog = True
58 self.socket = None
59
60 # syslog
61 facility = logging.handlers.SysLogHandler.LOG_DAEMON
62 address = '/dev/log'
63 format = '%(name)s: %(levelname)s: %(message)s'
64
65 try:
66 self.syslog_handler = logging.handlers.SysLogHandler(address=address, facility=facility)
67 self.syslog_handler.setFormatter(logging.Formatter(format))
68 except Exception as e:
69 sys.stderr.write("warning: syslogs: %s\n" % str(e))
70 self.syslog_handler = None
71
72 # console
73 format = '%(levelname)s: %(message)s'
74 self.console_handler = logging.StreamHandler(sys.stderr)
75 self.console_handler.setFormatter(logging.Formatter(format))
76
77 if self.syslog_handler and self.LOGGER_NAME[-1] == 'd':
78 self.update_current_logger(syslog=True, verbose=True, debug=False)
79 else:
80 self.update_current_logger(syslog=False, verbose=False, debug=False)
81
82 def update_current_logger(self, syslog, verbose, debug):
83 self.syslog = syslog
84 self.root.setLevel(self.get_log_level(verbose=verbose, debug=debug))
85 self.root.handlers = [self.syslog_handler if self.syslog and self.syslog_handler else self.console_handler]
86 self.flush()
87
88 def flush(self):
89 if self.socket:
90 result = dict()
91 stdout = self._flush_buffer('stdout', self.stdout_buffer, result)
92 stderr = self._flush_buffer('stderr', self.stderr_buffer, result)
93 if stdout or stderr:
94 try:
95 self.tx_data(json.dumps(result))
96 self.redirect_stdouput()
97 except select.error as e:
98 # haven't seen the case yet
99 self.socket = None
100 self.update_current_logger(syslog=True, verbose=True)
101 self.critical(str(e))
102 exit(84)
103 self.console_handler.flush()
104
105 if self.syslog_handler:
106 self.syslog_handler.flush()
107
108 def tx_data(self, data, socket=None):
109 socket_obj = socket if socket else self.socket
110 ready = select.select([], [socket_obj], [])
111 if ready and ready[1] and ready[1][0] == socket_obj:
112 frmt = "=%ds" % len(data)
113 packed_msg = struct.pack(frmt, data)
114 packed_hdr = struct.pack('=I', len(packed_msg))
115 socket_obj.sendall(packed_hdr)
116 socket_obj.sendall(packed_msg)
117
118 def set_socket(self, socket):
119 self.socket = socket
120 self.redirect_stdouput()
121
122 def redirect_stdouput(self):
123 self.stdout_buffer = sys.stdout = StringIO()
124 self.stderr_buffer = self.console_handler.stream = sys.stderr = StringIO()
125
126 def error(self, msg, *args, **kwargs):
127 self.root_error(msg, *args, **kwargs)
128 self.flush()
129
130 def critical(self, msg, *args, **kwargs):
131 self.root_critical(msg, *args, **kwargs)
132 self.flush()
133
134 def warning(self, msg, *args, **kwargs):
135 self.root_warning(msg, *args, **kwargs)
136 self.flush()
137
138 def info(self, msg, *args, **kwargs):
139 self.root_info(msg, *args, **kwargs)
140 self.flush()
141
142 def debug(self, msg, *args, **kwargs):
143 self.root_debug(msg, *args, **kwargs)
144 self.flush()
145
146 def get_current_log_level(self):
147 return self.root.level
148
149 def is_syslog(self): return self.syslog
150
151 @staticmethod
152 def get_log_level(verbose=False, debug=False):
153 log_level = logging.WARNING
154 if debug:
155 log_level = logging.DEBUG
156 elif verbose:
157 log_level = logging.INFO
158 return log_level
159
160 @staticmethod
161 def _flush_buffer(stream, buff, dictionary):
162 if buff:
163 data = buff.getvalue()
164 if data:
165 dictionary[stream] = data
166 return True
167
168
169 log = Log()