├── requirements-docs.txt ├── docs ├── readme.rst ├── api.rst ├── index.rst └── conf.py ├── MANIFEST.in ├── requirements-checks.txt ├── setup.cfg ├── .coveragerc ├── tox.ini ├── requirements-tests.txt ├── .travis.yml ├── scripts └── check-code-style.sh ├── LICENSE.txt ├── verboselogs ├── pylint.py ├── tests.py └── __init__.py ├── Makefile ├── setup.py └── README.rst /requirements-docs.txt: -------------------------------------------------------------------------------- 1 | pylint 2 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.rst 2 | include *.txt 3 | graft docs 4 | -------------------------------------------------------------------------------- /requirements-checks.txt: -------------------------------------------------------------------------------- 1 | # Python packages required to run `make check'. 2 | flake8 >= 2.6.0 3 | flake8-docstrings >= 0.2.8 4 | pyflakes >= 1.2.3 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # Enable universal wheels because `verboselogs' is 2 | # pure Python and works on Python 2 and 3 alike. 3 | 4 | [wheel] 5 | universal=1 6 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc: Configuration file for coverage.py. 2 | # http://nedbatchelder.com/code/coverage/ 3 | 4 | [run] 5 | source = verboselogs 6 | omit = verboselogs/tests.py 7 | 8 | # vim: ft=dosini 9 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py26, py27, py34, py35, py36, pypy 3 | 4 | [testenv] 5 | deps = -rrequirements-tests.txt 6 | commands = py.test {posargs} 7 | 8 | [pytest] 9 | addopts = --verbose 10 | python_files = verboselogs/tests.py 11 | 12 | [flake8] 13 | exclude = .tox 14 | ignore = D211 15 | max-line-length = 120 16 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API documentation 2 | ================= 3 | 4 | The following documentation is based on the source code of version |release| of 5 | the `verboselogs` package. 6 | 7 | :mod:`verboselogs` 8 | ------------------ 9 | 10 | .. automodule:: verboselogs 11 | :members: 12 | 13 | :mod:`verboselogs.pylint` 14 | ------------------------- 15 | 16 | .. automodule:: verboselogs.pylint 17 | :members: 18 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | verboselogs documentation 2 | ========================= 3 | 4 | Welcome to the documentation of `verboselogs` version |release|! 5 | 6 | The first part of the documentation is the readme which gives you a general 7 | overview of the `verboselogs` package: 8 | 9 | .. toctree:: 10 | readme 11 | 12 | The second part is the documentation of the available modules: 13 | 14 | .. toctree:: 15 | api 16 | -------------------------------------------------------------------------------- /requirements-tests.txt: -------------------------------------------------------------------------------- 1 | mock >= 1.0.1 2 | pytest >= 2.6.1 3 | pytest-cov >= 2.2.1 4 | 5 | # The following entries provide a pylint installation that's compatible with 6 | # Python 2.6. The version pinning here was based on the following resources: 7 | # - https://github.com/certbot/certbot/issues/97#issuecomment-65632583 8 | # - https://bitbucket.org/logilab/pylint/commits/066bfa24a14f59288379638e1d64a9aa856769fd 9 | pylint < 1.4 10 | astroid <= 1.3.2 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | - "2.6" 5 | - "2.7" 6 | - "3.4" 7 | - "3.5" 8 | - "3.6" 9 | - "pypy" 10 | install: 11 | - pip install pip-accel 12 | - pip-accel install coveralls 13 | - pip-accel install --requirement=requirements-checks.txt 14 | - pip-accel install --requirement=requirements-tests.txt 15 | - LC_ALL=C pip-accel install . 16 | script: 17 | - make check 18 | - py.test --cov --verbose 19 | after_success: 20 | - coveralls 21 | branches: 22 | except: 23 | - /^[0-9]/ 24 | -------------------------------------------------------------------------------- /scripts/check-code-style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # I value automated code style checks that break my Travis CI builds but I also 4 | # value compatibility with Python 2.6, however recently it seems that flake8 5 | # has dropped Python 2.6 compatibility [1]. That's only fair, but now I need to 6 | # work around it, hence this trivial script :-). 7 | # 8 | # [1] https://travis-ci.org/xolox/python-verboselogs/jobs/147540390 9 | 10 | if python -c 'import sys; sys.exit(0 if sys.version_info[:2] >= (2, 7) else 1)'; then 11 | echo "Updating installation of flake8 .." >&2 12 | pip-accel install --upgrade --quiet --requirement=requirements-checks.txt 13 | flake8 14 | else 15 | echo "Skipping code style checks on Python 2.6 .." >&2 16 | fi 17 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Peter Odding 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /verboselogs/pylint.py: -------------------------------------------------------------------------------- 1 | # Verbose, notice, and spam log levels for Python's logging module. 2 | # 3 | # Author: Glenn Matthews 4 | # Last Change: August 7, 2017 5 | # URL: https://verboselogs.readthedocs.io 6 | 7 | """ 8 | Pylint_ plugin to fix invalid errors about the :mod:`logging` module. 9 | 10 | .. _Pylint: https://pypi.python.org/pypi/pylint 11 | """ 12 | 13 | from astroid import MANAGER, scoped_nodes, nodes 14 | 15 | 16 | def register(linter): 17 | """No-op (required by Pylint).""" 18 | 19 | 20 | def verboselogs_class_transform(cls): 21 | """Make Pylint aware of our custom logger methods.""" 22 | if cls.name == 'RootLogger': 23 | for meth in ['notice', 'spam', 'success', 'verbose']: 24 | cls.locals[meth] = [scoped_nodes.Function(meth, None)] 25 | 26 | 27 | def verboselogs_module_transform(mod): 28 | """Make Pylint aware of our custom log levels.""" 29 | if mod.name == 'logging': 30 | for const in ['NOTICE', 'SPAM', 'SUCCESS', 'VERBOSE']: 31 | mod.locals[const] = [nodes.Const(const)] 32 | 33 | 34 | # Register the above methods with Pylint. 35 | MANAGER.register_transform(scoped_nodes.Class, verboselogs_class_transform) 36 | MANAGER.register_transform(scoped_nodes.Module, verboselogs_module_transform) 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Verbose, notice, and spam log levels for Python's logging module. 2 | # 3 | # Author: Peter Odding 4 | # Last Change: July 26, 2016 5 | # URL: https://verboselogs.readthedocs.io 6 | 7 | WORKON_HOME ?= $(HOME)/.virtualenvs 8 | VIRTUAL_ENV ?= $(WORKON_HOME)/verboselogs 9 | PATH := $(VIRTUAL_ENV)/bin:$(PATH) 10 | MAKE := $(MAKE) --no-print-directory 11 | SHELL = bash 12 | 13 | default: 14 | @echo 'Makefile for verboselogs' 15 | @echo 16 | @echo 'Usage:' 17 | @echo 18 | @echo ' make install install the package in a virtual environment' 19 | @echo ' make reset recreate the virtual environment' 20 | @echo ' make check check coding style (PEP-8, PEP-257)' 21 | @echo ' make test run the test suite' 22 | @echo ' make docs update documentation using Sphinx' 23 | @echo ' make publish publish changes to GitHub/PyPI' 24 | @echo ' make clean cleanup all temporary files' 25 | @echo 26 | 27 | install: 28 | @test -d "$(VIRTUAL_ENV)" || mkdir -p "$(VIRTUAL_ENV)" 29 | @test -x "$(VIRTUAL_ENV)/bin/python" || virtualenv --quiet "$(VIRTUAL_ENV)" 30 | @test -x "$(VIRTUAL_ENV)/bin/pip" || easy_install pip 31 | @test -x "$(VIRTUAL_ENV)/bin/pip-accel" || (pip install --quiet pip-accel && pip-accel install --quiet 'urllib3[secure]') 32 | @echo "Updating installation of verboselogs .." >&2 33 | @pip uninstall --yes verboselogs &>/dev/null || true 34 | @pip install --quiet --editable . 35 | 36 | reset: 37 | $(MAKE) clean 38 | rm -Rf "$(VIRTUAL_ENV)" 39 | $(MAKE) install 40 | 41 | check: install 42 | @scripts/check-code-style.sh 43 | 44 | test: install 45 | @pip-accel install --quiet detox --requirement=requirements-tests.txt 46 | @py.test --cov 47 | @coverage html 48 | @detox 49 | 50 | docs: install 51 | @pip-accel install --quiet sphinx 52 | @cd docs && sphinx-build -nb html -d build/doctrees . build/html 53 | 54 | publish: install 55 | git push origin && git push --tags origin 56 | make clean 57 | pip-accel install --quiet twine wheel 58 | python setup.py sdist bdist_wheel 59 | twine upload dist/* 60 | make clean 61 | 62 | clean: 63 | rm -Rf *.egg .cache .coverage .tox build dist docs/build htmlcov 64 | find -depth -type d -name __pycache__ -exec rm -Rf {} \; 65 | find -type f -name '*.pyc' -delete 66 | 67 | .PHONY: default install reset check test docs publish clean 68 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Verbose, notice, and spam log levels for Python's logging module. 2 | # 3 | # Author: Peter Odding 4 | # Last Change: March 7, 2017 5 | # URL: https://verboselogs.readthedocs.io 6 | 7 | """Sphinx documentation configuration for the `verboselogs` package.""" 8 | 9 | import os 10 | import sys 11 | 12 | # Add the verboselogs source distribution's root directory to the module path. 13 | sys.path.insert(0, os.path.abspath(os.pardir)) 14 | 15 | # -- General configuration ----------------------------------------------------- 16 | 17 | # Sphinx extension module names. 18 | extensions = [ 19 | 'sphinx.ext.autodoc', 20 | 'sphinx.ext.intersphinx', 21 | 'sphinx.ext.viewcode', 22 | ] 23 | 24 | # Sort members by the source order instead of alphabetically. 25 | autodoc_member_order = 'bysource' 26 | 27 | # Paths that contain templates, relative to this directory. 28 | templates_path = ['templates'] 29 | 30 | # The suffix of source filenames. 31 | source_suffix = '.rst' 32 | 33 | # The master toctree document. 34 | master_doc = 'index' 35 | 36 | # General information about the project. 37 | project = u'verboselogs' 38 | copyright = u'2017, Peter Odding' 39 | 40 | # The version info for the project you're documenting, acts as replacement for 41 | # |version| and |release|, also used in various other places throughout the 42 | # built documents. 43 | 44 | # Find the package version and make it the release. 45 | from verboselogs import __version__ as verboselogs_version # NOQA 46 | 47 | # The short X.Y version. 48 | version = '.'.join(verboselogs_version.split('.')[:2]) 49 | 50 | # The full version, including alpha/beta/rc tags. 51 | release = verboselogs_version 52 | 53 | # The language for content autogenerated by Sphinx. Refer to documentation 54 | # for a list of supported languages. 55 | language = 'en' 56 | 57 | # List of patterns, relative to source directory, that match files and 58 | # directories to ignore when looking for source files. 59 | exclude_patterns = ['build'] 60 | 61 | # If true, '()' will be appended to :func: etc. cross-reference text. 62 | add_function_parentheses = True 63 | 64 | # The name of the Pygments (syntax highlighting) style to use. 65 | pygments_style = 'sphinx' 66 | 67 | # Refer to the Python standard library. 68 | # From: http://twistedmatrix.com/trac/ticket/4582. 69 | intersphinx_mapping = dict( 70 | python=('https://docs.python.org/2', None), 71 | ) 72 | 73 | # -- Options for HTML output --------------------------------------------------- 74 | 75 | # The theme to use for HTML and HTML Help pages. See the documentation for 76 | # a list of builtin themes. 77 | html_theme = 'classic' 78 | 79 | # Output file base name for HTML help builder. 80 | htmlhelp_basename = 'verboselogsdoc' 81 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Verbose, notice, and spam log levels for Python's logging module. 4 | # 5 | # Author: Peter Odding 6 | # Last Change: March 7, 2017 7 | # URL: https://verboselogs.readthedocs.io 8 | 9 | """Setup script for the `verboselogs` package.""" 10 | 11 | # Standard library modules. 12 | import codecs 13 | import os 14 | import re 15 | 16 | # De-facto standard solution for Python packaging. 17 | from setuptools import find_packages, setup 18 | 19 | 20 | def get_contents(*args): 21 | """Get the contents of a file relative to the source distribution directory.""" 22 | with codecs.open(get_absolute_path(*args), 'r', 'UTF-8') as handle: 23 | return handle.read() 24 | 25 | 26 | def get_version(*args): 27 | """Extract the version number from a Python module.""" 28 | contents = get_contents(*args) 29 | metadata = dict(re.findall('__([a-z]+)__ = [\'"]([^\'"]+)', contents)) 30 | return metadata['version'] 31 | 32 | 33 | def get_absolute_path(*args): 34 | """Transform relative pathnames into absolute pathnames.""" 35 | return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args) 36 | 37 | 38 | setup( 39 | name='verboselogs', 40 | version=get_version('verboselogs', '__init__.py'), 41 | description="Verbose logging level for Python's logging module", 42 | long_description=get_contents('README.rst'), 43 | url='https://verboselogs.readthedocs.io', 44 | author='Peter Odding', 45 | author_email='peter@peterodding.com', 46 | packages=find_packages(), 47 | classifiers=[ 48 | 'Development Status :: 5 - Production/Stable', 49 | 'Intended Audience :: Developers', 50 | 'Intended Audience :: Information Technology', 51 | 'Intended Audience :: System Administrators', 52 | 'License :: OSI Approved :: MIT License', 53 | 'Programming Language :: Python', 54 | 'Programming Language :: Python :: 2', 55 | 'Programming Language :: Python :: 2.6', 56 | 'Programming Language :: Python :: 2.7', 57 | 'Programming Language :: Python :: 3', 58 | 'Programming Language :: Python :: 3.4', 59 | 'Programming Language :: Python :: 3.5', 60 | 'Programming Language :: Python :: 3.6', 61 | 'Programming Language :: Python :: Implementation :: CPython', 62 | 'Programming Language :: Python :: Implementation :: PyPy', 63 | 'Topic :: Software Development', 64 | 'Topic :: Software Development :: Libraries', 65 | 'Topic :: Software Development :: Libraries :: Python Modules', 66 | 'Topic :: System', 67 | 'Topic :: System :: Logging', 68 | 'Topic :: System :: Systems Administration', 69 | 'Topic :: Terminals', 70 | ]) 71 | -------------------------------------------------------------------------------- /verboselogs/tests.py: -------------------------------------------------------------------------------- 1 | # Verbose, notice, and spam log levels for Python's logging module. 2 | # 3 | # Author: Peter Odding 4 | # Last Change: August 7, 2017 5 | # URL: https://verboselogs.readthedocs.io 6 | 7 | """Test suite for the `verboselogs` package.""" 8 | 9 | # Standard library modules. 10 | import logging 11 | import random 12 | import string 13 | import sys 14 | import unittest 15 | 16 | # Test dependencies. 17 | import mock 18 | 19 | # The module we're testing. 20 | import verboselogs 21 | 22 | 23 | class VerboseLogsTestCase(unittest.TestCase): 24 | 25 | """Container for the `verboselogs` tests.""" 26 | 27 | def test_install(self): 28 | """Test the :func:`verboselogs.install()` function.""" 29 | default_logger = logging.getLogger(random_string()) 30 | assert isinstance(default_logger, logging.Logger) 31 | verboselogs.install() 32 | custom_logger = logging.getLogger(random_string()) 33 | assert isinstance(custom_logger, verboselogs.VerboseLogger) 34 | 35 | def test_notice_method(self): 36 | """Test the :func:`~verboselogs.VerboseLogger.notice()` method.""" 37 | self.check_custom_level('notice') 38 | 39 | def test_spam_method(self): 40 | """Test the :func:`~verboselogs.VerboseLogger.spam()` method.""" 41 | self.check_custom_level('spam') 42 | 43 | def test_success_method(self): 44 | """Test the :func:`~verboselogs.VerboseLogger.success()` method.""" 45 | self.check_custom_level('success') 46 | 47 | def test_verbose_method(self): 48 | """Test the :func:`~verboselogs.VerboseLogger.verbose()` method.""" 49 | self.check_custom_level('verbose') 50 | 51 | def check_custom_level(self, name): 52 | """Check a custom log method.""" 53 | logger = verboselogs.VerboseLogger(random_string()) 54 | # Gotcha: If we use NOTSET (0) here the level will be inherited from 55 | # the parent logger and our custom log level may be filtered out. 56 | logger.setLevel(1) 57 | logger._log = mock.MagicMock() 58 | level = getattr(verboselogs, name.upper()) 59 | method = getattr(logger, name.lower()) 60 | message = "Any random message" 61 | method(message) 62 | logger._log.assert_called_with(level, message, ()) 63 | 64 | def test_pylint_plugin(self): 65 | """Test the :mod:`verboselogs.pylint` module.""" 66 | saved_args = sys.argv 67 | try: 68 | sys.argv = ['pylint', '--load-plugins', 'verboselogs.pylint', '--errors-only', 'verboselogs'] 69 | __import__('pylint').run_pylint() 70 | except SystemExit: 71 | pass 72 | finally: 73 | sys.argv = saved_args 74 | 75 | 76 | def random_string(length=25): 77 | """Generate a random string.""" 78 | return ''.join(random.choice(string.ascii_letters) for i in range(length)) 79 | -------------------------------------------------------------------------------- /verboselogs/__init__.py: -------------------------------------------------------------------------------- 1 | # Custom log levels for Python's logging module. 2 | # 3 | # Author: Peter Odding 4 | # Last Change: August 7, 2017 5 | # URL: https://verboselogs.readthedocs.io 6 | 7 | """ 8 | Custom log levels for Python's :mod:`logging` module. 9 | 10 | The :mod:`verboselogs` module defines the :data:`NOTICE`, :data:`SPAM`, 11 | :data:`SUCCESS` and :data:`VERBOSE` constants, the :class:`VerboseLogger` class 12 | and the :func:`add_log_level()` and :func:`install()` functions. 13 | 14 | At import time :func:`add_log_level()` is used to register the custom log 15 | levels :data:`NOTICE`, :data:`SPAM`, :data:`SUCCESS` and :data:`VERBOSE` with 16 | Python's :mod:`logging` module. 17 | """ 18 | 19 | import logging 20 | 21 | __version__ = '1.7' 22 | """Semi-standard module versioning.""" 23 | 24 | NOTICE = 25 25 | """ 26 | The numeric value of the 'notice' log level (a number). 27 | 28 | The value of :data:`NOTICE` positions the notice log level between the 29 | :data:`~logging.WARNING` and :data:`~logging.INFO` levels. Refer to `pull 30 | request #3 `_ for more 31 | details. 32 | 33 | :see also: The :func:`~VerboseLogger.notice()` method of the 34 | :class:`VerboseLogger` class. 35 | """ 36 | 37 | SPAM = 5 38 | """ 39 | The numeric value of the 'spam' log level (a number). 40 | 41 | The value of :data:`SPAM` positions the spam log level between the 42 | :data:`~logging.DEBUG` and :data:`~logging.NOTSET` levels. 43 | 44 | :see also: The :func:`~VerboseLogger.spam()` method of the 45 | :class:`VerboseLogger` class. 46 | """ 47 | 48 | SUCCESS = 35 49 | """ 50 | The numeric value of the 'success' log level (a number). 51 | 52 | The value of :data:`SUCCESS` positions the success log level between the 53 | :data:`~logging.WARNING` and :data:`~logging.ERROR` levels. Refer to `issue #4 54 | `_ for more details. 55 | 56 | :see also: The :func:`~VerboseLogger.success()` method of the 57 | :class:`VerboseLogger` class. 58 | """ 59 | 60 | VERBOSE = 15 61 | """ 62 | The numeric value of the 'verbose' log level (a number). 63 | 64 | The value of :data:`VERBOSE` positions the verbose log level between the 65 | :data:`~logging.INFO` and :data:`~logging.DEBUG` levels. 66 | 67 | :see also: The :func:`~VerboseLogger.verbose()` method of the 68 | :class:`VerboseLogger` class. 69 | """ 70 | 71 | 72 | def install(): 73 | """ 74 | Make :class:`VerboseLogger` the default logger class. 75 | 76 | The :func:`install()` function uses :func:`~logging.setLoggerClass()` to 77 | configure :class:`VerboseLogger` as the default class for all loggers 78 | created by :func:`logging.getLogger()` after :func:`install()` has been 79 | called. Here's how it works: 80 | 81 | .. code-block:: python 82 | 83 | import logging 84 | import verboselogs 85 | 86 | verboselogs.install() 87 | logger = logging.getLogger(__name__) # will be a VerboseLogger instance 88 | """ 89 | logging.setLoggerClass(VerboseLogger) 90 | 91 | 92 | def add_log_level(value, name): 93 | """ 94 | Add a new log level to the :mod:`logging` module. 95 | 96 | :param value: The log level's number (an integer). 97 | :param name: The name for the log level (a string). 98 | """ 99 | logging.addLevelName(value, name) 100 | setattr(logging, name, value) 101 | 102 | 103 | # Define the NOTICE log level. 104 | add_log_level(NOTICE, 'NOTICE') 105 | 106 | # Define the SPAM log level. 107 | add_log_level(SPAM, 'SPAM') 108 | 109 | # Define the SUCCESS log level. 110 | add_log_level(SUCCESS, 'SUCCESS') 111 | 112 | # Define the VERBOSE log level. 113 | add_log_level(VERBOSE, 'VERBOSE') 114 | 115 | 116 | class VerboseLogger(logging.Logger): 117 | 118 | """ 119 | Custom logger class to support the additional logging levels. 120 | 121 | This subclass of :class:`logging.Logger` adds support for the additional 122 | logging methods :func:`notice()`, :func:`spam()`, :func:`success()` and 123 | :func:`verbose()`. 124 | 125 | You can use :func:`verboselogs.install()` to make :class:`VerboseLogger` 126 | the default logger class. 127 | """ 128 | 129 | def __init__(self, *args, **kw): 130 | """ 131 | Initialize a :class:`VerboseLogger` object. 132 | 133 | :param args: Refer to the superclass (:class:`logging.Logger`). 134 | :param kw: Refer to the superclass (:class:`logging.Logger`). 135 | 136 | This method first initializes the superclass and then it sets the root 137 | logger as the parent of this logger. 138 | 139 | The function :func:`logging.getLogger()` is normally responsible for 140 | defining the hierarchy of logger objects however because verbose 141 | loggers can be created by calling the :class:`VerboseLogger` 142 | constructor, we're responsible for defining the parent relationship 143 | ourselves. 144 | """ 145 | logging.Logger.__init__(self, *args, **kw) 146 | self.parent = logging.getLogger() 147 | 148 | def notice(self, msg, *args, **kw): 149 | """Log a message with level :data:`NOTICE`. The arguments are interpreted as for :func:`logging.debug()`.""" 150 | if self.isEnabledFor(NOTICE): 151 | self._log(NOTICE, msg, args, **kw) 152 | 153 | def spam(self, msg, *args, **kw): 154 | """Log a message with level :data:`SPAM`. The arguments are interpreted as for :func:`logging.debug()`.""" 155 | if self.isEnabledFor(SPAM): 156 | self._log(SPAM, msg, args, **kw) 157 | 158 | def success(self, msg, *args, **kw): 159 | """Log a message with level :data:`SUCCESS`. The arguments are interpreted as for :func:`logging.debug()`.""" 160 | if self.isEnabledFor(SUCCESS): 161 | self._log(SUCCESS, msg, args, **kw) 162 | 163 | def verbose(self, msg, *args, **kw): 164 | """Log a message with level :data:`VERBOSE`. The arguments are interpreted as for :func:`logging.debug()`.""" 165 | if self.isEnabledFor(VERBOSE): 166 | self._log(VERBOSE, msg, args, **kw) 167 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | verboselogs: Verbose logging level for Python's logging module 2 | ============================================================== 3 | 4 | .. image:: https://travis-ci.org/xolox/python-verboselogs.svg?branch=master 5 | :target: https://travis-ci.org/xolox/python-verboselogs 6 | 7 | .. image:: https://coveralls.io/repos/xolox/python-verboselogs/badge.png?branch=master 8 | :target: https://coveralls.io/r/xolox/python-verboselogs?branch=master 9 | 10 | The verboselogs_ package extends Python's logging_ module to add the log levels 11 | NOTICE_, SPAM_, SUCCESS_ and VERBOSE_: 12 | 13 | - The NOTICE level sits between the predefined WARNING and INFO levels. 14 | - The SPAM level sits between the predefined DEBUG and NOTSET levels. 15 | - The SUCCESS level sits between the predefined WARNING and ERROR levels. 16 | - The VERBOSE level sits between the predefined INFO and DEBUG levels. 17 | 18 | The code to do this is simple and short, but I still don't want to copy/paste 19 | it to every project I'm working on, hence this package. It's currently tested 20 | on Python 2.6, 2.7, 3.4, 3.5, 3.6 and PyPy. 21 | 22 | .. contents:: 23 | :local: 24 | :depth: 2 25 | 26 | Installation 27 | ------------ 28 | 29 | The verboselogs package is available on PyPI_ which means installation should 30 | be as simple as: 31 | 32 | .. code-block:: sh 33 | 34 | $ pip install verboselogs 35 | 36 | There's actually a multitude of ways to install Python packages (e.g. the `per 37 | user site-packages directory`_, `virtual environments`_ or just installing 38 | system wide) and I have no intention of getting into that discussion here, so 39 | if this intimidates you then read up on your options before returning to these 40 | instructions ;-). 41 | 42 | Usage 43 | ----- 44 | 45 | It's very simple to start using the verboselogs package: 46 | 47 | >>> import logging, verboselogs 48 | >>> logger = verboselogs.VerboseLogger('verbose-demo') 49 | >>> logger.addHandler(logging.StreamHandler()) 50 | >>> logger.setLevel(logging.VERBOSE) 51 | >>> logger.verbose("Can we have verbose logging? %s", "Yes we can!") 52 | 53 | Here's a skeleton of a very simple Python program with a command line interface 54 | and configurable logging: 55 | 56 | .. code-block:: python 57 | 58 | """ 59 | Usage: demo.py [OPTIONS] 60 | 61 | This is the usage message of demo.py. Usually 62 | this text explains how to use the program. 63 | 64 | Supported options: 65 | -v, --verbose make more noise 66 | -h, --help show this message and exit 67 | """ 68 | 69 | import getopt 70 | import logging 71 | import sys 72 | import verboselogs 73 | 74 | logger = verboselogs.VerboseLogger('demo') 75 | logger.addHandler(logging.StreamHandler()) 76 | logger.setLevel(logging.INFO) 77 | 78 | # Command line option defaults. 79 | verbosity = 0 80 | 81 | # Parse command line options. 82 | opts, args = getopt.getopt(sys.argv[1:], 'vqh', ['verbose', 'quiet', 'help']) 83 | 84 | # Map command line options to variables. 85 | for option, argument in opts: 86 | if option in ('-v', '--verbose'): 87 | verbosity += 1 88 | elif option in ('-q', '--quiet'): 89 | verbosity -= 1 90 | elif option in ('-h', '--help'): 91 | print __doc__.strip() 92 | sys.exit(0) 93 | else: 94 | assert False, "Unhandled option!" 95 | 96 | # Configure logger for requested verbosity. 97 | if verbosity >= 4: 98 | logger.setLevel(logging.SPAM) 99 | elif verbosity >= 3: 100 | logger.setLevel(logging.DEBUG) 101 | elif verbosity >= 2: 102 | logger.setLevel(logging.VERBOSE) 103 | elif verbosity >= 1: 104 | logger.setLevel(logging.NOTICE) 105 | elif verbosity < 0: 106 | logger.setLevel(logging.WARNING) 107 | 108 | # Your code goes here. 109 | ... 110 | 111 | If you want to set VerboseLogger_ as the default logging class for all 112 | subsequent logger instances, you can do so using `verboselogs.install()`_: 113 | 114 | .. code-block:: python 115 | 116 | import logging 117 | import verboselogs 118 | 119 | verboselogs.install() 120 | logger = logging.getLogger(__name__) # will be a VerboseLogger instance 121 | 122 | Pylint plugin 123 | ------------- 124 | 125 | If using the above `verboselogs.install()`_ approach, Pylint_ is not smart 126 | enough to recognize that logging_ is using verboselogs, resulting in errors 127 | like:: 128 | 129 | E:285,24: Module 'logging' has no 'VERBOSE' member (no-member) 130 | E:375,12: Instance of 'RootLogger' has no 'verbose' member (no-member) 131 | 132 | To fix this, verboselogs provides a Pylint plugin verboselogs.pylint_ which, 133 | when loaded with ``pylint --load-plugins verboselogs.pylint``, adds the 134 | verboselogs methods and constants to Pylint's understanding of the logging_ 135 | module. 136 | 137 | Overview of logging levels 138 | -------------------------- 139 | 140 | The table below shows the names, `numeric values`_ and descriptions_ of the 141 | predefined log levels and the VERBOSE, NOTICE, and SPAM levels defined by this 142 | package, plus some notes that I added. 143 | 144 | ======== ===== ============================= ============================= 145 | Level Value Description Notes 146 | ======== ===== ============================= ============================= 147 | NOTSET 0 When a logger is created, the This level isn't intended to 148 | level is set to NOTSET (note be used explicitly, however 149 | that the root logger is when a logger has its level 150 | created with level WARNING). set to NOTSET its effective 151 | level will be inherited from 152 | the parent logger. 153 | SPAM 5 Way too verbose for regular 154 | debugging, but nice to have 155 | when someone is getting 156 | desperate in a late night 157 | debugging session and decides 158 | that they want as much 159 | instrumentation as possible! 160 | :-) 161 | DEBUG 10 Detailed information, Usually at this level the 162 | typically of interest only logging output is so low 163 | when diagnosing problems. level that it's not useful 164 | to users who are not 165 | familiar with the software's 166 | internals. 167 | VERBOSE 15 Detailed information that 168 | should be understandable to 169 | experienced users to provide 170 | insight in the software's 171 | behavior; a sort of high 172 | level debugging information. 173 | INFO 20 Confirmation that things 174 | are working as expected. 175 | NOTICE 25 Auditing information about 176 | things that have multiple 177 | success paths or may need to 178 | be reverted. 179 | WARNING 30 An indication that something 180 | unexpected happened, or 181 | indicative of some problem 182 | in the near future (e.g. 183 | ‘disk space low’). The 184 | software is still working 185 | as expected. 186 | SUCCESS 35 A very explicit confirmation 187 | of success. 188 | ERROR 40 Due to a more serious 189 | problem, the software has not 190 | been able to perform some 191 | function. 192 | CRITICAL 50 A serious error, indicating 193 | that the program itself may 194 | be unable to continue 195 | running. 196 | ======== ===== ============================= ============================= 197 | 198 | Contact 199 | ------- 200 | 201 | The latest version of verboselogs is available on PyPI_ and GitHub_. The 202 | documentation is hosted on `Read the Docs`_. For bug reports please create an 203 | issue on GitHub_. If you have questions, suggestions, etc. feel free to send me 204 | an e-mail at `peter@peterodding.com`_. 205 | 206 | License 207 | ------- 208 | 209 | This software is licensed under the `MIT license`_. 210 | 211 | © 2017 Peter Odding. 212 | 213 | .. External references: 214 | .. _descriptions: http://docs.python.org/howto/logging.html#when-to-use-logging 215 | .. _GitHub: https://github.com/xolox/python-verboselogs 216 | .. _logging: http://docs.python.org/library/logging.html 217 | .. _MIT license: http://en.wikipedia.org/wiki/MIT_License 218 | .. _NOTICE: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.NOTICE 219 | .. _numeric values: http://docs.python.org/howto/logging.html#logging-levels 220 | .. _per user site-packages directory: https://www.python.org/dev/peps/pep-0370/ 221 | .. _peter@peterodding.com: peter@peterodding.com 222 | .. _Pylint: https://pypi.python.org/pypi/pylint 223 | .. _PyPI: https://pypi.python.org/pypi/verboselogs 224 | .. _Read the Docs: https://verboselogs.readthedocs.io 225 | .. _SPAM: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.SPAM 226 | .. _SUCCESS: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.SUCCESS 227 | .. _VERBOSE: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.VERBOSE 228 | .. _VerboseLogger: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.VerboseLogger 229 | .. _verboselogs.install(): http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.install 230 | .. _verboselogs.pylint: http://verboselogs.readthedocs.io/en/latest/api.html#verboselogs.pylint 231 | .. _verboselogs: https://pypi.python.org/pypi/verboselogs/ 232 | .. _virtual environments: http://docs.python-guide.org/en/latest/dev/virtualenvs/ 233 | --------------------------------------------------------------------------------