logger: remove deprecated compat logger

- remove old Logger and LoggerModule classes
- remove old {,Compat}LogRecord classes
- remove deprecated and unneeded methods from StreamlinkLogger
- remove usage of old Logger from Session
- remove session reference from ConsoleOutput
This commit is contained in:
bastimeyer 2020-10-13 14:02:59 +02:00
parent b4c89f57c2
commit 9ac40cb075
6 changed files with 15 additions and 226 deletions

View File

@ -1,6 +1,4 @@
import logging
import sys
import warnings
from logging import NOTSET, ERROR, WARN, INFO, DEBUG, CRITICAL
from threading import Lock
@ -17,72 +15,11 @@ levels = [name for _, name in _levelToName.items()]
_config_lock = Lock()
class _CompatLogRecord(logging.LogRecord):
"""
LogRecord wrapper to include sinfo for Python 3 by not Python 2
"""
def __init__(self, name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None, **kwargs):
super(_CompatLogRecord, self).__init__(name, level, pathname, lineno, msg, args, exc_info, func=func,
sinfo=sinfo, **kwargs)
class _LogRecord(_CompatLogRecord):
def getMessage(self):
"""
Return the message for this LogRecord.
Return the message for this LogRecord after merging any user-supplied
arguments with the message.
"""
msg = self.msg
if self.args:
msg = msg.format(*self.args)
return msg
class StreamlinkLogger(logging.getLoggerClass(), object):
def __init__(self, name, level=logging.NOTSET):
super(StreamlinkLogger, self).__init__(name, level)
class StreamlinkLogger(logging.getLoggerClass()):
def trace(self, message, *args, **kws):
if self.isEnabledFor(TRACE):
self._log(TRACE, message, args, **kws)
def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
func=None, extra=None, sinfo=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
if name.startswith("streamlink"):
rv = _LogRecord(name, level, fn, lno, msg, args, exc_info, func, sinfo)
else:
rv = _CompatLogRecord(name, level, fn, lno, msg, args, exc_info, func, sinfo)
if extra is not None:
for key in extra:
if (key in ["message", "asctime"]) or (key in rv.__dict__):
raise KeyError("Attempt to overwrite %r in LogRecord" % key)
rv.__dict__[key] = extra[key]
return rv
def set_level(self, level):
self.setLevel(level)
@staticmethod
def new_module(name):
warnings.warn("Logger.new_module has been deprecated, use the standard logging.getLogger method",
category=DeprecationWarning, stacklevel=2)
return logging.getLogger("streamlink.{0}".format(name))
@staticmethod
def set_output(output):
"""
No-op, must be set in the log handler
"""
warnings.warn("Logger.set_output has been deprecated, use the standard logging module",
category=DeprecationWarning, stacklevel=2)
logging.setLoggerClass(StreamlinkLogger)
root = logging.getLogger("streamlink")
@ -130,59 +67,6 @@ class StringFormatter(logging.Formatter):
return s
class Logger(object):
Levels = levels
Format = "[{name}][{levelname}] {message}"
root_name = "streamlink_old"
def __init__(self):
warnings.warn("Logger class has been deprecated, use the standard logging module",
category=DeprecationWarning, stacklevel=2)
self.root = logging.getLogger(self.root_name)
root.propagate = False
self.handler = logging.StreamHandler(sys.stdout)
self.handler.setFormatter(StringFormatter(self.Format, style="{", remove_base=[self.root_name]))
self.root.addHandler(self.handler)
self.set_level("info")
@classmethod
def get_logger(cls, name):
return logging.getLogger("{0}.{1}".format(cls.root_name, name))
def new_module(self, module):
return LoggerModule(self, module)
def set_level(self, level):
self.root.setLevel(level)
def set_output(self, output):
self.handler.stream = output
def msg(self, module, level, msg, *args, **kwargs):
log = self.get_logger(module)
log.log(level, msg, *args)
class LoggerModule(object):
def __init__(self, manager, module):
warnings.warn("LoggerModule class has been deprecated, use the standard logging module",
category=DeprecationWarning, stacklevel=2)
self.manager = manager
self.module = module
def error(self, msg, *args, **kwargs):
self.manager.msg(self.module, ERROR, msg, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
self.manager.msg(self.module, WARN, msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.manager.msg(self.module, INFO, msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
self.manager.msg(self.module, DEBUG, msg, *args, **kwargs)
BASIC_FORMAT = "[{name}][{levelname}] {message}"
FORMAT_STYLE = "{"
REMOVE_BASE = ["streamlink", "streamlink_cli"]
@ -211,4 +95,4 @@ def basicConfig(**kwargs):
root.setLevel(level)
__all__ = ["StreamlinkLogger", "Logger", "basicConfig", "root", "levels"]
__all__ = ["StreamlinkLogger", "basicConfig", "root", "levels"]

View File

@ -8,7 +8,7 @@ import requests
from collections import OrderedDict
from streamlink.logger import StreamlinkLogger, Logger
from streamlink.logger import StreamlinkLogger
from streamlink.utils import update_scheme, memoize
from streamlink.utils.l10n import Localization
from . import plugins, __version__
@ -89,17 +89,6 @@ class Streamlink(object):
self.options.update(options)
self.plugins = OrderedDict({})
self.load_builtin_plugins()
self._logger = None
@property
def logger(self):
"""
Backwards compatible logger property
:return: Logger instance
"""
if not self._logger:
self._logger = Logger()
return self._logger
def set_option(self, key, value):
"""Sets general options used by plugins and streams originating
@ -367,25 +356,6 @@ class Streamlink(object):
plugin = self.plugins[plugin]
return plugin.get_option(key)
def set_loglevel(self, level):
"""Sets the log level used by this session.
Valid levels are: "none", "error", "warning", "info"
and "debug".
:param level: level of logging to output
"""
self.logger.set_level(level)
def set_logoutput(self, output):
"""Sets the log output used by this session.
:param output: a file-like object with a write method
"""
self.logger.set_output(output)
@memoize
def resolve_url(self, url, follow_redirect=True):
"""Attempts to find a plugin that can use this URL.

View File

@ -30,15 +30,10 @@ class ConsoleUserInputRequester(UserInputRequester):
class ConsoleOutput(object):
def __init__(self, output, streamlink, json=False):
self.streamlink = streamlink
def __init__(self, output, json=False):
self.json = json
self.output = output
def set_level(self, level):
self.streamlink.set_loglevel(level)
def set_output(self, output):
self.output = output

View File

@ -691,8 +691,7 @@ def setup_console(output):
global console
# All console related operations is handled via the ConsoleOutput class
console = ConsoleOutput(output, streamlink)
console.json = args.json
console = ConsoleOutput(output, args.json)
# Handle SIGTERM just like SIGINT
signal.signal(signal.SIGTERM, signal.default_int_handler)

View File

@ -1,6 +1,6 @@
from io import StringIO
import unittest
from unittest.mock import Mock, patch
from unittest.mock import patch
from streamlink_cli.console import ConsoleOutput
@ -13,41 +13,41 @@ class _TestObj(object):
class TestConsole(unittest.TestCase):
def test_msg_format(self):
output = StringIO()
console = ConsoleOutput(output, Mock())
console = ConsoleOutput(output)
console.msg("{0} - {1}", 1, 2)
self.assertEqual("1 - 2\n", output.getvalue())
def test_msg_format_kw(self):
output = StringIO()
console = ConsoleOutput(output, Mock())
console = ConsoleOutput(output)
console.msg("{test} - {what}", test=1, what=2)
self.assertEqual("1 - 2\n", output.getvalue())
def test_msg_json_not_set(self):
output = StringIO()
console = ConsoleOutput(output, Mock())
console = ConsoleOutput(output)
self.assertEqual(None, console.msg_json({"test": 1}))
self.assertEqual("", output.getvalue())
def test_msg_json(self):
output = StringIO()
console = ConsoleOutput(output, Mock(), json=True)
console = ConsoleOutput(output, json=True)
console.msg_json({"test": 1})
self.assertEqual('''{\n "test": 1\n}\n''', output.getvalue())
def test_msg_json_object(self):
output = StringIO()
test_obj = _TestObj()
console = ConsoleOutput(output, Mock(), json=True)
console = ConsoleOutput(output, json=True)
console.msg_json(test_obj)
self.assertEqual('''{\n "test": 1\n}\n''', output.getvalue())
@patch('streamlink_cli.console.sys.exit')
def test_msg_json_error(self, mock_exit):
output = StringIO()
console = ConsoleOutput(output, Mock(), json=True)
console = ConsoleOutput(output, json=True)
console.msg_json({"error": "bad"})
self.assertEqual('''{\n "error": "bad"\n}\n''', output.getvalue())
mock_exit.assert_called_with(1)
@ -55,7 +55,7 @@ class TestConsole(unittest.TestCase):
@patch('streamlink_cli.console.sys.exit')
def test_exit(self, mock_exit):
output = StringIO()
console = ConsoleOutput(output, Mock())
console = ConsoleOutput(output)
console.exit("error")
self.assertEqual("error: error\n", output.getvalue())
mock_exit.assert_called_with(1)
@ -63,17 +63,11 @@ class TestConsole(unittest.TestCase):
@patch('streamlink_cli.console.sys.exit')
def test_exit_json(self, mock_exit):
output = StringIO()
console = ConsoleOutput(output, Mock(), json=True)
console = ConsoleOutput(output, json=True)
console.exit("error")
self.assertEqual('''{\n "error": "error"\n}\n''', output.getvalue())
mock_exit.assert_called_with(1)
def test_set_level(self):
session = Mock()
console = ConsoleOutput(Mock(), session)
console.set_level("debug")
session.set_loglevel.assert_called_with("debug")
@patch('streamlink_cli.console.sys.stderr')
@patch('streamlink_cli.console.input')
@patch('streamlink_cli.console.sys.stdin.isatty')

View File

@ -1,10 +1,8 @@
from io import StringIO
import logging
import unittest
import warnings
from streamlink import logger, Streamlink
from tests import catch_warnings
from streamlink import logger
class TestLogging(unittest.TestCase):
@ -53,54 +51,3 @@ class TestLogging(unittest.TestCase):
logger.root.setLevel("info")
log.info(u"Special Character: Ѩ")
self.assertEqual(output.getvalue(), u"[test][info] Special Character: Ѩ\n")
class TestDeprecatedLogger(unittest.TestCase):
def setUp(self):
warnings.resetwarnings()
warnings.simplefilter('always', DeprecationWarning) # turn off filter
def tearDown(self):
warnings.simplefilter('default', DeprecationWarning) # restore filter
def _new_logger(self):
output = StringIO()
manager = logger.Logger()
manager.set_output(output)
return manager, output
@catch_warnings()
def test_deprecated_level(self):
manager, output = self._new_logger()
with warnings.catch_warnings(record=True):
log = manager.new_module("test_level")
log.debug("test")
self.assertEqual(output.tell(), 0)
manager.set_level("debug")
log.debug("test")
self.assertNotEqual(output.tell(), 0)
@catch_warnings()
def test_deprecated_output(self):
manager, output = self._new_logger()
log = manager.new_module("test_output")
manager.set_level("debug")
log.debug("test")
self.assertEqual(output.getvalue(), "[test_output][debug] test\n")
@catch_warnings()
def test_deprecated_session_logger(self):
session = Streamlink()
output = StringIO()
new_log = session.logger.new_module("test")
session.set_logoutput(output)
session.set_loglevel("info")
new_log.info("test1")
# regular python loggers shouldn't log here
logging.getLogger("streamlink.test").critical("should not log")
self.assertEqual(output.getvalue(), "[test][info] test1\n")