Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

beebox / crossover   deb

Repository URL to install this package:

Version: 18.5.0-1 

/ opt / cxoffice / lib / python / cxlog.py

# (c) Copyright 2009-2010, 2015. CodeWeavers, Inc.

"""Handles logging and error reporting."""

import os
import sys
import time
try:
    import thread
except ImportError:
    # pylint: disable=F0401
    import _thread as thread


# internal variables

# pylint: disable=C0103
_all_on = None
_channels = {}
_log_file = None
_start = None


#####
#
# Logging API
#
#####

def log_to(out, append=True):
    """Sets up logging to the specified file object, name, or handle.

    If append is true, then the log is appended to.
    """
    # pylint: disable=W0603
    global _log_file
    if sys.version_info >= (3,):
        if append:
            mode = 'at'
        else:
            mode = 'wt'
        if hasattr(out, 'write'):
            # file-like object
            _log_file = out
        else:
            # file handle or filename
            _log_file = open(out, mode, 1, 'utf8', 'backslashreplace')
    else:
        if append:
            mode = 'ab'
        else:
            mode = 'wb'
        if hasattr(out, 'write'):
            # file-like object
            _log_file = out
        elif isinstance(out, int):
            # file handle
            _log_file = os.fdopen(out, mode, 0)
        else:
            # filename
            _log_file = open(out, mode, 0)


def get_file():
    """Returns the file the traces are sent to if any, and None otherwise."""
    return _log_file


def get_filename():
    """Returns the name of the file that receives the logs.

    If logging goes to a file descriptor, then "&n" is returned where 'n' is
    the file descriptor. If logging is turned off, then None is returned.

    Occasionally exceptions were thrown here causing all kinds of
    weird hangs and breakages. Since logging is non-critical,
    we now catch all exceptions during writing.
    """
    if not _log_file:
        return None
    try:
        name = _log_file.name
        if name == '<fdopen>':
            name = '&%s' % _log_file.fileno()
    except AttributeError:
        name = repr(_log_file)
    return name

def is_on(channel=None):
    """Returns False if logging is turned off globally or for the specified
    channel. Otherwise returns True.

    The channels correspond to what is put in $CX_DEBUGMSG.
    """
    if _log_file is None:
        return False
    if channel is None:
        return _all_on is not False
    if channel in _channels:
        return _channels[channel]
    return _all_on is True

def init_logging():
    """Sets up logging based on the CX_LOG and CX_DEBUGMSG variables.

    This is called automatically when cxlog is first imported.
    """
    if 'CX_LOG' in os.environ:
        if os.environ['CX_LOG'] == '-':
            log_to(sys.stderr)
        else:
            try:
                log_to(os.environ['CX_LOG'])
            except IOError:
                ioerror = sys.exc_info()[1]
                warn("could not open log output file: " + unicode(ioerror))
    elif 'CX_DEBUGMSG' in os.environ:
        log_to(sys.stderr)

    if 'CX_DEBUGMSG' in os.environ:
        # pylint: disable=W0603
        global _all_on
        for channel in os.environ['CX_DEBUGMSG'].split(','):
            if channel == '+all':
                _all_on = True
            elif channel == '-all':
                _all_on = False
            elif channel.startswith('-'):
                _channels[channel.lstrip('-')] = False
            else:
                _channels[channel.lstrip('+')] = True
        if is_on('timestamp'):
            global _start
            _start = time.time()


def _tid_prefix():
    if is_on('tid'):
        return '%s:' % thread.get_ident()
    return ''

def _timestamp_prefix():
    if _start is None:
        return ''
    return '%.3f:' % (time.time() - _start)

try:
    unicode_type = unicode
except NameError:
    unicode_type = str

def _to_str(string, always_repr):
    if always_repr:
        result = repr(string)
    elif isinstance(string, str):
        return string
    elif isinstance(string, unicode_type):
        return string.encode('utf8')
    else:
        result = repr(string)
    if isinstance(result, str):
        return result
    return "<object of type %s could not be converted to a string>" % _to_str(type(string), True)

def to_str(string):
    """Format an arbitrary object for printing.

    The result is guaranteed to be a string, and this function will never cause
    an exception. If it's a string or unicode object, the contents are used
    literally."""
    try:
        return _to_str(string, False)
    except: # pylint: disable=W0702
        return "<exception raised while converting an object to string>"

def debug_str(string):
    """Format an arbitrary object for debugging purposes.

    The result is guaranteed to be a string, and this function will never cause
    an exception. If possible, this is a python representation of the object,
    or something in <angle brackets>."""
    try:
        return _to_str(string, True)
    except: # pylint: disable=W0702
        return "<exception raised while converting an object to string>"


def log(message):
    """Prints a log message.

    What is printed is 'fmt % args' and a linefeed is automatically added.
    """
    if _log_file and _all_on is not False:
        _log_file.write('%s%s%s\n' % (_timestamp_prefix(), _tid_prefix(), to_str(message)))


def log_(channel, message):
    """Same as cxlog(), but the message is only logged if logging is turned on
    for the specified channel.
    """
    if is_on(channel):
        _log_file.write("%s%s%s:%s\n" % (_timestamp_prefix(), _tid_prefix(), to_str(channel), to_str(message)))



#####
#
# Error and warning reporting interface
#
#####

def name0():
    """Returns the current executable basename."""
    return os.path.basename(sys.argv[0])


def warn(message):
    """Issues a warning to the user on stderr.

    A linefeed is automatically appended to the message.
    """
    msg = name0() + ":warning: " + to_str(message) + "\n"
    sys.stderr.write(msg)
    if _log_file and _log_file != sys.stderr:
        _log_file.write(msg)


def err(message):
    """Issues an error to the user on stderr.

    A linefeed is automatically appended to the message.
    """
    msg = name0() + ":error: " + to_str(message) + "\n"
    sys.stderr.write(msg)
    if _log_file and _log_file != sys.stderr:
        _log_file.write(msg)


init_logging()