2 """A very simple logger that tries to be concurrency-safe."""
10 LOG_FILE = '/var/log/nodemanager'
11 LOG_SLIVERS = '/var/lib/nodemanager/getslivers.txt'
12 LOG_DATABASE = '/var/lib/nodemanager/database.txt'
14 # basically define 3 levels
18 # default is to log a reasonable amount of stuff for when running on operational nodes
24 assert level in [LOG_NONE, LOG_NODE, LOG_VERBOSE]
27 logger.log("Failed to set LOG_LEVEL to %s" % level)
30 log('(v) ' + msg, LOG_VERBOSE)
32 def log(msg, level=LOG_NODE):
33 """Write <msg> to the log file if level >= current log level (default LOG_NODE)."""
37 fd = os.open(LOG_FILE, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600)
38 if not msg.endswith('\n'):
40 os.write(fd, '%s: %s' % (time.asctime(time.gmtime()), msg))
47 def log_exc(msg="", name=None):
48 """Log traceback resulting from an exception."""
51 printout += "%s: "%name
52 printout += "EXCEPTION caught <%s> \n" % msg
53 for frame in traceback.format_exc().split("\n"):
54 printout += (date_width+2)*" " + "%s\n" % frame
57 def log_trace(msg="", name=None):
58 """Log current stack"""
61 printout += "%s: " % name
62 printout += "LOGTRACE\n"
63 for frame in traceback.format_stack():
64 printout += "..." + frame
68 ########## snapshot data to a file
69 # for some reason the various modules are still triggered even when the
70 # data from PLC cannot be reached
71 # we show this message instead of the exception stack instead in this case
72 def log_missing_data(msg,key):
73 log("%s: could not find the %s key in data (PLC connection down?) - IGNORED"%(msg,key))
75 def log_data_in_file(data, file, message="",level=LOG_NODE):
81 now=time.strftime("Last update: %Y.%m.%d at %H:%M:%S %Z", time.localtime())
83 if message: f.write('Message:'+message+'\n')
84 pp=pprint.PrettyPrinter(stream=f,indent=2)
87 verbose("logger:.log_data_in_file Owerwrote %s"%file)
89 log_exc('logger.log_data_in_file failed - file=%s - message=%r'%(file,message))
91 def log_slivers(data):
92 log_data_in_file(data, LOG_SLIVERS, "raw GetSlivers")
94 log_data_in_file(db, LOG_DATABASE, "raw database")
96 #################### child processes
97 # avoid waiting until the process returns;
98 # that makes debugging of hanging children hard
101 def __init__(self, message='log_call: '):
103 self.message = message
112 log(self.message + self.buffer)
115 # time out in seconds - avoid hanging subprocesses - default is 5 minutes
116 default_timeout_minutes = 5
118 # returns a bool that is True when everything goes fine and the retcod is 0
119 def log_call(command, timeout=default_timeout_minutes*60, poll=1):
120 message=" ".join(command)
121 log("log_call: running command %s" % message)
122 verbose("log_call: timeout=%r s" % timeout)
123 verbose("log_call: poll=%r s" % poll)
124 trigger=time.time()+timeout
127 child = subprocess.Popen(command, bufsize=1,
128 stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
131 # see if anything can be read within the poll interval
132 (r, w, x) = select.select([child.stdout], [], [], poll)
134 buffer.add(child.stdout.read(1))
136 returncode = child.poll()
138 if returncode != None:
140 # child is done and return 0
142 log("log_call:end command (%s) completed" % message)
147 log("log_call:end command (%s) returned with code %d" %(message,returncode))
149 # no : still within timeout ?
150 if time.time() >= trigger:
153 log("log_call:end terminating command (%s) - exceeded timeout %d s"%(message,timeout))
156 log_exc("failed to run command %s" % message)