Revision 1ae4c5a1 lib/utils/__init__.py

b/lib/utils/__init__.py
42 42
import fcntl
43 43
import resource
44 44
import logging
45
import logging.handlers
46 45
import signal
47 46
import OpenSSL
48 47
import datetime
......
59 58
from ganeti.utils.retry import * # pylint: disable-msg=W0401
60 59
from ganeti.utils.text import * # pylint: disable-msg=W0401
61 60
from ganeti.utils.mlock import * # pylint: disable-msg=W0401
61
from ganeti.utils.log import * # pylint: disable-msg=W0401
62 62

  
63 63
_locksheld = []
64 64

  
......
2276 2276
  return float(seconds) + (float(microseconds) * 0.000001)
2277 2277

  
2278 2278

  
2279
class LogFileHandler(logging.FileHandler):
2280
  """Log handler that doesn't fallback to stderr.
2281

  
2282
  When an error occurs while writing on the logfile, logging.FileHandler tries
2283
  to log on stderr. This doesn't work in ganeti since stderr is redirected to
2284
  the logfile. This class avoids failures reporting errors to /dev/console.
2285

  
2286
  """
2287
  def __init__(self, filename, mode="a", encoding=None):
2288
    """Open the specified file and use it as the stream for logging.
2289

  
2290
    Also open /dev/console to report errors while logging.
2291

  
2292
    """
2293
    logging.FileHandler.__init__(self, filename, mode, encoding)
2294
    self.console = open(constants.DEV_CONSOLE, "a")
2295

  
2296
  def handleError(self, record): # pylint: disable-msg=C0103
2297
    """Handle errors which occur during an emit() call.
2298

  
2299
    Try to handle errors with FileHandler method, if it fails write to
2300
    /dev/console.
2301

  
2302
    """
2303
    try:
2304
      logging.FileHandler.handleError(self, record)
2305
    except Exception: # pylint: disable-msg=W0703
2306
      try:
2307
        self.console.write("Cannot log message:\n%s\n" % self.format(record))
2308
      except Exception: # pylint: disable-msg=W0703
2309
        # Log handler tried everything it could, now just give up
2310
        pass
2311

  
2312

  
2313
def SetupLogging(logfile, debug=0, stderr_logging=False, program="",
2314
                 multithreaded=False, syslog=constants.SYSLOG_USAGE,
2315
                 console_logging=False):
2316
  """Configures the logging module.
2317

  
2318
  @type logfile: str
2319
  @param logfile: the filename to which we should log
2320
  @type debug: integer
2321
  @param debug: if greater than zero, enable debug messages, otherwise
2322
      only those at C{INFO} and above level
2323
  @type stderr_logging: boolean
2324
  @param stderr_logging: whether we should also log to the standard error
2325
  @type program: str
2326
  @param program: the name under which we should log messages
2327
  @type multithreaded: boolean
2328
  @param multithreaded: if True, will add the thread name to the log file
2329
  @type syslog: string
2330
  @param syslog: one of 'no', 'yes', 'only':
2331
      - if no, syslog is not used
2332
      - if yes, syslog is used (in addition to file-logging)
2333
      - if only, only syslog is used
2334
  @type console_logging: boolean
2335
  @param console_logging: if True, will use a FileHandler which falls back to
2336
      the system console if logging fails
2337
  @raise EnvironmentError: if we can't open the log file and
2338
      syslog/stderr logging is disabled
2339

  
2340
  """
2341
  fmt = "%(asctime)s: " + program + " pid=%(process)d"
2342
  sft = program + "[%(process)d]:"
2343
  if multithreaded:
2344
    fmt += "/%(threadName)s"
2345
    sft += " (%(threadName)s)"
2346
  if debug:
2347
    fmt += " %(module)s:%(lineno)s"
2348
    # no debug info for syslog loggers
2349
  fmt += " %(levelname)s %(message)s"
2350
  # yes, we do want the textual level, as remote syslog will probably
2351
  # lose the error level, and it's easier to grep for it
2352
  sft += " %(levelname)s %(message)s"
2353
  formatter = logging.Formatter(fmt)
2354
  sys_fmt = logging.Formatter(sft)
2355

  
2356
  root_logger = logging.getLogger("")
2357
  root_logger.setLevel(logging.NOTSET)
2358

  
2359
  # Remove all previously setup handlers
2360
  for handler in root_logger.handlers:
2361
    handler.close()
2362
    root_logger.removeHandler(handler)
2363

  
2364
  if stderr_logging:
2365
    stderr_handler = logging.StreamHandler()
2366
    stderr_handler.setFormatter(formatter)
2367
    if debug:
2368
      stderr_handler.setLevel(logging.NOTSET)
2369
    else:
2370
      stderr_handler.setLevel(logging.CRITICAL)
2371
    root_logger.addHandler(stderr_handler)
2372

  
2373
  if syslog in (constants.SYSLOG_YES, constants.SYSLOG_ONLY):
2374
    facility = logging.handlers.SysLogHandler.LOG_DAEMON
2375
    syslog_handler = logging.handlers.SysLogHandler(constants.SYSLOG_SOCKET,
2376
                                                    facility)
2377
    syslog_handler.setFormatter(sys_fmt)
2378
    # Never enable debug over syslog
2379
    syslog_handler.setLevel(logging.INFO)
2380
    root_logger.addHandler(syslog_handler)
2381

  
2382
  if syslog != constants.SYSLOG_ONLY:
2383
    # this can fail, if the logging directories are not setup or we have
2384
    # a permisssion problem; in this case, it's best to log but ignore
2385
    # the error if stderr_logging is True, and if false we re-raise the
2386
    # exception since otherwise we could run but without any logs at all
2387
    try:
2388
      if console_logging:
2389
        logfile_handler = LogFileHandler(logfile)
2390
      else:
2391
        logfile_handler = logging.FileHandler(logfile)
2392
      logfile_handler.setFormatter(formatter)
2393
      if debug:
2394
        logfile_handler.setLevel(logging.DEBUG)
2395
      else:
2396
        logfile_handler.setLevel(logging.INFO)
2397
      root_logger.addHandler(logfile_handler)
2398
    except EnvironmentError:
2399
      if stderr_logging or syslog == constants.SYSLOG_YES:
2400
        logging.exception("Failed to enable logging to file '%s'", logfile)
2401
      else:
2402
        # we need to re-raise the exception
2403
        raise
2404

  
2405

  
2406 2279
def IsNormAbsPath(path):
2407 2280
  """Check whether a path is absolute and also normalized
2408 2281

  

Also available in: Unified diff