Package backend :: Package common :: Module rhnLog
[hide private]
[frames] | no frames]

Source Code for Module backend.common.rhnLog

  1  # rhnLog.py                                            - Logging functions. 
  2  #------------------------------------------------------------------------------ 
  3  # This module contains the necessary functions for producing log messages to 
  4  # stderr, stdout or a specified filename. Used by all server-side code. 
  5  # 
  6  # USAGE: For general purposes, simply import the log_debug function and use it 
  7  #        as log_debug(min_level, *args) 
  8  # 
  9  # NOTE ON LOG LEVELS (rough descriptions): 
 10  # 1 - generally for 1 line log items and/or of relative importance 
 11  # 2 - shorter multi-line log items 
 12  # 3 - longer multi-line log items and/or of lesser importance 
 13  # 4 - excessive stuff 
 14  # 5 - really excessive stuff 
 15  # 
 16  #------------------------------------------------------------------------------ 
 17  # 
 18  # Copyright (c) 2008--2018 Red Hat, Inc. 
 19  # 
 20  # This software is licensed to you under the GNU General Public License, 
 21  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
 22  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
 23  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
 24  # along with this software; if not, see 
 25  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 26  # 
 27  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 28  # granted to use or replicate Red Hat trademarks that are incorporated 
 29  # in this software or its documentation. 
 30  # 
 31   
 32  # system module imports 
 33  import os 
 34  import sys 
 35  import traceback 
 36  import time 
 37  import fcntl 
 38  import atexit 
 39  from spacewalk.common.fileutils import getUidGid 
 40  from spacewalk.common.rhnLib import isSUSE 
 41   
 42  LOG = None 
 43   
 44  # helper function to format the current time in the log format 
 45   
 46   
47 -def log_time():
48 if time.daylight: 49 # altzone provides the DST-corrected time 50 tz_offset = time.altzone 51 else: 52 # DST is not in effect 53 tz_offset = time.timezone 54 # Unfortunately, -3601 / 3600 == 2 55 # Also, tz_offset's sign is reverted: it is positive west of GMT 56 if tz_offset < 0: 57 sign = '+' 58 else: 59 sign = '-' 60 hours, secs = divmod(abs(tz_offset), 3600) 61 mins = secs / 60 62 63 tz_offset_string = " %s%02d:%02d" % (sign, hours, mins) 64 t = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(time.time())) 65 return t + tz_offset_string
66 67 # function for setting the close-on-exec flag 68 69
70 -def set_close_on_exec(fd):
71 s = fcntl.fcntl(fd, fcntl.F_GETFD) 72 fcntl.fcntl(fd, fcntl.F_SETFD, s | fcntl.FD_CLOEXEC)
73 74 # pylint: disable=W0702 75 76 # Init the log 77 78
79 -def initLOG(log_file="stderr", level=0):
80 global LOG 81 82 # check if it already setup 83 if LOG is not None: 84 # We already have a logging object 85 if log_file is None or LOG.file == log_file: 86 # Keep the same logging object, change only the log level 87 LOG.level = level 88 return 89 # We need a different type, so destroy the old one 90 LOG = None 91 elif log_file is None: 92 log_file = "/dev/null" 93 94 # attempt to create the path to the log file if neccessary 95 log_path = os.path.dirname(log_file) 96 if log_file not in ('stderr', 'stdout') \ 97 and log_path and not os.path.exists(os.path.dirname(log_file)): 98 log_stderr("WARNING: log path not found; attempting to create %s" % 99 log_path, sys.exc_info()[:2]) 100 101 # fetch uid, gid so we can do a "chown ..." 102 if isSUSE(): 103 apache_uid, apache_gid = getUidGid('wwwrun', 'www') 104 else: 105 apache_uid, apache_gid = getUidGid('apache', 'apache') 106 107 try: 108 os.makedirs(log_path) 109 if os.getuid() == 0: 110 os.chown(log_path, apache_uid, 0) 111 else: 112 os.chown(log_path, apache_uid, apache_gid) 113 except: 114 log_stderr("ERROR: unable to create log file path %s" % log_path, 115 sys.exc_info()[:2]) 116 return 117 118 # At this point, LOG is None and log_file is not None 119 # Get a new LOG 120 LOG = rhnLog(log_file, level) 121 return
122 123 # Convenient macro-type debugging function 124 125
126 -def log_debug(level, *args):
127 # Please excuse the style inconsistencies. 128 if LOG and LOG.level >= level: 129 LOG.logMessage(*args)
130 131 # Dump some information to stderr. 132 133
134 -def log_stderr(*args):
135 pid = os.getpid() 136 for arg in args: 137 sys.stderr.write("Spacewalk %s %s: %s\n" % ( 138 pid, log_time(), arg)) 139 sys.stderr.flush()
140 141 # Convenient error logging function 142 143
144 -def log_error(*args):
145 if not args: 146 return 147 if LOG: 148 LOG.logMessage("ERROR", *args) 149 # log to stderr too 150 log_stderr(str(args))
151 152 # Log a string with no extra info. 153 154
155 -def log_clean(level, msg):
156 if LOG and LOG.level >= level: 157 LOG.writeToLog(msg)
158 159 # set the request object for the LOG so we don't have to expose the 160 # LOG object externally 161 162
163 -def log_setreq(req):
164 if LOG: 165 LOG.set_req(req)
166 167 # The base log class 168 169
170 -class rhnLog:
171
172 - def __init__(self, log_file, level):
173 self.level = level 174 self.log_info = "0.0.0.0: " 175 self.file = log_file 176 self.pid = os.getpid() 177 self.real = 0 178 if self.file in ["stderr", "stdout"]: 179 self.fd = getattr(sys, self.file) 180 self.log_info = "" 181 return 182 183 newfileYN = 0 184 if not os.path.exists(self.file): 185 newfileYN = 1 # just used for the chown/chmod 186 187 # else, open it as a real file, with locking and stuff 188 try: 189 # try to open it in line buffered mode 190 self.fd = open(self.file, "a", 1) 191 set_close_on_exec(self.fd) 192 if newfileYN: 193 if isSUSE(): 194 apache_uid, apache_gid = getUidGid('wwwrun', 'www') 195 else: 196 apache_uid, apache_gid = getUidGid('apache', 'apache') 197 if os.getuid() == 0: 198 os.chown(self.file, apache_uid, 0) 199 else: 200 os.chown(self.file, apache_uid, apache_gid) 201 os.chmod(self.file, int('0660', 8)) 202 except: 203 log_stderr("ERROR LOG FILE: Couldn't open log file %s" % self.file, 204 sys.exc_info()[:2]) 205 self.file = "stderr" 206 self.fd = sys.stderr 207 else: 208 self.real = 1
209 210 # Main logging method.
211 - def logMessage(self, *args):
212 tbStack = traceback.extract_stack() 213 callid = len(tbStack) - 3 214 module = '' 215 try: # So one can debug from the commandline. 216 module = tbStack[callid][0] 217 arr = module.split('/') 218 if len(arr) > 1: 219 lastDir = arr[-2] + "/" 220 else: 221 lastDir = "" 222 filename = arr[-1] 223 filename = filename[:filename.rindex('.')] 224 module = lastDir + filename 225 del lastDir 226 except: 227 module = '' 228 229 msg = "%s%s.%s" % (self.log_info, module, tbStack[callid][2]) 230 if args: 231 msg = "%s%s" % (msg, repr(args)) 232 self.writeMessage(msg)
233 234 # send a message to the log file w/some extra data (time stamp, etc).
235 - def writeMessage(self, msg):
236 if self.real: 237 msg = "%s %d %s" % (log_time(), self.pid, msg) 238 else: 239 msg = "%s %s" % (log_time(), msg) 240 self.writeToLog(msg)
241 242 # send a message to the log file.
243 - def writeToLog(self, msg):
244 # this is for debugging in case of errors 245 # fd = self.fd # no-op, but useful for dumping the current data 246 self.fd.write("%s\n" % msg)
247 248 # Reinitialize req info if req has changed.
249 - def set_req(self, req=None):
250 remoteAddr = '0.0.0.0' 251 if req: 252 if "X-Forwarded-For" in req.headers_in: 253 remoteAddr = req.headers_in["X-Forwarded-For"] 254 else: 255 remoteAddr = req.connection.remote_ip 256 self.log_info = "%s: " % (remoteAddr, )
257 258 # shutdown the log
259 - def __del__(self):
260 if self.real: 261 self.fd.close() 262 self.level = self.log_info = None 263 self.pid = self.file = self.real = self.fd = None
264 265
266 -def _exit():
267 global LOG 268 if LOG: 269 del LOG 270 LOG = None
271 272 atexit.register(_exit) 273 274 275 #------------------------------------------------------------------------------ 276 if __name__ == "__main__": 277 print("You can not run this module by itself") 278 sys.exit(-1) 279 #------------------------------------------------------------------------------ 280