# Buggy code
def setup_logging(level, console_stream=None, log_dir=None, scope=None, log_name=None):
    """Configures logging for a given scope, by default the global scope.

    :param str level: The logging level to enable, must be one of the level names listed here:
                      https://docs.python.org/2/library/logging.html#levels
    :param file console_stream: The stream to use for default (console) logging. If None (default),
                                this will disable console logging.
    :param str log_dir: An optional directory to emit logs files in.  If unspecified, no disk logging
                        will occur.  If supplied, the directory will be created if it does not already
                        exist and all logs will be tee'd to a rolling set of log files in that
                        directory.
    :param str scope: A logging scope to configure.  The scopes are hierarchichal logger names, with
                      The '.' separator providing the scope hierarchy.  By default the root logger is
                      configured.
    :param str log_name: The base name of the log file (defaults to 'pants.log').
    :returns: The full path to the main log file if file logging is configured or else `None`.
    :rtype: str
    """

    # TODO(John Sirois): Consider moving to straight python logging.  The divide between the
    # context/work-unit logging and standard python logging doesn't buy us anything.

    # TODO(John Sirois): Support logging.config.fileConfig so a site can setup fine-grained
    # logging control and we don't need to be the middleman plumbing an option for each python
    # standard logging knob.

    log_filename = None
    log_stream = None

    logger = logging.getLogger(scope)
    for handler in logger.handlers:
        logger.removeHandler(handler)

    if console_stream:
        console_handler = StreamHandler(stream=console_stream)
        console_handler.setFormatter(Formatter(fmt="%(levelname)s] %(message)s"))
        console_handler.setLevel(level)
        logger.addHandler(console_handler)

    if log_dir:
        safe_mkdir(log_dir)
        log_filename = os.path.join(log_dir, log_name or "pants.log")
        file_handler = RotatingFileHandler(
            log_filename, maxBytes=10 * 1024 * 1024, backupCount=4
        )
        log_stream = file_handler.stream

        class GlogFormatter(Formatter):
            LEVEL_MAP = {
                logging.FATAL: "F",
                logging.ERROR: "E",
                logging.WARN: "W",
                logging.INFO: "I",
                logging.DEBUG: "D",
            }

            def format(self, record):
                datetime = time.strftime(
                    "%m%d %H:%M:%S", time.localtime(record.created)
                )
                micros = int((record.created - int(record.created)) * 1e6)
                return "{levelchar}{datetime}.{micros:06d} {process} {filename}:{lineno}] {msg}".format(
                    levelchar=self.LEVEL_MAP[record.levelno],
                    datetime=datetime,
                    micros=micros,
                    process=record.process,
                    filename=record.filename,
                    lineno=record.lineno,
                    msg=record.getMessage(),
                )

        file_handler.setFormatter(GlogFormatter())
        file_handler.setLevel(level)
        logger.addHandler(file_handler)

    logger.setLevel(level)

    # This routes warnings through our loggers instead of straight to raw stderr.
    logging.captureWarnings(True)

    return LoggingSetupResult(log_filename, log_stream)


# Traceback (ValueError)
F0117 15:10:04.500231 12664 process_manager.py:463] Traceback (most recent call last):
File "/Users/redacted/.pex/install/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl.ac6c80da047e6ed09228262b774906b65ebf6918/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl/pants/pantsd/process_manager.py", line 461, in daemonize
self.post_fork_child(**post_fork_child_opts or {})
File "/Users/redacted/.pex/install/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl.ac6c80da047e6ed09228262b774906b65ebf6918/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl/pants/bin/daemon_pants_runner.py", line 172, in post_fork_child
self._exiter.set_except_hook(sys.stderr)
File "/Users/redacted/.pex/install/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl.ac6c80da047e6ed09228262b774906b65ebf6918/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl/pants/base/exiter.py", line 123, in set_except_hook
self._setup_faulthandler(trace_stream or sys.stderr)
File "/Users/redacted/.pex/install/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl.ac6c80da047e6ed09228262b774906b65ebf6918/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl/pants/base/exiter.py", line 117, in _setup_faulthandler
faulthandler.enable(trace_stream)
File "/Users/redacted/.pex/install/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl.ac6c80da047e6ed09228262b774906b65ebf6918/pantsbuild.pants-1.4.0.dev20+3346017507-cp27-none-macosx_10_8_x86_64.whl/pants/pantsd/pants_daemon.py", line 61, in fileno
return self._stream.fileno()
ValueError: I/O operation on closed file

# Fixed code
def setup_logging(level, console_stream=None, log_dir=None, scope=None, log_name=None):
    """Configures logging for a given scope, by default the global scope.

    :param str level: The logging level to enable, must be one of the level names listed here:
                      https://docs.python.org/2/library/logging.html#levels
    :param file console_stream: The stream to use for default (console) logging. If None (default),
                                this will disable console logging.
    :param str log_dir: An optional directory to emit logs files in.  If unspecified, no disk logging
                        will occur.  If supplied, the directory will be created if it does not already
                        exist and all logs will be tee'd to a rolling set of log files in that
                        directory.
    :param str scope: A logging scope to configure.  The scopes are hierarchichal logger names, with
                      The '.' separator providing the scope hierarchy.  By default the root logger is
                      configured.
    :param str log_name: The base name of the log file (defaults to 'pants.log').
    :returns: The full path to the main log file if file logging is configured or else `None`.
    :rtype: str
    """

    # TODO(John Sirois): Consider moving to straight python logging.  The divide between the
    # context/work-unit logging and standard python logging doesn't buy us anything.

    # TODO(John Sirois): Support logging.config.fileConfig so a site can setup fine-grained
    # logging control and we don't need to be the middleman plumbing an option for each python
    # standard logging knob.

    log_filename = None
    file_handler = None

    logger = logging.getLogger(scope)
    for handler in logger.handlers:
        logger.removeHandler(handler)

    if console_stream:
        console_handler = StreamHandler(stream=console_stream)
        console_handler.setFormatter(Formatter(fmt="%(levelname)s] %(message)s"))
        console_handler.setLevel(level)
        logger.addHandler(console_handler)

    if log_dir:
        safe_mkdir(log_dir)
        log_filename = os.path.join(log_dir, log_name or "pants.log")
        file_handler = FileHandler(log_filename)

        class GlogFormatter(Formatter):
            LEVEL_MAP = {
                logging.FATAL: "F",
                logging.ERROR: "E",
                logging.WARN: "W",
                logging.INFO: "I",
                logging.DEBUG: "D",
            }

            def format(self, record):
                datetime = time.strftime(
                    "%m%d %H:%M:%S", time.localtime(record.created)
                )
                micros = int((record.created - int(record.created)) * 1e6)
                return "{levelchar}{datetime}.{micros:06d} {process} {filename}:{lineno}] {msg}".format(
                    levelchar=self.LEVEL_MAP[record.levelno],
                    datetime=datetime,
                    micros=micros,
                    process=record.process,
                    filename=record.filename,
                    lineno=record.lineno,
                    msg=record.getMessage(),
                )

        file_handler.setFormatter(GlogFormatter())
        file_handler.setLevel(level)
        logger.addHandler(file_handler)

    logger.setLevel(level)

    # This routes warnings through our loggers instead of straight to raw stderr.
    logging.captureWarnings(True)

    return LoggingSetupResult(log_filename, file_handler)