diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index a263f99..0000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = oslo_log -omit = oslo_log/tests/* - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f6d6848..0000000 --- a/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg* -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage* -cover -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp - -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 25d1324..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.log.git \ No newline at end of file diff --git a/.mailmap b/.mailmap deleted file mode 100644 index cc92f17..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# \ No newline at end of file diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 0edde41..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ ./oslo_log $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 101119d..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/oslo.log \ No newline at end of file diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index a127609..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -oslo.log Style Commandments -====================================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/README.rst b/README.rst deleted file mode 100644 index 8bc9682..0000000 --- a/README.rst +++ /dev/null @@ -1,21 +0,0 @@ -================================ -oslo.log -- Oslo Logging Library -================================ - -.. image:: https://img.shields.io/pypi/v/oslo.log.svg - :target: https://pypi.python.org/pypi/oslo.log/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.log.svg - :target: https://pypi.python.org/pypi/oslo.log/ - :alt: Downloads - -The oslo.log (logging) configuration library provides standardized -configuration for all openstack projects. It also provides custom -formatters, handlers and support for context specific -logging (like resource id's etc). - -* Free software: Apache license -* Documentation: http://docs.openstack.org/developer/oslo.log -* Source: http://git.openstack.org/cgit/openstack/oslo.log -* Bugs: http://bugs.launchpad.net/oslo.log diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..bf0a020 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +Use instead the project deb-python-oslo.log at +http://git.openstack.org/cgit/openstack/deb-python-oslo.log . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab8..0000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/doc/source/api/fixtures.rst b/doc/source/api/fixtures.rst deleted file mode 100644 index 97f69ab..0000000 --- a/doc/source/api/fixtures.rst +++ /dev/null @@ -1,9 +0,0 @@ -================== - oslo_log.fixture -================== - -.. module:: oslo_log.fixture - -.. autofunction:: oslo_log.fixture.get_logging_handle_error_fixture - -.. autoclass:: oslo_log.fixture.SetLogLevel diff --git a/doc/source/api/formatters.rst b/doc/source/api/formatters.rst deleted file mode 100644 index 5ff6fd8..0000000 --- a/doc/source/api/formatters.rst +++ /dev/null @@ -1,8 +0,0 @@ -===================== - oslo_log.formatters -===================== - -.. automodule:: oslo_log.formatters - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/api/handlers.rst b/doc/source/api/handlers.rst deleted file mode 100644 index b02a32c..0000000 --- a/doc/source/api/handlers.rst +++ /dev/null @@ -1,8 +0,0 @@ -===================== - oslo_log.handlers -===================== - -.. automodule:: oslo_log.handlers - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/api/helpers.rst b/doc/source/api/helpers.rst deleted file mode 100644 index 747905a..0000000 --- a/doc/source/api/helpers.rst +++ /dev/null @@ -1,8 +0,0 @@ -================== - oslo_log.helpers -================== - -.. automodule:: oslo_log.helpers - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/api/log.rst b/doc/source/api/log.rst deleted file mode 100644 index b4d42be..0000000 --- a/doc/source/api/log.rst +++ /dev/null @@ -1,12 +0,0 @@ -============== - oslo_log.log -============== - -.. automodule:: oslo_log.log - :members: - :undoc-members: - :show-inheritance: - -.. seealso:: - - :doc:`../usage` diff --git a/doc/source/api/versionutils.rst b/doc/source/api/versionutils.rst deleted file mode 100644 index 9be5a9c..0000000 --- a/doc/source/api/versionutils.rst +++ /dev/null @@ -1,6 +0,0 @@ -======================= - oslo_log.versionutils -======================= - -.. automodule:: oslo_log.versionutils - :members: diff --git a/doc/source/api/watchers.rst b/doc/source/api/watchers.rst deleted file mode 100644 index 367d8c2..0000000 --- a/doc/source/api/watchers.rst +++ /dev/null @@ -1,12 +0,0 @@ -================== - oslo_log.watchers -================== - -.. automodule:: oslo_log.watchers - :members: - :undoc-members: - :show-inheritance: - -.. seealso:: - - :doc:`../usage` diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index f64b726..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - #'sphinx.ext.intersphinx', - 'oslosphinx', - 'oslo_config.sphinxext', -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.log' -copyright = u'2014, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/configfiles/example_nova.rst b/doc/source/configfiles/example_nova.rst deleted file mode 100644 index 36a42b3..0000000 --- a/doc/source/configfiles/example_nova.rst +++ /dev/null @@ -1,84 +0,0 @@ -========================================= - Example Configuration File for ``nova`` -========================================= - -This sample configuration file demonstrates how the OpenStack compute -service (nova) might be configured. - -.. literalinclude:: nova_sample.conf - :language: ini - :prepend: # nova_sample.conf - -Two logger nodes are set up, ``root`` and ``nova``. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 1-2 - -Several handlers are created, to send messages to different outputs. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 4-5 - -And two formatters are created to be used based on whether the logging -location will have OpenStack request context information available or -not. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 7-8 - -The ``root`` logger is configured to send messages to the ``null`` -handler, silencing most messages that are not part of the nova -application code namespace. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 10-12 - -The ``nova`` logger is configured to send messages marked as ``INFO`` -and higher level to the standard error stream. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 14-17 - -The ``amqp`` and ``amqplib`` loggers, used by the module that connects -the application to the message bus, are configured to emit warning -messages to the standard error stream. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 19-27 - -The ``sqlalchemy`` logger, used by the module that connects the -application to the database, is configured to emit warning messages to -the standard error stream. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 29-35 - -Similarly, ``boto``, ``suds``, and ``eventlet.wsgi.server`` are -configured to send warnings to the standard error stream. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 37-53 - -The ``stderr`` handler, being used by most of the loggers above, is -configured to write to the standard error stream on the console. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 55-58 - -The ``stderr`` handler uses the ``context`` formatter, which takes its -configuration settings from ``oslo.config``. - -.. literalinclude:: nova_sample.conf - :language: ini - :lines: 80-81 - -The ``stdout`` and ``syslog`` handlers are defined, but not used. diff --git a/doc/source/configfiles/index.rst b/doc/source/configfiles/index.rst deleted file mode 100644 index 5b1c769..0000000 --- a/doc/source/configfiles/index.rst +++ /dev/null @@ -1,47 +0,0 @@ -============================== - Advanced Configuration Files -============================== - -The oslo.config options described in :doc:`/opts` make it easy to -enable some default logging configuration behavior such as setting the -default log level and output file. For more advanced configurations -using translations or multiple output destinations oslo.log relies on -the Python standard library logging module configuration file -features. - -The configuration file can be used to tie together the loggers, -handlers, and formatters and provide all of the necessary -configuration values to enable any desired behavior. Refer to the -`Python logging Module Tutorial`_ for descriptions of these concepts. - -Logger Names -============ - -Loggers are configured by name. Most OpenStack applications use logger -names based on the source file where the message is coming from. A -file named ``myapp/package/module.py`` corresponds to a logger named -``myapp.package.module``. - -Loggers are configured in a tree structure, and the names reflect -their location in this hierarchy. It is not necessary to configure -every logger, since messages are passed up the tree during -processing. To control the logging for ``myapp``, for example, it is -only necessary to set up a logger for ``myapp`` and not -``myapp.package.module``. - -The base of the tree, through which all log message may pass unless -otherwise discarded, is called the ``root`` logger. - -Example Files -============= - -.. toctree:: - :glob: - - example* - -.. seealso:: - - * `Python logging Module Tutorial`_ - -.. _Python logging Module Tutorial: https://docs.python.org/2.7/howto/logging.html diff --git a/doc/source/configfiles/nova_sample.conf b/doc/source/configfiles/nova_sample.conf deleted file mode 100644 index 6841819..0000000 --- a/doc/source/configfiles/nova_sample.conf +++ /dev/null @@ -1,84 +0,0 @@ -[loggers] -keys = root, nova - -[handlers] -keys = stderr, stdout, watchedfile, syslog, null - -[formatters] -keys = context, default - -[logger_root] -level = WARNING -handlers = null - -[logger_nova] -level = INFO -handlers = stderr -qualname = nova - -[logger_amqp] -level = WARNING -handlers = stderr -qualname = amqp - -[logger_amqplib] -level = WARNING -handlers = stderr -qualname = amqplib - -[logger_sqlalchemy] -level = WARNING -handlers = stderr -qualname = sqlalchemy -# "level = INFO" logs SQL queries. -# "level = DEBUG" logs SQL queries and results. -# "level = WARNING" logs neither. (Recommended for production systems.) - -[logger_boto] -level = WARNING -handlers = stderr -qualname = boto - -# NOTE(mikal): suds is used by the vmware driver, removing this will -# cause many extraneous log lines for their tempest runs. Refer to -# https://review.openstack.org/#/c/219225/ for details. -[logger_suds] -level = INFO -handlers = stderr -qualname = suds - -[logger_eventletwsgi] -level = WARNING -handlers = stderr -qualname = eventlet.wsgi.server - -[handler_stderr] -class = StreamHandler -args = (sys.stderr,) -formatter = context - -[handler_stdout] -class = StreamHandler -args = (sys.stdout,) -formatter = context - -[handler_watchedfile] -class = handlers.WatchedFileHandler -args = ('nova.log',) -formatter = context - -[handler_syslog] -class = handlers.SysLogHandler -args = ('/dev/log', handlers.SysLogHandler.LOG_USER) -formatter = context - -[handler_null] -class = logging.NullHandler -formatter = default -args = () - -[formatter_context] -class = oslo_log.formatters.ContextFormatter - -[formatter_default] -format = %(message)s diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 97344d1..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============ -Contributing -============ - -.. include:: ../../CONTRIBUTING.rst \ No newline at end of file diff --git a/doc/source/examples.rst b/doc/source/examples.rst deleted file mode 100644 index 007ee48..0000000 --- a/doc/source/examples.rst +++ /dev/null @@ -1,60 +0,0 @@ -========== - Examples -========== - -.. _examples: - -These files can be found in the docs/source/examples directory of -the git source of this project. They can also be found at the -`online git respository`_ of this project. - -.. _online git respository: http://git.openstack.org/cgit/openstack/oslo.log/tree/doc/source/examples - - -python_logging.py ------------------ - -.. _example_python_logging.py: - -.. highlight:: python -.. literalinclude:: examples/python_logging.py - :linenos: - -oslo_logging.py ---------------- - -.. _example_oslo_logging.py: - -.. literalinclude:: examples/oslo_logging.py - -usage.py --------- - -.. _example_usage.py: - -.. literalinclude:: examples/usage.py - :linenos: - -usage_helper.py ---------------- - -.. _example_usage_helper.py: - -.. literalinclude:: examples/usage_helper.py - :linenos: - -usage_i18n.py -------------- - -.. _example_usage_i18n.py: - -.. literalinclude:: examples/usage_i18n.py - :linenos: - -usage_context.py ----------------- - -.. _example_usage_context.py: - -.. literalinclude:: examples/usage_context.py - :linenos: diff --git a/doc/source/examples/_i18n.py b/doc/source/examples/_i18n.py deleted file mode 100644 index 3bc9256..0000000 --- a/doc/source/examples/_i18n.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A demonstration of oslo.i18n integration module that is used - in projects wanting to implement Oslo i18n translation. - - See http://docs.openstack.org/developer/oslo.i18n/usage.html -""" - -import oslo_i18n - -DOMAIN = "demo" - -_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# The contextual translation function using the name "_C" -_C = _translators.contextual_form - -# The plural translation function using the name "_P" -_P = _translators.plural_form - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical - - -def get_available_languages(): - return oslo_i18n.get_available_languages(DOMAIN) diff --git a/doc/source/examples/oslo_logging.py b/doc/source/examples/oslo_logging.py deleted file mode 100644 index c002c8e..0000000 --- a/doc/source/examples/oslo_logging.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A minimal syntax example of Oslo Logging""" - -from oslo_config import cfg -from oslo_log import log as logging - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF -DOMAIN = "demo" - -logging.register_options(CONF) -logging.setup(CONF, DOMAIN) - -# Oslo Logging uses INFO as default -LOG.info("Oslo Logging") -LOG.warning("Oslo Logging") -LOG.error("Oslo Logging") diff --git a/doc/source/examples/python_logging.py b/doc/source/examples/python_logging.py deleted file mode 100644 index 44605da..0000000 --- a/doc/source/examples/python_logging.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A syntax example of Python Logging""" - -import logging - -LOG = logging.getLogger(__name__) - -# Define a default handler at INFO logging level -logging.basicConfig(level=logging.INFO) - -LOG.info("Python Standard Logging") -LOG.warning("Python Standard Logging") -LOG.error("Python Standard Logging") diff --git a/doc/source/examples/usage.py b/doc/source/examples/usage.py deleted file mode 100644 index 1afcd36..0000000 --- a/doc/source/examples/usage.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A usage example of Oslo Logging - -This example requires the following package to be installed. - -$ pip install oslo.log - -Additional Oslo packages installed include oslo.config, oslo.context, -oslo.i18n, osli.serialization and oslo.utils. - -More information about Oslo Logging can be found at: - - http://docs.openstack.org/developer/oslo.log/usage.html -""" - -from oslo_config import cfg -from oslo_log import log as logging - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF -DOMAIN = 'demo' - - -def prepare(): - """Prepare Oslo Logging (2 or 3 steps) - - Use of Oslo Logging involves the following: - - * logging.register_options - * logging.set_defaults (optional) - * logging.setup - """ - - # Required step to register common, logging and generic configuration - # variables - logging.register_options(CONF) - - # Optional step to set new defaults if necessary for - # * logging_context_format_string - # * default_log_levels - # - # These variables default to respectively: - # - # import oslo_log - # oslo_log._options.DEFAULT_LOG_LEVELS - # oslo_log._options.log_opts[0].default - # - - extra_log_level_defaults = [ - 'dogpile=INFO', - 'routes=INFO' - ] - - logging.set_defaults( - default_log_levels=logging.get_default_log_levels() + - extra_log_level_defaults) - - # Required setup based on configuration and domain - logging.setup(CONF, DOMAIN) - - -if __name__ == '__main__': - prepare() - # NOTE: These examples do not demonstration Oslo i18n messages - - LOG.info("Welcome to Oslo Logging") - LOG.debug("A debugging message") - LOG.warning("A warning occurred") - LOG.error("An error occurred") - try: - raise Exception("This is exceptional") - except Exception: - LOG.exception("An Exception occurred") diff --git a/doc/source/examples/usage_context.py b/doc/source/examples/usage_context.py deleted file mode 100644 index 15a3c07..0000000 --- a/doc/source/examples/usage_context.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A usage example of Oslo Logging with context - -This example requires the following package to be installed. - -$ pip install oslo.log - -Additional Oslo packages installed include oslo.config, oslo.context, -oslo.i18n, osli.serialization and oslo.utils. - -More information about Oslo Logging can be found at: - - http://docs.openstack.org/developer/oslo.log/usage.html - http://docs.openstack.org/developer/oslo.context/usage.html -""" - -from oslo_config import cfg -from oslo_context import context -from oslo_log import log as logging - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF -DOMAIN = 'demo' - - -def prepare(): - """Prepare Oslo Logging (2 or 3 steps) - - Use of Oslo Logging involves the following: - - * logging.register_options - * logging.set_defaults (optional) - * logging.setup - """ - - # Required step to register common, logging and generic configuration - # variables - logging.register_options(CONF) - - # Optional step to set new defaults if necessary for - # * logging_context_format_string - # * default_log_levels - # - # These variables default to respectively: - # - # import oslo_log - # oslo_log._options.DEFAULT_LOG_LEVELS - # oslo_log._options.log_opts[0].default - # - - extra_log_level_defaults = [ - 'dogpile=INFO', - 'routes=INFO' - ] - - logging.set_defaults( - default_log_levels=logging.get_default_log_levels() + - extra_log_level_defaults) - - # Required setup based on configuration and domain - logging.setup(CONF, DOMAIN) - - -if __name__ == '__main__': - prepare() - - LOG.info("Welcome to Oslo Logging") - LOG.info("Without context") - context.RequestContext(user='6ce90b4d', - tenant='d6134462', - domain='a6b9360e') - LOG.info("With context") diff --git a/doc/source/examples/usage_helper.py b/doc/source/examples/usage_helper.py deleted file mode 100644 index dcd76eb..0000000 --- a/doc/source/examples/usage_helper.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A usage example with helper debugging of minimum Oslo Logging - -This example requires the following package to be installed. - -$ pip install oslo.log - -Additional Oslo packages installed include oslo.config, oslo.context, -oslo.i18n, osli.serialization and oslo.utils. - -More information about Oslo Logging can be found at: - - http://docs.openstack.org/developer/oslo.log/usage.html -""" - -# Use default Python logging to display running output -import logging as py_logging -from oslo_config import cfg -from oslo_log import log as logging - - -LOG = py_logging.getLogger(__name__) -CONF = cfg.CONF -DOMAIN = "demo" - - -def prepare(): - """Prepare Oslo Logging (2 or 3 steps) - - Use of Oslo Logging involves the following: - - * logging.register_options - * logging.set_defaults (optional) - * logging.setup - """ - - LOG.debug("Prepare Oslo Logging") - - LOG.info("Size of configuration options before %d", len(CONF)) - - # Required step to register common, logging and generic configuration - # variables - logging.register_options(CONF) - - LOG.info("Size of configuration options after %d", len(CONF)) - - # Optional step to set new defaults if necessary for - # * logging_context_format_string - # * default_log_levels - # - # These variables default to respectively: - # - # import oslo_log - # oslo_log._options.DEFAULT_LOG_LEVELS - # oslo_log._options.log_opts[0].default - # - - custom_log_level_defaults = logging.get_default_log_levels() + [ - 'dogpile=INFO', - 'routes=INFO' - ] - - logging.set_defaults(default_log_levels=custom_log_level_defaults) - - # NOTE: We cannot show the contents of the CONF object - # after register_options() because accessing this caches - # the default_log_levels subsequently modified with set_defaults() - LOG.info("List of Oslo Logging configuration options and current values") - LOG.info("=" * 80) - for c in CONF: - LOG.info("%s = %s" % (c, CONF[c])) - LOG.info("=" * 80) - - # Required setup based on configuration and domain - logging.setup(CONF, DOMAIN) - - -if __name__ == '__main__': - py_logging.basicConfig(level=py_logging.DEBUG) - - prepare() - # NOTE: These examples do not demonstration Oslo i18n messages - LOG.info("Welcome to Oslo Logging") - LOG.debug("A debugging message") - LOG.warning("A warning occurred") - LOG.error("An error occurred") - try: - raise Exception("This is exceptional") - except Exception: - LOG.exception("An Exception occurred") diff --git a/doc/source/examples/usage_i18n.py b/doc/source/examples/usage_i18n.py deleted file mode 100644 index 5961b75..0000000 --- a/doc/source/examples/usage_i18n.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""A usage example of Oslo Logging with Oslo i18n - -This example requires the following package to be installed. -$ pip install oslo.log - -Additional Oslo packages installed include oslo.config, oslo.context, -oslo.i18n, osli.serialization and oslo.utils. - -More information about Oslo Logging can be found at: - - http://docs.openstack.org/developer/oslo.log/usage.html - http://docs.openstack.org/developer/oslo.i18n/usage.html -""" - -from oslo_config import cfg -from oslo_log import log as logging -from _i18n import _, _LI, _LW, _LE # noqa - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF -DOMAIN = 'demo' - - -def prepare(): - """Prepare Oslo Logging (2 or 3 steps) - - Use of Oslo Logging involves the following: - - * logging.register_options - * logging.set_defaults (optional) - * logging.setup - """ - - # Required step to register common, logging and generic configuration - # variables - logging.register_options(CONF) - - # Optional step to set new defaults if necessary for - # * logging_context_format_string - # * default_log_levels - # - # These variables default to respectively: - # - # import oslo_log - # oslo_log._options.DEFAULT_LOG_LEVELS - # oslo_log._options.log_opts[0].default - # - - extra_log_level_defaults = [ - 'dogpile=INFO', - 'routes=INFO' - ] - - logging.set_defaults( - default_log_levels=logging.get_default_log_levels() + - extra_log_level_defaults) - - # Required setup based on configuration and domain - logging.setup(CONF, DOMAIN) - - -if __name__ == '__main__': - prepare() - # NOTE: These examples use Oslo i18n marker functions - - LOG.info(_LI("Welcome to Oslo Logging")) - LOG.debug("A debugging message") # Debug messages are not translated - LOG.warning(_LW("A warning occurred")) - LOG.error(_LE("An error occurred")) - try: - raise Exception(_("This is exceptional")) - except Exception: - LOG.exception(_LE("An Exception occurred")) diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 4e3ef9d..0000000 --- a/doc/source/history.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. Add a fake link so that the reference to "assert_" in one of the - changelog messages that looks like a reST link but isn't has - something to resolve to. - -.. _assert: https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertTrue - -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 0cf0d6c..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,36 +0,0 @@ -================================ -oslo.log -- Oslo Logging Library -================================ - -The oslo.log (logging) configuration library provides standardized -configuration for all openstack projects. It also provides custom -formatters, handlers and support for context specific -logging (like resource id's etc). - -.. toctree:: - :maxdepth: 1 - - installation - usage - migration - opts - configfiles/index - examples - contributing - history - -API Documentation -================= - -.. toctree:: - :maxdepth: 2 - :glob: - - api/* - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index aebf51d..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install oslo.log - -To use ``oslo_log.fixture``, some additional dependencies -are needed. They can be installed using the ``fixtures`` extra:: - - $ pip install 'oslo.log[fixtures]' diff --git a/doc/source/migration.rst b/doc/source/migration.rst deleted file mode 100644 index 25d13c4..0000000 --- a/doc/source/migration.rst +++ /dev/null @@ -1,119 +0,0 @@ -Migrating from Oslo Incubator to oslo.log -========================================= - -Applications using the incubated version of the logging code from Oslo -may need to make some extra changes. - -What do I import? ------------------ - -Our goal is to allow most libraries to import the Python standard -library module, ``logging``, and not require ``oslo.log`` -directly. Applications may do the same, but if an application takes -advantage of features like passing keywords through to the context for -logging, it is likely to be less confusing to use ``oslo.log`` -everywhere, rather than have different types of loggers in different -modules of the application. - -No more ``audit()`` -------------------- - -The ``audit()`` method of the old ``ContextAdapter`` class no longer -exists. We agreed in the `cross project spec`_ to stop using audit -level anyway, so those calls should be replaced with calls to -``info()``. - -.. _cross project spec: http://git.openstack.org/cgit/openstack/openstack-specs/tree/specs/log-guidelines.rst - -Deprecation tools moved to ``versionutils`` -------------------------------------------- - -The :meth:`deprecated` decorator and :class:`DeprecatedConfig` have -moved to :mod:`oslo_log.versionutils`. Replace ``LOG.deprecated()`` -with :mod:`oslo_log.versionutils.report_deprecated_feature`, passing a -local logger object as the first argument so the log message includes -the location information. - -No more implicit conversion to unicode/str ------------------------------------------- - -The old :class:`ContextAdapter` used to convert anything given to it -to a :class:`unicode` object before passing it to lower layers of the -logging code. The new logging configuration uses a formatter instead -of an adapter, so this conversion is no longer possible. All message -format strings therefore need to be passed as unicode objects -- -that's strictly :class:`unicode`, not :class:`str`. If a message has -no interpolation for extra parameters, a byte string can be used. - -The most common place to encounter this is where :meth:`Logger.error` -is used by passing an exception object as the first argument. - -:: - - # Old style - try: - do_something() - except Exception as err: - LOG.error(err) - -Now, the error should be converted to unicode either by calling -:func:`six.text_type` or by using a unicode formatting string to -provide context. It's even better to replace the redundant message -produced by passing the exception with a useful message. - -:: - - # New style, preferred approach - from myapp._i18n import _LE # see oslo.i18n - try: - do_something() - except Exception as err: - LOG.exception(_LE(u"do_something couldn't do something")) - - # New style, with exception - from myapp._i18n import _LE # see oslo.i18n - try: - do_something() - except Exception as err: - LOG.error(_LE(u"do_something couldn't do something: %s"), err) - - # New style, alternate without context - import six - try: - do_something() - except Exception as err: - LOG.error(six.text_type(err)) - -Failure to do this for exceptions or other objects containing -translatable strings from ``oslo.i18n`` results in an exception when -the :class:`_Message` instance is combined in unsupported ways with -the default formatting string inside the :mod:`logging` module in the -standard library. - -Changes to App Initialization ------------------------------ - -The logging options are no longer registered on the global -configuration object defined in ``oslo.config``, and need to be -registered explicitly on the configuration object being used by the -application. Do this by calling :func:`~oslo_log.log.register_options` -before parsing command line options. - -The same configuration option passed to -:func:`~oslo_log.log.register_options` should also be passed as the -first argument to :func:`~oslo_log.log.setup`. - -See :ref:`usage-app` for more details about application setup. - -Passing Context ---------------- - -Applications are expected to be using -:class:`oslo_context.context.RequestContext` as the base class for -their application-specific context classes. The base class manages a -thread-local storage for the "current" context object so that -``oslo.log`` can retrieve it without having the value passed in -explicitly. This ensures that all log messages include the same -context information, such as the request id and user -identification. See the ``oslo.context`` documentation for details of -using the class. diff --git a/doc/source/opts.rst b/doc/source/opts.rst deleted file mode 100644 index 4e95f4d..0000000 --- a/doc/source/opts.rst +++ /dev/null @@ -1,9 +0,0 @@ -======================= - Configuration Options -======================= - -oslo.log uses oslo.config to define and manage configuration options -to allow the deployer to control how an application's logs are -handled. - -.. show-options:: oslo.log diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index a6ebf9a..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,167 +0,0 @@ -======= - Usage -======= - -.. _usage-app: - -In an Application -================= - -When using `Python's standard logging library`_ the following minimal setup -demostrates basic logging. - -.. _Python's standard logging library: https://docs.python.org/2/library/logging.html - -.. highlight:: python -.. literalinclude:: examples/python_logging.py - :linenos: - :lines: 17-26 - -Source: :ref:`examples/python_logging.py ` - -When using Oslo Logging the following setup demonstrates a comparative -syntax with Python standard logging. - - -.. literalinclude:: examples/oslo_logging.py - :linenos: - :lines: 17-30 - :emphasize-lines: 8,9 - -Source: :ref:`examples/oslo_logging.py ` - -Oslo Logging Setup Methods --------------------------- - -Applications need to use the oslo.log configuration functions to register -logging-related configuration options and configure the root and other -default loggers before using standard logging functions. - -Call :func:`~oslo_log.log.register_options` with an oslo.config CONF object -before parsing any application command line options. - -.. literalinclude:: examples/usage.py - :linenos: - :lines: 33,36-37,46-49 - :emphasize-lines: 7 - -Optionally call :func:`~oslo_log.log.set_defaults` before setup to -change default logging levels if necessary. - -.. literalinclude:: examples/usage.py - :linenos: - :lines: 51-53,61-69 - :emphasize-lines: 10 - -Call :func:`~oslo_log.log.setup` with the oslo.config CONF object used -when registering objects, along with the domain and optionally a version -to configure logging for the application. - -.. literalinclude:: examples/usage.py - :linenos: - :lines: 34,36-37,70-72 - :emphasize-lines: 6 - -Source: :ref:`examples/usage.py ` - -Oslo Logging Functions ----------------------- - -Use standard Python logging functions to produce log records at applicable -log levels. - -.. literalinclude:: examples/usage.py - :linenos: - :lines: 77-83 - -**Example Logging Output:** - -:: - - 2016-01-14 21:07:51.394 12945 INFO __main__ [-] Welcome to Oslo Logging - 2016-01-14 21:07:51.395 12945 WARNING __main__ [-] A warning occurred - 2016-01-14 21:07:51.395 12945 ERROR __main__ [-] An error occurred - 2016-01-14 21:07:51.396 12945 ERROR __main__ [-] An Exception occurred - 2016-01-14 21:07:51.396 12945 ERROR __main__ None - 2016-01-14 21:07:51.396 12945 ERROR __main__ - -Logging within an application should use `Oslo International Utilities (i18n)`_ marker -functions to provide language translation capabilities. - -.. _Oslo International Utilities (i18n): http://docs.openstack.org/developer/oslo.i18n/ - -.. literalinclude:: examples/usage_i18n.py - :linenos: - :lines: 31-32,76,79-85 - :emphasize-lines: 1 - -Source: :ref:`examples/usage_i18n.py ` - -With the use of `Oslo Context`_, log records can also contain -additional contextual information applicable for your application. - -.. _Oslo Context: http://docs.openstack.org/developer/oslo.context/ - -.. literalinclude:: examples/usage_context.py - :linenos: - :lines: 80-85 - :emphasize-lines: 3-5 - -**Example Logging Output:** - -:: - - 2016-01-14 20:04:34.562 11266 INFO __main__ [-] Welcome to Oslo Logging - 2016-01-14 20:04:34.563 11266 INFO __main__ [-] Without context - 2016-01-14 20:04:34.563 11266 INFO __main__ [req-bbc837a6-be80-4eb2-8ca3-53043a93b78d 6ce90b4d d6134462 a6b9360e - -] With context - -The log record output format without context is defined with -:oslo.config:option:`logging_default_format_string` configuration -variable. When specifying context the -:oslo.config:option:`logging_context_format_string` configuration -variable is used. - -The Oslo RequestContext object contains a number of attributes that can be -specified in :oslo.config:option:`logging_context_format_string`. An -application can extend this object to provide additional attributes that can -be specified in log records. - - - -Examples --------- - -:ref:`examples/usage.py ` provides a documented -example of Oslo Logging setup. - -:ref:`examples/usage_helper.py ` provides an -example showing debugging logging at each step details the configuration -and logging at each step of Oslo Logging setup. - -:ref:`examples/usage_i18n.py ` provides a -documented example of Oslo Logging with Oslo i18n supported messages. - -:ref:`examples/usage_context.py ` provides -a documented example of Oslo Logging with Oslo Context. - - -General Logging Guidelines -========================== - -The `OpenStack Logging Guidelines`_ in openstack-specs repository -explain how to use different logging levels, and the desired logging -patterns to be used in OpenStack applications. - -.. _OpenStack Logging Guidelines: http://specs.openstack.org/openstack/openstack-specs/specs/log-guidelines.html - -In a Library -============ - -oslo.log is primarily used for configuring logging in an application, -but it does include helpers that can be useful from libraries. - -:func:`~oslo_log.log.getLogger` wraps the function of the same name -from Python's standard library to add a -:class:`~oslo_log.log.KeywordArgumentAdapter`, making it easier to -pass data to the formatters provided by oslo.log and configured by an -application. diff --git a/oslo_log/__init__.py b/oslo_log/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_log/_i18n.py b/oslo_log/_i18n.py deleted file mode 100644 index 15c84e7..0000000 --- a/oslo_log/_i18n.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""oslo.i18n integration module. - -See http://docs.openstack.org/developer/oslo.i18n/usage.html . - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='oslo_log') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/oslo_log/_options.py b/oslo_log/_options.py deleted file mode 100644 index 3a2fb2f..0000000 --- a/oslo_log/_options.py +++ /dev/null @@ -1,171 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg - -from oslo_log import versionutils - -_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" - -DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN', - 'qpid=WARN', 'sqlalchemy=WARN', 'suds=INFO', - 'oslo.messaging=INFO', 'iso8601=WARN', - 'requests.packages.urllib3.connectionpool=WARN', - 'urllib3.connectionpool=WARN', 'websocket=WARN', - 'requests.packages.urllib3.util.retry=WARN', - 'urllib3.util.retry=WARN', - 'keystonemiddleware=WARN', 'routes.middleware=WARN', - 'stevedore=WARN', 'taskflow=WARN', - 'keystoneauth=WARN', 'oslo.cache=INFO', - 'dogpile.core.dogpile=INFO'] - -_IGNORE_MESSAGE = "This option is ignored if log_config_append is set." - -common_cli_opts = [ - cfg.BoolOpt('debug', - short='d', - default=False, - mutable=True, - help='If set to true, the logging level will be set to ' - 'DEBUG instead of the default INFO level.'), - cfg.BoolOpt('verbose', - short='v', - default=True, - help='If set to false, the logging level will be set to ' - 'WARNING instead of the default INFO level.', - deprecated_for_removal=True), -] - -logging_cli_opts = [ - cfg.StrOpt('log-config-append', - metavar='PATH', - deprecated_name='log-config', - mutable=True, - help='The name of a logging configuration file. This file ' - 'is appended to any existing logging configuration ' - 'files. For details about logging configuration files, ' - 'see the Python logging module documentation. Note that ' - 'when logging configuration files are used then all ' - 'logging configuration is set in the configuration file ' - 'and other logging configuration options are ignored ' - '(for example, logging_context_format_string).'), - cfg.StrOpt('log-date-format', - default=_DEFAULT_LOG_DATE_FORMAT, - metavar='DATE_FORMAT', - help='Defines the format string for %%(asctime)s in log ' - 'records. Default: %(default)s . ' - + _IGNORE_MESSAGE), - cfg.StrOpt('log-file', - metavar='PATH', - deprecated_name='logfile', - help='(Optional) Name of log file to send logging output to. ' - 'If no default is set, logging will go to stderr as ' - 'defined by use_stderr. ' - + _IGNORE_MESSAGE), - cfg.StrOpt('log-dir', - deprecated_name='logdir', - help='(Optional) The base directory used for relative log_file ' - ' paths. ' - + _IGNORE_MESSAGE), - cfg.BoolOpt('watch-log-file', - default=False, - help='Uses logging handler designed to watch file ' - 'system. When log file is moved or removed this handler ' - 'will open a new log file with specified path ' - 'instantaneously. It makes sense only if log_file option ' - 'is specified and Linux platform is used. ' - + _IGNORE_MESSAGE), - cfg.BoolOpt('use-syslog', - default=False, - help='Use syslog for logging. ' - 'Existing syslog format is DEPRECATED ' - 'and will be changed later to honor RFC5424. ' - + _IGNORE_MESSAGE), - cfg.StrOpt('syslog-log-facility', - default='LOG_USER', - help='Syslog facility to receive log lines. ' - + _IGNORE_MESSAGE), -] - -generic_log_opts = [ - cfg.BoolOpt('use_stderr', - default=True, - help='Log output to standard error. ' - + _IGNORE_MESSAGE), -] - -log_opts = [ - cfg.StrOpt('logging_context_format_string', - default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [%(request_id)s %(user_identity)s] ' - '%(instance)s%(message)s', - help='Format string to use for log messages with context.'), - cfg.StrOpt('logging_default_format_string', - default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s ' - '%(name)s [-] %(instance)s%(message)s', - help='Format string to use for log messages when context is ' - 'undefined.'), - cfg.StrOpt('logging_debug_format_suffix', - default='%(funcName)s %(pathname)s:%(lineno)d', - help='Additional data to append to log message when logging ' - 'level for the message is DEBUG.'), - cfg.StrOpt('logging_exception_prefix', - default='%(asctime)s.%(msecs)03d %(process)d ERROR %(name)s ' - '%(instance)s', - help='Prefix each line of exception output with this format.'), - cfg.StrOpt('logging_user_identity_format', - default='%(user)s %(tenant)s ' - '%(domain)s %(user_domain)s %(project_domain)s', - help='Defines the format string for %(user_identity)s that ' - 'is used in logging_context_format_string.'), - cfg.ListOpt('default_log_levels', - default=DEFAULT_LOG_LEVELS, - help='List of package logging levels in logger=LEVEL pairs. ' - + _IGNORE_MESSAGE), - cfg.BoolOpt('publish_errors', - default=False, - help='Enables or disables publication of error events.'), - - # NOTE(mikal): there are two options here because sometimes we are handed - # a full instance (and could include more information), and other times we - # are just handed a UUID for the instance. - cfg.StrOpt('instance_format', - default='[instance: %(uuid)s] ', - help='The format for an instance that is passed with the log ' - 'message.'), - cfg.StrOpt('instance_uuid_format', - default='[instance: %(uuid)s] ', - help='The format for an instance UUID that is passed with the ' - 'log message.'), -] - - -def list_opts(): - """Returns a list of oslo.config options available in the library. - - The returned list includes all oslo.config options which may be registered - at runtime by the library. - - Each element of the list is a tuple. The first element is the name of the - group under which the list of elements in the second element will be - registered. A group name of None corresponds to the [DEFAULT] group in - config files. - - The purpose of this is to allow tools like the Oslo sample config file - generator (oslo-config-generator) to discover the options exposed to users - by this library. - - :returns: a list of (group_name, opts) tuples - """ - return [(None, (common_cli_opts + logging_cli_opts + - generic_log_opts + log_opts + - versionutils.deprecated_opts))] diff --git a/oslo_log/fixture/__init__.py b/oslo_log/fixture/__init__.py deleted file mode 100644 index 577ac91..0000000 --- a/oslo_log/fixture/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from .logging_error import get_logging_handle_error_fixture -from .setlevel import SetLogLevel diff --git a/oslo_log/fixture/logging_error.py b/oslo_log/fixture/logging_error.py deleted file mode 100644 index 9a3140a..0000000 --- a/oslo_log/fixture/logging_error.py +++ /dev/null @@ -1,37 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - - -def get_logging_handle_error_fixture(): - """returns a fixture to make logging raise formatting exceptions. - - To use:: - - from oslo_log import fixture as log_fixture - - self.useFixture(log_fixture.get_logging_handle_error_fixture()) - """ - return fixtures.MonkeyPatch('logging.Handler.handleError', - _handleError) - - -def _handleError(self, record): - """Monkey patch for logging.Handler.handleError. - - The default handleError just logs the error to stderr but we want - the option of actually raising an exception. - """ - raise diff --git a/oslo_log/fixture/setlevel.py b/oslo_log/fixture/setlevel.py deleted file mode 100644 index d3e2e2c..0000000 --- a/oslo_log/fixture/setlevel.py +++ /dev/null @@ -1,49 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -import fixtures - - -class SetLogLevel(fixtures.Fixture): - """Override the log level for the named loggers, restoring their - previous value at the end of the test. - - To use:: - - from oslo_log import fixture as log_fixture - - self.useFixture(log_fixture.SetLogLevel(['myapp.foo'], logging.DEBUG)) - - :param logger_names: Sequence of logger names, as would be passed - to getLogger(). - :type logger_names: list(str) - :param level: Logging level, usually one of logging.DEBUG, - logging.INFO, etc. - :type level: int - """ - - def __init__(self, logger_names, level): - self.logger_names = logger_names - self.level = level - - def setUp(self): - super(SetLogLevel, self).setUp() - for name in self.logger_names: - # NOTE(dhellmann): Use the stdlib version of getLogger() - # so we get the logger and not any adaptor wrapping it. - logger = logging.getLogger(name) - self.addCleanup(logger.setLevel, logger.level) - logger.setLevel(self.level) diff --git a/oslo_log/formatters.py b/oslo_log/formatters.py deleted file mode 100644 index 0c38304..0000000 --- a/oslo_log/formatters.py +++ /dev/null @@ -1,335 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime -import debtcollector -import itertools -import logging -import logging.config -import logging.handlers -import socket -import sys -import traceback - -from dateutil import tz -import six -from six import moves - -from oslo_context import context as context_utils -from oslo_serialization import jsonutils -from oslo_utils import encodeutils - - -def _dictify_context(context): - if getattr(context, 'get_logging_values', None): - return context.get_logging_values() - elif getattr(context, 'to_dict', None): - debtcollector.deprecate( - 'The RequestContext.get_logging_values() ' - 'method should be defined for logging context specific ' - 'information. The to_dict() method is deprecated ' - 'for oslo.log use.', version='3.8.0', removal_version='5.0.0') - return context.to_dict() - # This dict only style logging format will become deprecated - # when projects using a dictionary object for context are updated - elif isinstance(context, dict): - return context - - return {} - - -# A configuration object is given to us when the application registers -# the logging options. -_CONF = None - - -def _store_global_conf(conf): - global _CONF - _CONF = conf - - -def _update_record_with_context(record): - """Given a log record, update it with context information. - - The request context, if there is one, will either be passed with the - incoming record or in the global thread-local store. - """ - context = record.__dict__.get( - 'context', - context_utils.get_current() - ) - if context: - d = _dictify_context(context) - # Copy the context values directly onto the record so they can be - # used by the formatting strings. - for k, v in d.items(): - setattr(record, k, v) - - return context - - -def _ensure_unicode(msg): - """Do our best to turn the input argument into a unicode object. - """ - if isinstance(msg, six.text_type): - return msg - if not isinstance(msg, six.binary_type): - return six.text_type(msg) - return encodeutils.safe_decode( - msg, - incoming='utf-8', - errors='xmlcharrefreplace') - - -class _ReplaceFalseValue(dict): - def __getitem__(self, key): - return dict.get(self, key, None) or '-' - - -class JSONFormatter(logging.Formatter): - def __init__(self, fmt=None, datefmt=None): - # NOTE(jkoelker) we ignore the fmt argument, but its still there - # since logging.config.fileConfig passes it. - self.datefmt = datefmt - try: - self.hostname = socket.gethostname() - except socket.error: - self.hostname = None - - def formatException(self, ei, strip_newlines=True): - lines = traceback.format_exception(*ei) - if strip_newlines: - lines = [moves.filter( - lambda x: x, - line.rstrip().splitlines()) for line in lines] - lines = list(itertools.chain(*lines)) - return lines - - def format(self, record): - message = {'message': record.getMessage(), - 'asctime': self.formatTime(record, self.datefmt), - 'name': record.name, - 'msg': record.msg, - 'args': record.args, - 'levelname': record.levelname, - 'levelno': record.levelno, - 'pathname': record.pathname, - 'filename': record.filename, - 'module': record.module, - 'lineno': record.lineno, - 'funcname': record.funcName, - 'created': record.created, - 'msecs': record.msecs, - 'relative_created': record.relativeCreated, - 'thread': record.thread, - 'thread_name': record.threadName, - 'process_name': record.processName, - 'process': record.process, - 'traceback': None, - 'hostname': self.hostname} - - # Build the extra values that were given to us, including - # the context. - context = _update_record_with_context(record) - if hasattr(record, 'extra'): - extra = record.extra.copy() - else: - extra = {} - for key in getattr(record, 'extra_keys', []): - if key not in extra: - extra[key] = getattr(record, key) - # If we saved a context object, explode it into the extra - # dictionary because the values are more useful than the - # object reference. - if 'context' in extra: - extra.update(_dictify_context(context)) - del extra['context'] - message['extra'] = extra - - if record.exc_info: - message['traceback'] = self.formatException(record.exc_info) - - return jsonutils.dumps(message) - - -class ContextFormatter(logging.Formatter): - """A context.RequestContext aware formatter configured through flags. - - The flags used to set format strings are: logging_context_format_string - and logging_default_format_string. You can also specify - logging_debug_format_suffix to append extra formatting if the log level is - debug. - - The standard variables available to the formatter are listed at: - http://docs.python.org/library/logging.html#formatter - - In addition to the standard variables, one custom variable is - available to both formatting string: `isotime` produces a - timestamp in ISO8601 format, suitable for producing - RFC5424-compliant log messages. - - Furthermore, logging_context_format_string has access to all of - the data in a dict representation of the context. - """ - - def __init__(self, *args, **kwargs): - """Initialize ContextFormatter instance - - Takes additional keyword arguments which can be used in the message - format string. - - :keyword project: project name - :type project: string - :keyword version: project version - :type version: string - - """ - - self.project = kwargs.pop('project', 'unknown') - self.version = kwargs.pop('version', 'unknown') - self.conf = kwargs.pop('config', _CONF) - - logging.Formatter.__init__(self, *args, **kwargs) - - def format(self, record): - """Uses contextstring if request_id is set, otherwise default.""" - - if six.PY2: - should_use_unicode = True - for arg in record.args: - try: - six.text_type(arg) - except UnicodeDecodeError: - should_use_unicode = False - break - if (not isinstance(record.msg, six.text_type) - and should_use_unicode): - record.msg = _ensure_unicode(record.msg) - - # store project info - record.project = self.project - record.version = self.version - - # FIXME(dims): We need a better way to pick up the instance - # or instance_uuid parameters from the kwargs from say - # LOG.info or LOG.warn - instance_extra = '' - instance = getattr(record, 'instance', None) - instance_uuid = getattr(record, 'instance_uuid', None) - context = _update_record_with_context(record) - if instance: - try: - instance_extra = (self.conf.instance_format - % instance) - except TypeError: - instance_extra = instance - elif instance_uuid: - instance_extra = (self.conf.instance_uuid_format - % {'uuid': instance_uuid}) - elif context: - # FIXME(dhellmann): We should replace these nova-isms with - # more generic handling in the Context class. See the - # app-agnostic-logging-parameters blueprint. - instance = getattr(context, 'instance', None) - instance_uuid = getattr(context, 'instance_uuid', None) - - # resource_uuid was introduced in oslo_context's - # RequestContext - resource_uuid = getattr(context, 'resource_uuid', None) - - if instance: - instance_extra = (self.conf.instance_format - % {'uuid': instance}) - elif instance_uuid: - instance_extra = (self.conf.instance_uuid_format - % {'uuid': instance_uuid}) - elif resource_uuid: - instance_extra = (self.conf.instance_uuid_format - % {'uuid': resource_uuid}) - - record.instance = instance_extra - - # NOTE(sdague): default the fancier formatting params - # to an empty string so we don't throw an exception if - # they get used - for key in ('instance', 'color', 'user_identity', 'resource', - 'user_name', 'project_name'): - if key not in record.__dict__: - record.__dict__[key] = '' - - # Set the "user_identity" value of "logging_context_format_string" - # by using "logging_user_identity_format" and - # get_logging_values of oslo.context. - if context: - record.user_identity = ( - self.conf.logging_user_identity_format % - _ReplaceFalseValue(context.__dict__) - ) - - if record.__dict__.get('request_id'): - fmt = self.conf.logging_context_format_string - else: - fmt = self.conf.logging_default_format_string - - if (record.levelno == logging.DEBUG and - self.conf.logging_debug_format_suffix): - fmt += " " + self.conf.logging_debug_format_suffix - - self._compute_iso_time(record) - - if sys.version_info < (3, 2): - self._fmt = fmt - else: - self._style = logging.PercentStyle(fmt) - self._fmt = self._style._fmt - # Cache this on the record, Logger will respect our formatted copy - if record.exc_info: - record.exc_text = self.formatException(record.exc_info, record) - return logging.Formatter.format(self, record) - - def formatException(self, exc_info, record=None): - """Format exception output with CONF.logging_exception_prefix.""" - if not record: - return logging.Formatter.formatException(self, exc_info) - - stringbuffer = moves.StringIO() - traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], - None, stringbuffer) - lines = stringbuffer.getvalue().split('\n') - stringbuffer.close() - - if self.conf.logging_exception_prefix.find('%(asctime)') != -1: - record.asctime = self.formatTime(record, self.datefmt) - - self._compute_iso_time(record) - - formatted_lines = [] - for line in lines: - pl = self.conf.logging_exception_prefix % record.__dict__ - fl = '%s%s' % (pl, line) - formatted_lines.append(fl) - return '\n'.join(formatted_lines) - - def _compute_iso_time(self, record): - # set iso8601 timestamp - localtz = tz.tzlocal() - record.isotime = datetime.datetime.fromtimestamp( - record.created).replace(tzinfo=localtz).isoformat() - if record.created == int(record.created): - # NOTE(stpierre): when the timestamp includes no - # microseconds -- e.g., 1450274066.000000 -- then the - # microseconds aren't included in the isoformat() time. As - # a result, in literally one in a million cases - # isoformat() looks different. This adds microseconds when - # that happens. - record.isotime = "%s.000000%s" % (record.isotime[:-6], - record.isotime[-6:]) diff --git a/oslo_log/handlers.py b/oslo_log/handlers.py deleted file mode 100644 index 347384f..0000000 --- a/oslo_log/handlers.py +++ /dev/null @@ -1,76 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import inspect -import logging -import logging.config -import logging.handlers -import os -try: - import syslog -except ImportError: - syslog = None -from oslo_utils import encodeutils - - -NullHandler = logging.NullHandler - - -def _get_binary_name(): - return os.path.basename(inspect.stack()[-1][1]) - - -_AUDIT = logging.INFO + 1 -_TRACE = 5 - - -if syslog is not None: - class OSSysLogHandler(logging.Handler): - """Syslog based handler. Only available on UNIX-like platforms.""" - severity_map = { - "CRITICAL": syslog.LOG_CRIT, - "DEBUG": syslog.LOG_DEBUG, - "ERROR": syslog.LOG_ERR, - "INFO": syslog.LOG_INFO, - "WARNING": syslog.LOG_WARNING, - "WARN": syslog.LOG_WARNING, - } - - def __init__(self, facility=syslog.LOG_USER): - # Do not use super() unless type(logging.Handler) is 'type' - # (i.e. >= Python 2.7). - logging.Handler.__init__(self) - binary_name = _get_binary_name() - syslog.openlog(binary_name, 0, facility) - - def emit(self, record): - priority = self.severity_map.get(record.levelname, - syslog.LOG_DEBUG) - message = encodeutils.safe_encode(self.format(record)) - - syslog.syslog(priority, message) - - -class ColorHandler(logging.StreamHandler): - LEVEL_COLORS = { - _TRACE: '\033[00;35m', # MAGENTA - logging.DEBUG: '\033[00;32m', # GREEN - logging.INFO: '\033[00;36m', # CYAN - _AUDIT: '\033[01;36m', # BOLD CYAN - logging.WARN: '\033[01;33m', # BOLD YELLOW - logging.ERROR: '\033[01;31m', # BOLD RED - logging.CRITICAL: '\033[01;31m', # BOLD RED - } - - def format(self, record): - record.color = self.LEVEL_COLORS[record.levelno] - return logging.StreamHandler.format(self, record) diff --git a/oslo_log/helpers.py b/oslo_log/helpers.py deleted file mode 100644 index 30b697f..0000000 --- a/oslo_log/helpers.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Log helper functions.""" - -import functools -import logging - - -def _get_full_class_name(cls): - return '%s.%s' % (cls.__module__, - getattr(cls, '__qualname__', cls.__name__)) - - -def log_method_call(method): - """Decorator helping to log method calls. - - :param method: Method to decorate to be logged. - :type method: method definition - """ - log = logging.getLogger(method.__module__) - - @functools.wraps(method) - def wrapper(*args, **kwargs): - if args: - first_arg = args[0] - cls = (first_arg if isinstance(first_arg, type) - else first_arg.__class__) - caller = _get_full_class_name(cls) - else: - caller = 'static' - data = {'caller': caller, - 'method_name': method.__name__, - 'args': args[1:], 'kwargs': kwargs} - log.debug('%(caller)s method %(method_name)s ' - 'called with arguments %(args)s %(kwargs)s', data) - return method(*args, **kwargs) - return wrapper diff --git a/oslo_log/locale/de/LC_MESSAGES/oslo_log.po b/oslo_log/locale/de/LC_MESSAGES/oslo_log.po deleted file mode 100644 index f18bbdd..0000000 --- a/oslo_log/locale/de/LC_MESSAGES/oslo_log.po +++ /dev/null @@ -1,60 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.log 3.10.1.dev3\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-24 09:24+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-20 06:43+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language-Team: German\n" -"Language: de\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s and may be removed in %(remove_in)s. " -"It will not be superseded." -msgstr "" -"Seit %(as_of)s wird %(what)s nicht mehr unterstützt und voraussichtlich in " -"%(remove_in)s entfernt. Es gibt keine Alternative." - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s and may " -"be removed in %(remove_in)s." -msgstr "" -"Seit %(as_of)s wird %(what)s nicht mehr unterstützt und voraussichtlich in " -"%(remove_in)s entfernt. Benutzen Sie %(in_favor_of)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s." -msgstr "" -"Seit %(as_of)s wird %(what)s nicht mehr unterstützt. Benutzen Sie " -"%(in_favor_of)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s. It will not be superseded." -msgstr "" -"Seit %(as_of)s wird %(what)s nicht mehr unterstützt. Es gibt keine " -"Alternative." - -#, python-format -msgid "Deprecated: %s" -msgstr "Nicht weiter unterstützt: %s" - -#, python-format -msgid "Error loading logging config %(log_config)s: %(err_msg)s" -msgstr "" -"Fehler beim Laden der Logging Konfiguration %(log_config)s: %(err_msg)s" - -#, python-format -msgid "Fatal call to deprecated config: %(msg)s" -msgstr "Aufruf zu nicht weiter unterstützter Konfiguration: %(msg)s" - -#, python-format -msgid "syslog facility must be one of: %s" -msgstr "Sylog Facility muß einer von %s sein." diff --git a/oslo_log/locale/en_GB/LC_MESSAGES/oslo_log.po b/oslo_log/locale/en_GB/LC_MESSAGES/oslo_log.po deleted file mode 100644 index 0eb0b7f..0000000 --- a/oslo_log/locale/en_GB/LC_MESSAGES/oslo_log.po +++ /dev/null @@ -1,55 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.log 3.11.1.dev4\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-07-01 03:32+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-28 05:56+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s and may be removed in %(remove_in)s. " -"It will not be superseded." -msgstr "" -"%(what)s is deprecated as of %(as_of)s and may be removed in %(remove_in)s. " -"It will not be superseded." - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s and may " -"be removed in %(remove_in)s." -msgstr "" -"%(what)s is deprecated as of %(as_of)s in favour of %(in_favor_of)s and may " -"be removed in %(remove_in)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s." -msgstr "%(what)s is deprecated as of %(as_of)s in favour of %(in_favor_of)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s. It will not be superseded." -msgstr "%(what)s is deprecated as of %(as_of)s. It will not be superseded." - -#, python-format -msgid "Deprecated: %s" -msgstr "Deprecated: %s" - -#, python-format -msgid "Error loading logging config %(log_config)s: %(err_msg)s" -msgstr "Error loading logging config %(log_config)s: %(err_msg)s" - -#, python-format -msgid "Fatal call to deprecated config: %(msg)s" -msgstr "Fatal call to deprecated config: %(msg)s" - -#, python-format -msgid "syslog facility must be one of: %s" -msgstr "syslog facility must be one of: %s" diff --git a/oslo_log/locale/es/LC_MESSAGES/oslo_log.po b/oslo_log/locale/es/LC_MESSAGES/oslo_log.po deleted file mode 100644 index cfa4732..0000000 --- a/oslo_log/locale/es/LC_MESSAGES/oslo_log.po +++ /dev/null @@ -1,64 +0,0 @@ -# Translations template for oslo.log. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.log project. -# -# Translators: -# Adriana Chisco Landazábal , 2015 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.log 3.4.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 12:12+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2015-06-22 08:59+0000\n" -"Last-Translator: Adriana Chisco Landazábal \n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Spanish\n" - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s and may be removed in %(remove_in)s. " -"It will not be superseded." -msgstr "" -"%(what)s está en desuso así como %(as_of)s y puede ser removido en " -"%(remove_in)s. No se sustituirá." - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s and may " -"be removed in %(remove_in)s." -msgstr "" -"%(what)s esté en desuso así como %(as_of)s en beneficio de %(in_favor_of)s y " -"puede ser removido en %(remove_in)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s." -msgstr "" -"%(what)s está en desuso así como %(as_of)s en beneficio de %(in_favor_of)s." - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s. It will not be superseded." -msgstr "%(what)s está en desuso así como %(as_of)s. No se sustituirá." - -#, python-format -msgid "Deprecated: %s" -msgstr "En desuso: %s" - -#, python-format -msgid "Error loading logging config %(log_config)s: %(err_msg)s" -msgstr "" -"Error al cargar la configuración de registro %(log_config)s: %(err_msg)s" - -#, python-format -msgid "Fatal call to deprecated config: %(msg)s" -msgstr "Aviso urgente de configuración en desuso: %(msg)s" - -#, python-format -msgid "syslog facility must be one of: %s" -msgstr "El recurso syslog debe ser uno de: %s" diff --git a/oslo_log/locale/ja/LC_MESSAGES/oslo_log.po b/oslo_log/locale/ja/LC_MESSAGES/oslo_log.po deleted file mode 100644 index d82325d..0000000 --- a/oslo_log/locale/ja/LC_MESSAGES/oslo_log.po +++ /dev/null @@ -1,57 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.log 3.4.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 12:12+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-02-20 06:53+0000\n" -"Last-Translator: KATO Tomoyuki \n" -"Language-Team: Japanese\n" -"Language: ja\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s and may be removed in %(remove_in)s. " -"It will not be superseded." -msgstr "" -"%(what)s は %(as_of)s において非推奨になります。%(remove_in)s において削除さ" -"れる可能性があります。後継はありません。" - -#, python-format -msgid "" -"%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s and may " -"be removed in %(remove_in)s." -msgstr "" -"%(what)s は、%(in_favor_of)s に移行するために %(as_of)s において非推奨になり" -"ます。 %(remove_in)s において削除される可能性があります。" - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s." -msgstr "" -"%(what)s は、%(in_favor_of)s に移行するために %(as_of)s において非推奨になり" -"ます。" - -#, python-format -msgid "%(what)s is deprecated as of %(as_of)s. It will not be superseded." -msgstr "%(what)s は %(as_of)s において非推奨になります。後継はありません。" - -#, python-format -msgid "Deprecated: %s" -msgstr "非推奨: %s" - -#, python-format -msgid "Error loading logging config %(log_config)s: %(err_msg)s" -msgstr "ロギング設定 %(log_config)s の読み込み中にエラー発生: %(err_msg)s" - -#, python-format -msgid "Fatal call to deprecated config: %(msg)s" -msgstr "非推奨設定の致命的な呼び出し: %(msg)s" - -#, python-format -msgid "syslog facility must be one of: %s" -msgstr "syslog ファシリティーは次のどれかである必要があります: %s" diff --git a/oslo_log/log.py b/oslo_log/log.py deleted file mode 100644 index 1d7f3e2..0000000 --- a/oslo_log/log.py +++ /dev/null @@ -1,455 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""OpenStack logging handler. - -This module adds to logging functionality by adding the option to specify -a context object when calling the various log methods. If the context object -is not specified, default formatting is used. Additionally, an instance uuid -may be passed as part of the log message, which is intended to make it easier -for admins to find messages related to a specific instance. - -It also allows setting of formatting information through conf. - -""" - -import logging -import logging.config -import logging.handlers -import os -import platform -import sys -try: - import syslog -except ImportError: - syslog = None -import traceback - -from oslo_config import cfg -from oslo_utils import importutils -import six -from six import moves - -from oslo_log._i18n import _ -from oslo_log import _options -from oslo_log import formatters -from oslo_log import handlers - -CRITICAL = logging.CRITICAL -FATAL = logging.FATAL -ERROR = logging.ERROR -WARNING = logging.WARNING -WARN = logging.WARNING -INFO = logging.INFO -DEBUG = logging.DEBUG -NOTSET = logging.NOTSET -TRACE = handlers._TRACE - -logging.addLevelName(TRACE, 'TRACE') - - -def _get_log_file_path(conf, binary=None): - logfile = conf.log_file - logdir = conf.log_dir - - if logfile and not logdir: - return logfile - - if logfile and logdir: - return os.path.join(logdir, logfile) - - if logdir: - binary = binary or handlers._get_binary_name() - return '%s.log' % (os.path.join(logdir, binary),) - - return None - - -def _iter_loggers(): - """Iterate on existing loggers.""" - - # Sadly, Logger.manager and Manager.loggerDict are not documented, - # but there is no logging public function to iterate on all loggers. - - # The root logger is not part of loggerDict. - yield logging.getLogger() - - manager = logging.Logger.manager - for logger in manager.loggerDict.values(): - if isinstance(logger, logging.PlaceHolder): - continue - yield logger - - -class BaseLoggerAdapter(logging.LoggerAdapter): - - warn = logging.LoggerAdapter.warning - - @property - def handlers(self): - return self.logger.handlers - - def trace(self, msg, *args, **kwargs): - self.log(TRACE, msg, *args, **kwargs) - - -class KeywordArgumentAdapter(BaseLoggerAdapter): - """Logger adapter to add keyword arguments to log record's extra data - - Keywords passed to the log call are added to the "extra" - dictionary passed to the underlying logger so they are emitted - with the log message and available to the format string. - - Special keywords: - - extra - An existing dictionary of extra values to be passed to the - logger. If present, the dictionary is copied and extended. - resource - A dictionary-like object containing a ``name`` key or ``type`` - and ``id`` keys. - - """ - - def process(self, msg, kwargs): - # Make a new extra dictionary combining the values we were - # given when we were constructed and anything from kwargs. - extra = {} - extra.update(self.extra) - if 'extra' in kwargs: - extra.update(kwargs.pop('extra')) - # Move any unknown keyword arguments into the extra - # dictionary. - for name in list(kwargs.keys()): - if name == 'exc_info': - continue - extra[name] = kwargs.pop(name) - # NOTE(dhellmann): The gap between when the adapter is called - # and when the formatter needs to know what the extra values - # are is large enough that we can't get back to the original - # extra dictionary easily. We leave a hint to ourselves here - # in the form of a list of keys, which will eventually be - # attributes of the LogRecord processed by the formatter. That - # allows the formatter to know which values were original and - # which were extra, so it can treat them differently (see - # JSONFormatter for an example of this). We sort the keys so - # it is possible to write sane unit tests. - extra['extra_keys'] = list(sorted(extra.keys())) - # Place the updated extra values back into the keyword - # arguments. - kwargs['extra'] = extra - - # NOTE(jdg): We would like an easy way to add resource info - # to logging, for example a header like 'volume-' - # Turns out Nova implemented this but it's Nova specific with - # instance. Also there's resource_uuid that's been added to - # context, but again that only works for Instances, and it - # only works for contexts that have the resource id set. - resource = kwargs['extra'].get('resource', None) - if resource: - - # Many OpenStack resources have a name entry in their db ref - # of the form -, let's just use that if - # it's passed in - if not resource.get('name', None): - - # For resources that don't have the name of the format we wish - # to use (or places where the LOG call may not have the full - # object ref, allow them to pass in a dict: - # resource={'type': volume, 'id': uuid} - - resource_type = resource.get('type', None) - resource_id = resource.get('id', None) - - if resource_type and resource_id: - kwargs['extra']['resource'] = ('[' + resource_type + - '-' + resource_id + '] ') - else: - # FIXME(jdg): Since the name format can be specified via conf - # entry, we may want to consider allowing this to be configured - # here as well - kwargs['extra']['resource'] = ('[' + resource.get('name', '') - + '] ') - - return msg, kwargs - - -def _create_logging_excepthook(product_name): - def logging_excepthook(exc_type, value, tb): - extra = {'exc_info': (exc_type, value, tb)} - getLogger(product_name).critical( - "".join(traceback.format_exception_only(exc_type, value)), - **extra) - return logging_excepthook - - -class LogConfigError(Exception): - - message = _('Error loading logging config %(log_config)s: %(err_msg)s') - - def __init__(self, log_config, err_msg): - self.log_config = log_config - self.err_msg = err_msg - - def __str__(self): - return self.message % dict(log_config=self.log_config, - err_msg=self.err_msg) - - -def _load_log_config(log_config_append): - try: - if not hasattr(_load_log_config, "old_time"): - _load_log_config.old_time = 0 - new_time = os.path.getmtime(log_config_append) - if _load_log_config.old_time != new_time: - # Reset all existing loggers before reloading config as fileConfig - # does not reset non-child loggers. - for logger in _iter_loggers(): - logger.level = logging.NOTSET - logger.handlers = [] - logger.propagate = 1 - logging.config.fileConfig(log_config_append, - disable_existing_loggers=False) - _load_log_config.old_time = new_time - except (moves.configparser.Error, KeyError, os.error) as exc: - raise LogConfigError(log_config_append, six.text_type(exc)) - - -def _mutate_hook(conf, fresh): - """Reconfigures oslo.log according to the mutated options.""" - - # verbose is deprecated, so I didn't make it mutable, so there's no need to - # test for it here. - if (None, 'debug') in fresh: - _refresh_root_level(conf.debug, conf.verbose) - - if (None, 'log-config-append') in fresh: - _load_log_config.old_time = 0 - if conf.log_config_append: - _load_log_config(conf.log_config_append) - - -def register_options(conf): - """Register the command line and configuration options used by oslo.log.""" - - # Sometimes logging occurs before logging is ready (e.g., oslo_config). - # To avoid "No handlers could be found," temporarily log to sys.stderr. - root_logger = logging.getLogger(None) - if not root_logger.handlers: - root_logger.addHandler(logging.StreamHandler()) - - conf.register_cli_opts(_options.common_cli_opts) - conf.register_cli_opts(_options.logging_cli_opts) - conf.register_opts(_options.generic_log_opts) - conf.register_opts(_options.log_opts) - formatters._store_global_conf(conf) - - conf.register_mutate_hook(_mutate_hook) - - -def setup(conf, product_name, version='unknown'): - """Setup logging for the current application.""" - if conf.log_config_append: - _load_log_config(conf.log_config_append) - else: - _setup_logging_from_conf(conf, product_name, version) - sys.excepthook = _create_logging_excepthook(product_name) - - -def set_defaults(logging_context_format_string=None, - default_log_levels=None): - """Set default values for the configuration options used by oslo.log.""" - # Just in case the caller is not setting the - # default_log_level. This is insurance because - # we introduced the default_log_level parameter - # later in a backwards in-compatible change - if default_log_levels is not None: - cfg.set_defaults( - _options.log_opts, - default_log_levels=default_log_levels) - if logging_context_format_string is not None: - cfg.set_defaults( - _options.log_opts, - logging_context_format_string=logging_context_format_string) - - -def tempest_set_log_file(filename): - """Provide an API for tempest to set the logging filename. - - .. warning:: Only Tempest should use this function. - - We don't want applications to set a default log file, so we don't - want this in set_defaults(). Because tempest doesn't use a - configuration file we don't have another convenient way to safely - set the log file default. - - """ - cfg.set_defaults(_options.logging_cli_opts, log_file=filename) - - -def _find_facility(facility): - # NOTE(jd): Check the validity of facilities at run time as they differ - # depending on the OS and Python version being used. - valid_facilities = [f for f in - ["LOG_KERN", "LOG_USER", "LOG_MAIL", - "LOG_DAEMON", "LOG_AUTH", "LOG_SYSLOG", - "LOG_LPR", "LOG_NEWS", "LOG_UUCP", - "LOG_CRON", "LOG_AUTHPRIV", "LOG_FTP", - "LOG_LOCAL0", "LOG_LOCAL1", "LOG_LOCAL2", - "LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5", - "LOG_LOCAL6", "LOG_LOCAL7"] - if getattr(syslog, f, None)] - - facility = facility.upper() - - if not facility.startswith("LOG_"): - facility = "LOG_" + facility - - if facility not in valid_facilities: - raise TypeError(_('syslog facility must be one of: %s') % - ', '.join("'%s'" % fac - for fac in valid_facilities)) - - return getattr(syslog, facility) - - -def _refresh_root_level(debug, verbose): - """Set the level of the root logger. - - If 'debug' is True, the level will be DEBUG. Otherwise we look at 'verbose' - - if that is True, the level will be INFO. If neither are set, the level - will be WARNING. - - Note the 'verbose' option is deprecated. - - :param debug - :param verbose - """ - log_root = getLogger(None).logger - if debug: - log_root.setLevel(logging.DEBUG) - elif verbose: - log_root.setLevel(logging.INFO) - else: - log_root.setLevel(logging.WARNING) - - -def _setup_logging_from_conf(conf, project, version): - log_root = getLogger(None).logger - - # Remove all handlers - for handler in list(log_root.handlers): - log_root.removeHandler(handler) - - logpath = _get_log_file_path(conf) - if logpath: - if conf.watch_log_file and platform.system() == 'Linux': - from oslo_log import watchers - file_handler = watchers.FastWatchedFileHandler - else: - file_handler = logging.handlers.WatchedFileHandler - - filelog = file_handler(logpath) - log_root.addHandler(filelog) - - if conf.use_stderr: - streamlog = handlers.ColorHandler() - log_root.addHandler(streamlog) - - elif not logpath: - # pass sys.stdout as a positional argument - # python2.6 calls the argument strm, in 2.7 it's stream - streamlog = logging.StreamHandler(sys.stdout) - log_root.addHandler(streamlog) - - if conf.publish_errors: - handler = importutils.import_object( - "oslo_messaging.notify.log_handler.PublishErrorsHandler", - logging.ERROR) - log_root.addHandler(handler) - - if conf.use_syslog: - global syslog - if syslog is None: - raise RuntimeError("syslog is not available on this platform") - facility = _find_facility(conf.syslog_log_facility) - syslog_handler = handlers.OSSysLogHandler(facility=facility) - log_root.addHandler(syslog_handler) - - datefmt = conf.log_date_format - for handler in log_root.handlers: - handler.setFormatter(formatters.ContextFormatter(project=project, - version=version, - datefmt=datefmt, - config=conf)) - _refresh_root_level(conf.debug, conf.verbose) - - for pair in conf.default_log_levels: - mod, _sep, level_name = pair.partition('=') - logger = logging.getLogger(mod) - numeric_level = None - try: - # NOTE(harlowja): integer's are valid level names, and for some - # libraries they have a lower level than DEBUG that is typically - # defined at level 5, so to make that accessible, try to convert - # this to a integer, and if not keep the original... - numeric_level = int(level_name) - except ValueError: # nosec - pass - if numeric_level is not None: - logger.setLevel(numeric_level) - else: - logger.setLevel(level_name) - -_loggers = {} - - -def getLogger(name=None, project='unknown', version='unknown'): - """Build a logger with the given name. - - :param name: The name for the logger. This is usually the module - name, ``__name__``. - :type name: string - :param project: The name of the project, to be injected into log - messages. For example, ``'nova'``. - :type project: string - :param version: The version of the project, to be injected into log - messages. For example, ``'2014.2'``. - :type version: string - """ - # NOTE(dhellmann): To maintain backwards compatibility with the - # old oslo namespace package logger configurations, and to make it - # possible to control all oslo logging with one logger node, we - # replace "oslo_" with "oslo." so that modules under the new - # non-namespaced packages get loggers as though they are. - if name and name.startswith('oslo_'): - name = 'oslo.' + name[5:] - if name not in _loggers: - _loggers[name] = KeywordArgumentAdapter(logging.getLogger(name), - {'project': project, - 'version': version}) - return _loggers[name] - - -def get_default_log_levels(): - """Return the Oslo Logging default log levels. - - Returns a copy of the list so an application can change the value - and not affect the default value used in the log_opts configuration - setup. - """ - return list(_options.DEFAULT_LOG_LEVELS) diff --git a/oslo_log/loggers.py b/oslo_log/loggers.py deleted file mode 100644 index 9a779c8..0000000 --- a/oslo_log/loggers.py +++ /dev/null @@ -1,29 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from oslo_log import versionutils - - -@versionutils.deprecated( - versionutils.deprecated.LIBERTY, - remove_in=+1) -class WritableLogger(object): - """A thin wrapper that responds to `write` and logs.""" - - def __init__(self, logger, level=logging.INFO): - self.logger = logger - self.level = level - - def write(self, msg): - self.logger.log(self.level, msg.rstrip()) diff --git a/oslo_log/tests/__init__.py b/oslo_log/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_log/tests/unit/__init__.py b/oslo_log/tests/unit/__init__.py deleted file mode 100644 index 19f5e72..0000000 --- a/oslo_log/tests/unit/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. diff --git a/oslo_log/tests/unit/fixture/__init__.py b/oslo_log/tests/unit/fixture/__init__.py deleted file mode 100644 index 19f5e72..0000000 --- a/oslo_log/tests/unit/fixture/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. diff --git a/oslo_log/tests/unit/fixture/test_logging_error.py b/oslo_log/tests/unit/fixture/test_logging_error.py deleted file mode 100644 index abf9c41..0000000 --- a/oslo_log/tests/unit/fixture/test_logging_error.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from oslo_log import fixture -from oslo_log import log as logging -from oslotest import base as test_base - - -class TestLoggingFixture(test_base.BaseTestCase): - - def setUp(self): - super(TestLoggingFixture, self).setUp() - self.log = logging.getLogger(__name__) - - def test_logging_handle_error(self): - self.log.error('pid of first child is %(foo)s', 1) - self.useFixture(fixture.get_logging_handle_error_fixture()) - self.assertRaises(TypeError, - self.log.error, - 'pid of first child is %(foo)s', - 1) diff --git a/oslo_log/tests/unit/fixture/test_setlevel.py b/oslo_log/tests/unit/fixture/test_setlevel.py deleted file mode 100644 index eaaa7e4..0000000 --- a/oslo_log/tests/unit/fixture/test_setlevel.py +++ /dev/null @@ -1,36 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -from oslo_log import fixture -from oslotest import base as test_base - - -class TestSetLevelFixture(test_base.BaseTestCase): - - def test_unset_before(self): - logger = logging.getLogger('no-such-logger-unset') - self.assertEqual(logging.NOTSET, logger.level) - fix = fixture.SetLogLevel(['no-such-logger-unset'], logging.DEBUG) - with fix: - self.assertEqual(logging.DEBUG, logger.level) - self.assertEqual(logging.NOTSET, logger.level) - - def test_set_before(self): - logger = logging.getLogger('no-such-logger-set') - logger.setLevel(logging.ERROR) - self.assertEqual(logging.ERROR, logger.level) - fix = fixture.SetLogLevel(['no-such-logger-set'], logging.DEBUG) - with fix: - self.assertEqual(logging.DEBUG, logger.level) - self.assertEqual(logging.ERROR, logger.level) diff --git a/oslo_log/tests/unit/test_formatters.py b/oslo_log/tests/unit/test_formatters.py deleted file mode 100644 index 3bb2cd4..0000000 --- a/oslo_log/tests/unit/test_formatters.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Unit Tests for oslo.log formatter""" - -import mock - -from oslo_context import context -from oslo_log import formatters -from oslotest import base as test_base - - -def _fake_context(): - ctxt = context.RequestContext(user="user", - tenant="tenant", - project_domain="pdomain", - user_domain="udomain", - overwrite=True) - - return ctxt - - -class AlternativeRequestContext(object): - - def __init__(self, user=None, tenant=None): - self.user = user - self.tenant = tenant - - def to_dict(self): - return {'user': self.user, - 'tenant': self.tenant} - - -class FormatterTest(test_base.BaseTestCase): - - def setUp(self): - super(FormatterTest, self).setUp() - - def test_replace_false_value_exists(self): - d = {"user": "user1"} - s = "%(user)s" % formatters._ReplaceFalseValue(d) - self.assertEqual(d['user'], s) - - def test_replace_false_value_not_exists(self): - d = {"user": "user1"} - s = "%(project)s" % formatters._ReplaceFalseValue(d) - self.assertEqual("-", s) - - def test_dictify_context_empty(self): - self.assertEqual({}, formatters._dictify_context(None)) - - @mock.patch("debtcollector.deprecate") - def test_dictify_context_with_dict(self, mock_deprecate): - d = {"user": "user"} - self.assertEqual(d, formatters._dictify_context(d)) - mock_deprecate.assert_not_called() - - @mock.patch("debtcollector.deprecate") - def test_dictify_context_with_context(self, mock_deprecate): - ctxt = _fake_context() - self.assertEqual(ctxt.get_logging_values(), - formatters._dictify_context(ctxt)) - mock_deprecate.assert_not_called() - - @mock.patch("debtcollector.deprecate") - def test_dictify_context_without_get_logging_values(self, mock_deprecate): - ctxt = AlternativeRequestContext(user="user", tenant="tenant") - d = {"user": "user", "tenant": "tenant"} - self.assertEqual(d, formatters._dictify_context(ctxt)) - mock_deprecate.assert_called_with( - 'The RequestContext.get_logging_values() ' - 'method should be defined for logging context specific ' - 'information. The to_dict() method is deprecated ' - 'for oslo.log use.', removal_version='5.0.0', version='3.8.0') diff --git a/oslo_log/tests/unit/test_helpers.py b/oslo_log/tests/unit/test_helpers.py deleted file mode 100644 index 8e0f1ae..0000000 --- a/oslo_log/tests/unit/test_helpers.py +++ /dev/null @@ -1,62 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslo_log import helpers -from oslotest import base as test_base - - -@helpers.log_method_call -def _static_method(): - pass - - -class LogHelpersTestCase(test_base.BaseTestCase): - - def test_log_decorator(self): - '''Test that LOG.debug is called with proper arguments.''' - - class test_class(object): - @helpers.log_method_call - def test_method(self, arg1, arg2, arg3, *args, **kwargs): - pass - - @classmethod - @helpers.log_method_call - def test_classmethod(cls, arg1, arg2, arg3, *args, **kwargs): - pass - - args = tuple(range(6)) - kwargs = {'kwarg1': 6, 'kwarg2': 7} - - obj = test_class() - for method_name in ('test_method', 'test_classmethod'): - data = {'caller': helpers._get_full_class_name(test_class), - 'method_name': method_name, - 'args': args, - 'kwargs': kwargs} - - method = getattr(obj, method_name) - with mock.patch('logging.Logger.debug') as debug: - method(*args, **kwargs) - debug.assert_called_with(mock.ANY, data) - - def test_log_decorator_for_static(self): - '''Test that LOG.debug is called with proper arguments.''' - - data = {'caller': 'static', - 'method_name': '_static_method', - 'args': (), - 'kwargs': {}} - with mock.patch('logging.Logger.debug') as debug: - _static_method() - debug.assert_called_with(mock.ANY, data) diff --git a/oslo_log/tests/unit/test_log.py b/oslo_log/tests/unit/test_log.py deleted file mode 100644 index f656d3e..0000000 --- a/oslo_log/tests/unit/test_log.py +++ /dev/null @@ -1,1519 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2011 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from contextlib import contextmanager -import copy -import datetime -import logging -import os -import platform -import shutil -import sys -try: - import syslog -except ImportError: - syslog = None -import tempfile -import time - -from dateutil import tz -import mock -from oslo_config import cfg -from oslo_config import fixture as fixture_config # noqa -from oslo_context import context -from oslo_context import fixture as fixture_context -from oslo_i18n import fixture as fixture_trans -from oslo_serialization import jsonutils -from oslotest import base as test_base -import six -import testtools - -from oslo_log import _options -from oslo_log import formatters -from oslo_log import handlers -from oslo_log import log - - -MIN_LOG_INI = b"""[loggers] -keys=root - -[formatters] -keys= - -[handlers] -keys= - -[logger_root] -handlers= -""" - - -def _fake_context(): - ctxt = context.RequestContext(1, 1, overwrite=True) - ctxt.user = 'myuser' - ctxt.tenant = 'mytenant' - ctxt.domain = 'mydomain' - ctxt.project_domain = 'myprojectdomain' - ctxt.user_domain = 'myuserdomain' - - return ctxt - - -class CommonLoggerTestsMixIn(object): - """These tests are shared between LoggerTestCase and - LazyLoggerTestCase. - """ - - def setUp(self): - super(CommonLoggerTestsMixIn, self).setUp() - # common context has different fields to the defaults in log.py - self.config_fixture = self.useFixture( - fixture_config.Config(cfg.ConfigOpts())) - self.config = self.config_fixture.config - self.CONF = self.config_fixture.conf - log.register_options(self.config_fixture.conf) - self.config(logging_context_format_string='%(asctime)s %(levelname)s ' - '%(name)s [%(request_id)s ' - '%(user)s %(tenant)s] ' - '%(message)s') - self.log = None - log._setup_logging_from_conf(self.config_fixture.conf, 'test', 'test') - - def test_handlers_have_context_formatter(self): - formatters_list = [] - for h in self.log.logger.handlers: - f = h.formatter - if isinstance(f, formatters.ContextFormatter): - formatters_list.append(f) - self.assertTrue(formatters_list) - self.assertEqual(len(formatters_list), len(self.log.logger.handlers)) - - def test_handles_context_kwarg(self): - self.log.info("foo", context=_fake_context()) - self.assertTrue(True) # didn't raise exception - - def test_will_be_verbose_if_verbose_flag_set(self): - self.config(verbose=True) - logger_name = 'test_is_verbose' - log.setup(self.CONF, logger_name) - logger = logging.getLogger(logger_name) - self.assertEqual(logging.INFO, logger.getEffectiveLevel()) - - def test_will_be_debug_if_debug_flag_set(self): - self.config(debug=True) - logger_name = 'test_is_debug' - log.setup(self.CONF, logger_name) - logger = logging.getLogger(logger_name) - self.assertEqual(logging.DEBUG, logger.getEffectiveLevel()) - - def test_will_not_be_verbose_if_verbose_flag_not_set(self): - self.config(verbose=False) - logger_name = 'test_is_not_verbose' - log.setup(self.CONF, logger_name) - logger = logging.getLogger(logger_name) - self.assertEqual(logging.WARN, logger.getEffectiveLevel()) - - def test_no_logging_via_module(self): - for func in ('critical', 'error', 'exception', 'warning', 'warn', - 'info', 'debug', 'log'): - self.assertRaises(AttributeError, getattr, log, func) - - -class LoggerTestCase(CommonLoggerTestsMixIn, test_base.BaseTestCase): - def setUp(self): - super(LoggerTestCase, self).setUp() - self.log = log.getLogger(None) - - -class BaseTestCase(test_base.BaseTestCase): - def setUp(self): - super(BaseTestCase, self).setUp() - self.context_fixture = self.useFixture( - fixture_context.ClearRequestContext()) - self.config_fixture = self.useFixture( - fixture_config.Config(cfg.ConfigOpts())) - self.config = self.config_fixture.config - self.CONF = self.config_fixture.conf - log.register_options(self.CONF) - log.setup(self.CONF, 'base') - - -class LogTestBase(BaseTestCase): - """Base test class that provides some convenience functions.""" - def _add_handler_with_cleanup(self, log_instance, handler=None, - formatter=None): - """Add a log handler to a log instance. - - This function should be used to add handlers to loggers in test cases - instead of directly adding them to ensure that the handler is - correctly removed at the end of the test. Otherwise the handler may - be left on the logger and interfere with subsequent tests. - - :param log_instance: The log instance to which the handler will be - added. - :param handler: The handler class to be added. Must be the class - itself, not an instance. - :param formatter: The formatter class to set on the handler. Must be - the class itself, not an instance. - """ - self.stream = six.StringIO() - if handler is None: - handler = logging.StreamHandler - self.handler = handler(self.stream) - if formatter is None: - formatter = formatters.ContextFormatter - self.handler.setFormatter(formatter()) - log_instance.logger.addHandler(self.handler) - self.addCleanup(log_instance.logger.removeHandler, self.handler) - - def _set_log_level_with_cleanup(self, log_instance, level): - """Set the log level of a logger for the duration of a test. - - Use this function to set the log level of a logger and add the - necessary cleanup to reset it back to default at the end of the test. - - :param log_instance: The logger whose level will be changed. - :param level: The new log level to use. - """ - self.level = log_instance.logger.getEffectiveLevel() - log_instance.logger.setLevel(level) - self.addCleanup(log_instance.logger.setLevel, self.level) - - -class LogHandlerTestCase(BaseTestCase): - def test_log_path_logdir(self): - path = '/some/path' - binary = 'foo-bar' - expected = '%s/%s.log' % (path, binary) - self.config(log_dir=path, log_file=None) - self.assertEqual(log._get_log_file_path(self.config_fixture.conf, - binary=binary), - expected) - - def test_log_path_logfile(self): - path = '/some/path' - binary = 'foo-bar' - expected = '%s/%s.log' % (path, binary) - self.config(log_file=expected) - self.assertEqual(log._get_log_file_path(self.config_fixture.conf, - binary=binary), - expected) - - def test_log_path_none(self): - prefix = 'foo-bar' - self.config(log_dir=None, log_file=None) - self.assertIsNone(log._get_log_file_path(self.config_fixture.conf, - binary=prefix)) - - def test_log_path_logfile_overrides_logdir(self): - path = '/some/path' - prefix = 'foo-bar' - expected = '%s/%s.log' % (path, prefix) - self.config(log_dir='/some/other/path', - log_file=expected) - self.assertEqual(log._get_log_file_path(self.config_fixture.conf, - binary=prefix), - expected) - - def test_iter_loggers(self): - mylog = logging.getLogger("abc.cde") - loggers = list(log._iter_loggers()) - self.assertIn(logging.getLogger(), loggers) - self.assertIn(mylog, loggers) - - -class SysLogHandlersTestCase(BaseTestCase): - """Test the standard Syslog handler.""" - def setUp(self): - super(SysLogHandlersTestCase, self).setUp() - self.facility = logging.handlers.SysLogHandler.LOG_USER - self.logger = logging.handlers.SysLogHandler(facility=self.facility) - - def test_standard_format(self): - """Ensure syslog msg isn't modified for standard handler.""" - logrecord = logging.LogRecord('name', logging.WARNING, '/tmp', 1, - 'Message', None, None) - expected = logrecord - self.assertEqual(expected.getMessage(), - self.logger.format(logrecord)) - - -@testtools.skipUnless(syslog, "syslog is not available") -class OSSysLogHandlerTestCase(BaseTestCase): - def test_handler(self): - handler = handlers.OSSysLogHandler() - syslog.syslog = mock.Mock() - handler.emit( - logging.LogRecord("foo", logging.INFO, - "path", 123, "hey!", - None, None)) - self.assertTrue(syslog.syslog.called) - - def test_syslog_binary_name(self): - # There is no way to test the actual output written to the - # syslog (e.g. /var/log/syslog) to confirm binary_name value - # is actually present - syslog.openlog = mock.Mock() - handlers.OSSysLogHandler() - syslog.openlog.assert_called_with(handlers._get_binary_name(), - 0, syslog.LOG_USER) - - def test_find_facility(self): - self.assertEqual(syslog.LOG_USER, log._find_facility("user")) - self.assertEqual(syslog.LOG_LPR, log._find_facility("LPR")) - self.assertEqual(syslog.LOG_LOCAL3, log._find_facility("log_local3")) - self.assertEqual(syslog.LOG_UUCP, log._find_facility("LOG_UUCP")) - self.assertRaises(TypeError, - log._find_facility, - "fougere") - - def test_syslog(self): - msg_unicode = u"Benoît Knecht & François Deppierraz login failure" - msg_utf8 = msg_unicode.encode('utf-8') - - handler = handlers.OSSysLogHandler() - syslog.syslog = mock.Mock() - handler.emit( - logging.LogRecord("name", logging.INFO, "path", 123, - msg_unicode, None, None)) - syslog.syslog.assert_called_once_with(syslog.LOG_INFO, msg_utf8) - - -class LogLevelTestCase(BaseTestCase): - def setUp(self): - super(LogLevelTestCase, self).setUp() - levels = self.CONF.default_log_levels - info_level = 'nova-test' - warn_level = 'nova-not-debug' - other_level = 'nova-below-debug' - trace_level = 'nova-trace' - levels.append(info_level + '=INFO') - levels.append(warn_level + '=WARN') - levels.append(other_level + '=7') - levels.append(trace_level + '=TRACE') - self.config(default_log_levels=levels, - verbose=True) - log.setup(self.CONF, 'testing') - self.log = log.getLogger(info_level) - self.log_no_debug = log.getLogger(warn_level) - self.log_below_debug = log.getLogger(other_level) - self.log_trace = log.getLogger(trace_level) - - def test_is_enabled_for(self): - self.assertTrue(self.log.isEnabledFor(logging.INFO)) - self.assertFalse(self.log_no_debug.isEnabledFor(logging.DEBUG)) - self.assertTrue(self.log_below_debug.isEnabledFor(logging.DEBUG)) - self.assertTrue(self.log_below_debug.isEnabledFor(7)) - self.assertTrue(self.log_trace.isEnabledFor(log.TRACE)) - - def test_has_level_from_flags(self): - self.assertEqual(logging.INFO, self.log.logger.getEffectiveLevel()) - - def test_has_level_from_flags_for_trace(self): - self.assertEqual(log.TRACE, self.log_trace.logger.getEffectiveLevel()) - - def test_child_log_has_level_of_parent_flag(self): - l = log.getLogger('nova-test.foo') - self.assertEqual(logging.INFO, l.logger.getEffectiveLevel()) - - def test_child_log_has_level_of_parent_flag_for_trace(self): - l = log.getLogger('nova-trace.foo') - self.assertEqual(log.TRACE, l.logger.getEffectiveLevel()) - - -class JSONFormatterTestCase(LogTestBase): - def setUp(self): - super(JSONFormatterTestCase, self).setUp() - self.log = log.getLogger('test-json') - self._add_handler_with_cleanup(self.log, - formatter=formatters.JSONFormatter) - self._set_log_level_with_cleanup(self.log, logging.DEBUG) - - def test_json(self): - test_msg = 'This is a %(test)s line' - test_data = {'test': 'log'} - local_context = _fake_context() - self.log.debug(test_msg, test_data, key='value', context=local_context) - - data = jsonutils.loads(self.stream.getvalue()) - self.assertTrue(data) - self.assertTrue('extra' in data) - extra = data['extra'] - self.assertEqual('value', extra['key']) - self.assertEqual(local_context.auth_token, extra['auth_token']) - self.assertEqual(local_context.user, extra['user']) - self.assertEqual('test-json', data['name']) - - self.assertEqual(test_msg % test_data, data['message']) - self.assertEqual(test_msg, data['msg']) - self.assertEqual(test_data, data['args']) - - self.assertEqual('test_log.py', data['filename']) - self.assertEqual('test_json', data['funcname']) - - self.assertEqual('DEBUG', data['levelname']) - self.assertEqual(logging.DEBUG, data['levelno']) - self.assertFalse(data['traceback']) - - def test_json_exception(self): - test_msg = 'This is %s' - test_data = 'exceptional' - try: - raise Exception('This is exceptional') - except Exception: - self.log.exception(test_msg, test_data) - - data = jsonutils.loads(self.stream.getvalue()) - self.assertTrue(data) - self.assertTrue('extra' in data) - self.assertEqual('test-json', data['name']) - - self.assertEqual(test_msg % test_data, data['message']) - self.assertEqual(test_msg, data['msg']) - self.assertEqual([test_data], data['args']) - - self.assertEqual('ERROR', data['levelname']) - self.assertEqual(logging.ERROR, data['levelno']) - self.assertTrue(data['traceback']) - - def test_json_with_extra(self): - test_msg = 'This is a %(test)s line' - test_data = {'test': 'log'} - extra_data = {'special_user': 'user1', - 'special_tenant': 'unicorns'} - self.log.debug(test_msg, test_data, key='value', extra=extra_data) - - data = jsonutils.loads(self.stream.getvalue()) - self.assertTrue(data) - self.assertTrue('extra' in data) - for k, v in extra_data.items(): - self.assertIn(k, data['extra']) - self.assertEqual(v, data['extra'][k]) - - def test_json_with_extra_keys(self): - test_msg = 'This is a %(test)s line' - test_data = {'test': 'log'} - extra_keys = ['special_tenant', 'special_user'] - special_tenant = 'unicorns' - special_user = 'user2' - self.log.debug(test_msg, test_data, key='value', - extra_keys=extra_keys, special_tenant=special_tenant, - special_user=special_user) - - data = jsonutils.loads(self.stream.getvalue()) - self.assertTrue(data) - self.assertTrue('extra' in data) - self.assertTrue(extra_keys[0] in data['extra']) - self.assertEqual(special_tenant, data['extra'][extra_keys[0]]) - self.assertTrue(extra_keys[1] in data['extra']) - self.assertEqual(special_user, data['extra'][extra_keys[1]]) - - def test_can_process_strings(self): - expected = b'\\u2622' - if six.PY3: - # see ContextFormatterTestCase.test_can_process_strings - expected = '\\\\xe2\\\\x98\\\\xa2' - self.log.info(b'%s', u'\u2622'.encode('utf8')) - self.assertIn(expected, self.stream.getvalue()) - - -def get_fake_datetime(retval): - class FakeDateTime(datetime.datetime): - @classmethod - def fromtimestamp(cls, timestamp): - return retval - - return FakeDateTime - - -class ContextFormatterTestCase(LogTestBase): - def setUp(self): - super(ContextFormatterTestCase, self).setUp() - self.config(logging_context_format_string="HAS CONTEXT " - "[%(request_id)s]: " - "%(message)s", - logging_default_format_string="NOCTXT: %(message)s", - logging_debug_format_suffix="--DBG") - self.log = log.getLogger('') # obtain root logger instead of 'unknown' - self._add_handler_with_cleanup(self.log) - self._set_log_level_with_cleanup(self.log, logging.DEBUG) - self.trans_fixture = self.useFixture(fixture_trans.Translation()) - - def test_uncontextualized_log(self): - message = 'foo' - self.log.info(message) - self.assertEqual("NOCTXT: %s\n" % message, self.stream.getvalue()) - - def test_contextualized_log(self): - ctxt = _fake_context() - message = 'bar' - self.log.info(message, context=ctxt) - expected = 'HAS CONTEXT [%s]: %s\n' % (ctxt.request_id, message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_context_is_taken_from_tls_variable(self): - ctxt = _fake_context() - message = 'bar' - self.log.info(message) - expected = "HAS CONTEXT [%s]: %s\n" % (ctxt.request_id, message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_contextual_information_is_imparted_to_3rd_party_log_records(self): - ctxt = _fake_context() - sa_log = logging.getLogger('sqlalchemy.engine') - sa_log.setLevel(logging.INFO) - message = 'emulate logging within sqlalchemy' - sa_log.info(message) - - expected = ('HAS CONTEXT [%s]: %s\n' % (ctxt.request_id, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_message_logging_3rd_party_log_records(self): - ctxt = _fake_context() - ctxt.request_id = six.text_type('99') - sa_log = logging.getLogger('sqlalchemy.engine') - sa_log.setLevel(logging.INFO) - message = self.trans_fixture.lazy('test ' + six.unichr(128)) - sa_log.info(message) - - expected = ('HAS CONTEXT [%s]: %s\n' % (ctxt.request_id, - six.text_type(message))) - self.assertEqual(expected, self.stream.getvalue()) - - def test_debugging_log(self): - message = 'baz' - self.log.debug(message) - self.assertEqual("NOCTXT: %s --DBG\n" % message, - self.stream.getvalue()) - - def test_message_logging(self): - # NOTE(luisg): Logging message objects with unicode objects - # may cause trouble by the logging mechanism trying to coerce - # the Message object, with a wrong encoding. This test case - # tests that problem does not occur. - ctxt = _fake_context() - ctxt.request_id = six.text_type('99') - message = self.trans_fixture.lazy('test ' + six.unichr(128)) - self.log.info(message, context=ctxt) - expected = "HAS CONTEXT [%s]: %s\n" % (ctxt.request_id, - six.text_type(message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_unicode_conversion_in_adapter(self): - ctxt = _fake_context() - ctxt.request_id = six.text_type('99') - message = "Exception is (%s)" - ex = Exception(self.trans_fixture.lazy('test' + six.unichr(128))) - self.log.debug(message, ex, context=ctxt) - message = six.text_type(message) % ex - expected = "HAS CONTEXT [%s]: %s --DBG\n" % (ctxt.request_id, - message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_unicode_conversion_in_formatter(self): - ctxt = _fake_context() - ctxt.request_id = six.text_type('99') - no_adapt_log = logging.getLogger('no_adapt') - no_adapt_log.setLevel(logging.INFO) - message = "Exception is (%s)" - ex = Exception(self.trans_fixture.lazy('test' + six.unichr(128))) - no_adapt_log.info(message, ex) - message = six.text_type(message) % ex - expected = "HAS CONTEXT [%s]: %s\n" % (ctxt.request_id, - message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_user_identity_logging(self): - self.config(logging_context_format_string="HAS CONTEXT " - "[%(request_id)s " - "%(user_identity)s]: " - "%(message)s") - ctxt = _fake_context() - ctxt.request_id = u'99' - message = 'test' - self.log.info(message, context=ctxt) - expected = ("HAS CONTEXT [%s %s %s %s %s %s]: %s\n" % - (ctxt.request_id, ctxt.user, ctxt.tenant, ctxt.domain, - ctxt.user_domain, ctxt.project_domain, - six.text_type(message))) - self.assertEqual(expected, self.stream.getvalue()) - - def test_user_identity_logging_set_format(self): - self.config(logging_context_format_string="HAS CONTEXT " - "[%(request_id)s " - "%(user_identity)s]: " - "%(message)s", - logging_user_identity_format="%(user)s " - "%(tenant)s") - ctxt = _fake_context() - ctxt.request_id = u'99' - message = 'test' - self.log.info(message, context=ctxt) - expected = ("HAS CONTEXT [%s %s %s]: %s\n" % - (ctxt.request_id, ctxt.user, ctxt.tenant, - six.text_type(message))) - self.assertEqual(expected, self.stream.getvalue()) - - @mock.patch("datetime.datetime", - get_fake_datetime( - datetime.datetime(2015, 12, 16, 13, 54, 26, 517893))) - @mock.patch("dateutil.tz.tzlocal", new=mock.Mock(return_value=tz.tzutc())) - def test_rfc5424_isotime_format(self): - self.config(logging_default_format_string="%(isotime)s %(message)s") - - message = "test" - expected = "2015-12-16T13:54:26.517893+00:00 %s\n" % message - - self.log.info(message) - - self.assertEqual(expected, self.stream.getvalue()) - - @mock.patch("datetime.datetime", - get_fake_datetime( - datetime.datetime(2015, 12, 16, 13, 54, 26))) - @mock.patch("time.time", new=mock.Mock(return_value=1450274066.000000)) - @mock.patch("dateutil.tz.tzlocal", new=mock.Mock(return_value=tz.tzutc())) - def test_rfc5424_isotime_format_no_microseconds(self): - self.config(logging_default_format_string="%(isotime)s %(message)s") - - message = "test" - expected = "2015-12-16T13:54:26.000000+00:00 %s\n" % message - - self.log.info(message) - - self.assertEqual(expected, self.stream.getvalue()) - - def test_can_process_strings(self): - expected = b'\xe2\x98\xa2' - if six.PY3: - # in PY3 logging format string should be unicode string - # or it will fail and inserting byte string in unicode string - # causes such formatting - expected = '\\xe2\\x98\\xa2' - self.log.info(b'%s', u'\u2622'.encode('utf8')) - self.assertIn(expected, self.stream.getvalue()) - - -class ExceptionLoggingTestCase(LogTestBase): - """Test that Exceptions are logged.""" - - def test_excepthook_logs_exception(self): - product_name = 'somename' - exc_log = log.getLogger(product_name) - - self._add_handler_with_cleanup(exc_log) - excepthook = log._create_logging_excepthook(product_name) - - try: - raise Exception('Some error happened') - except Exception: - excepthook(*sys.exc_info()) - - expected_string = ("CRITICAL somename [-] " - "Exception: Some error happened") - self.assertTrue(expected_string in self.stream.getvalue(), - msg="Exception is not logged") - - def test_excepthook_installed(self): - log.setup(self.CONF, "test_excepthook_installed") - self.assertTrue(sys.excepthook != sys.__excepthook__) - - @mock.patch("datetime.datetime", - get_fake_datetime( - datetime.datetime(2015, 12, 16, 13, 54, 26, 517893))) - @mock.patch("dateutil.tz.tzlocal", new=mock.Mock(return_value=tz.tzutc())) - def test_rfc5424_isotime_format(self): - self.config( - logging_default_format_string="%(isotime)s %(message)s", - logging_exception_prefix="%(isotime)s ", - ) - - product_name = 'somename' - exc_log = log.getLogger(product_name) - - self._add_handler_with_cleanup(exc_log) - excepthook = log._create_logging_excepthook(product_name) - - message = 'Some error happened' - try: - raise Exception(message) - except Exception: - excepthook(*sys.exc_info()) - - expected_string = ("2015-12-16T13:54:26.517893+00:00 " - "Exception: %s" % message) - self.assertIn(expected_string, - self.stream.getvalue()) - - -class FancyRecordTestCase(LogTestBase): - """Test how we handle fancy record keys that are not in the - base python logging. - """ - - def setUp(self): - super(FancyRecordTestCase, self).setUp() - # NOTE(sdague): use the different formatters to demonstrate format - # string with valid fancy keys and without. Slightly hacky, but given - # the way log objects layer up seemed to be most concise approach - self.config(logging_context_format_string="%(color)s " - "[%(request_id)s]: " - "%(instance)s" - "%(resource)s" - "%(message)s", - logging_default_format_string="%(missing)s: %(message)s") - self.colorlog = log.getLogger() - self._add_handler_with_cleanup(self.colorlog, handlers.ColorHandler) - self._set_log_level_with_cleanup(self.colorlog, logging.DEBUG) - - def test_unsupported_key_in_log_msg(self): - # NOTE(sdague): exception logging bypasses the main stream - # and goes to stderr. Suggests on a better way to do this are - # welcomed. - error = sys.stderr - sys.stderr = six.StringIO() - - self.colorlog.info("foo") - self.assertNotEqual(-1, - sys.stderr.getvalue().find("KeyError: 'missing'")) - - sys.stderr = error - - def _validate_keys(self, ctxt, keyed_log_string): - infocolor = handlers.ColorHandler.LEVEL_COLORS[logging.INFO] - warncolor = handlers.ColorHandler.LEVEL_COLORS[logging.WARN] - info_msg = 'info' - warn_msg = 'warn' - infoexpected = "%s %s %s\n" % (infocolor, keyed_log_string, info_msg) - warnexpected = "%s %s %s\n" % (warncolor, keyed_log_string, warn_msg) - - self.colorlog.info(info_msg, context=ctxt) - self.assertEqual(infoexpected, self.stream.getvalue()) - self.assertEqual('\033[00;36m', infocolor) - - self.colorlog.warn(warn_msg, context=ctxt) - self.assertEqual(infoexpected + warnexpected, self.stream.getvalue()) - self.assertEqual('\033[01;33m', warncolor) - - def test_fancy_key_in_log_msg(self): - ctxt = _fake_context() - self._validate_keys(ctxt, '[%s]:' % ctxt.request_id) - - def test_instance_key_in_log_msg(self): - ctxt = _fake_context() - ctxt.resource_uuid = '1234' - self._validate_keys(ctxt, ('[%s]: [instance: %s]' % - (ctxt.request_id, ctxt.resource_uuid))) - - def test_resource_key_in_log_msg(self): - color = handlers.ColorHandler.LEVEL_COLORS[logging.INFO] - ctxt = _fake_context() - resource = 'resource-202260f9-1224-490d-afaf-6a744c13141f' - fake_resource = {'name': resource} - message = 'info' - self.colorlog.info(message, context=ctxt, resource=fake_resource) - expected = ('%s [%s]: [%s] %s\n' % - (color, ctxt.request_id, resource, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_resource_key_dict_in_log_msg(self): - color = handlers.ColorHandler.LEVEL_COLORS[logging.INFO] - ctxt = _fake_context() - type = 'fake_resource' - resource_id = '202260f9-1224-490d-afaf-6a744c13141f' - fake_resource = {'type': type, - 'id': resource_id} - message = 'info' - self.colorlog.info(message, context=ctxt, resource=fake_resource) - expected = ('%s [%s]: [%s-%s] %s\n' % - (color, ctxt.request_id, type, resource_id, message)) - self.assertEqual(expected, self.stream.getvalue()) - - -class InstanceRecordTestCase(LogTestBase): - def setUp(self): - super(InstanceRecordTestCase, self).setUp() - self.config(logging_context_format_string="[%(request_id)s]: " - "%(instance)s" - "%(resource)s" - "%(message)s", - logging_default_format_string="%(instance)s" - "%(resource)s" - "%(message)s") - self.log = log.getLogger() - self._add_handler_with_cleanup(self.log) - self._set_log_level_with_cleanup(self.log, logging.DEBUG) - - def test_instance_dict_in_context_log_msg(self): - ctxt = _fake_context() - uuid = 'C9B7CCC6-8A12-4C53-A736-D7A1C36A62F3' - fake_resource = {'uuid': uuid} - message = 'info' - self.log.info(message, context=ctxt, instance=fake_resource) - expected = ('[%s]: [instance: %s] %s\n' % - (ctxt.request_id, uuid, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_instance_dict_in_default_log_msg(self): - uuid = 'C9B7CCC6-8A12-4C53-A736-D7A1C36A62F3' - fake_resource = {'uuid': uuid} - message = 'info' - self.log.info(message, instance=fake_resource) - expected = '[instance: %s] %s\n' % (uuid, message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_instance_uuid_as_arg_in_context_log_msg(self): - ctxt = _fake_context() - uuid = 'C9B7CCC6-8A12-4C53-A736-D7A1C36A62F3' - message = 'info' - self.log.info(message, context=ctxt, instance_uuid=uuid) - expected = ('[%s]: [instance: %s] %s\n' % - (ctxt.request_id, uuid, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_instance_uuid_as_arg_in_default_log_msg(self): - uuid = 'C9B7CCC6-8A12-4C53-A736-D7A1C36A62F3' - message = 'info' - self.log.info(message, instance_uuid=uuid) - expected = '[instance: %s] %s\n' % (uuid, message) - self.assertEqual(expected, self.stream.getvalue()) - - def test_instance_uuid_from_context_in_context_log_msg(self): - ctxt = _fake_context() - ctxt.instance_uuid = 'CCCCCCCC-8A12-4C53-A736-D7A1C36A62F3' - message = 'info' - self.log.info(message, context=ctxt) - expected = ('[%s]: [instance: %s] %s\n' % - (ctxt.request_id, ctxt.instance_uuid, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_resource_uuid_from_context_in_context_log_msg(self): - ctxt = _fake_context() - ctxt.resource_uuid = 'RRRRRRRR-8A12-4C53-A736-D7A1C36A62F3' - message = 'info' - self.log.info(message, context=ctxt) - expected = ('[%s]: [instance: %s] %s\n' % - (ctxt.request_id, ctxt.resource_uuid, message)) - self.assertEqual(expected, self.stream.getvalue()) - - def test_instance_from_context_in_context_log_msg(self): - # NOTE: instance when passed in a context object is just a uuid. - # When passed to the log record, it is a dict. - ctxt = _fake_context() - ctxt.instance = 'IIIIIIII-8A12-4C53-A736-D7A1C36A62F3' - message = 'info' - self.log.info(message, context=ctxt) - values = (ctxt.request_id, ctxt.instance, message) - expected = '[%s]: [instance: %s] %s\n' % values - self.assertEqual(expected, self.stream.getvalue()) - - -class TraceLevelTestCase(LogTestBase): - def setUp(self): - super(TraceLevelTestCase, self).setUp() - self.config(logging_context_format_string="%(message)s") - self.mylog = log.getLogger() - self._add_handler_with_cleanup(self.mylog) - self._set_log_level_with_cleanup(self.mylog, log.TRACE) - - def test_trace_log_msg(self): - ctxt = _fake_context() - message = 'my trace message' - self.mylog.trace(message, context=ctxt) - self.assertEqual('%s\n' % message, self.stream.getvalue()) - - -class DomainTestCase(LogTestBase): - def setUp(self): - super(DomainTestCase, self).setUp() - self.config(logging_context_format_string="[%(request_id)s]: " - "%(user_identity)s " - "%(message)s") - self.mylog = log.getLogger() - self._add_handler_with_cleanup(self.mylog) - self._set_log_level_with_cleanup(self.mylog, logging.DEBUG) - - def _validate_keys(self, ctxt, keyed_log_string): - info_message = 'info' - infoexpected = "%s %s\n" % (keyed_log_string, info_message) - warn_message = 'warn' - warnexpected = "%s %s\n" % (keyed_log_string, warn_message) - - self.mylog.info(info_message, context=ctxt) - self.assertEqual(infoexpected, self.stream.getvalue()) - - self.mylog.warn(warn_message, context=ctxt) - self.assertEqual(infoexpected + warnexpected, self.stream.getvalue()) - - def test_domain_in_log_msg(self): - ctxt = _fake_context() - user_identity = ctxt.get_logging_values()['user_identity'] - self.assertTrue(ctxt.domain in user_identity) - self.assertTrue(ctxt.project_domain in user_identity) - self.assertTrue(ctxt.user_domain in user_identity) - self._validate_keys(ctxt, ('[%s]: %s' % - (ctxt.request_id, user_identity))) - - -class SetDefaultsTestCase(BaseTestCase): - class TestConfigOpts(cfg.ConfigOpts): - def __call__(self, args=None): - return cfg.ConfigOpts.__call__(self, - args=args, - prog='test', - version='1.0', - usage='%(prog)s FOO BAR', - default_config_files=[]) - - def setUp(self): - super(SetDefaultsTestCase, self).setUp() - self.conf = self.TestConfigOpts() - self.conf.register_opts(_options.log_opts) - self.conf.register_cli_opts(_options.logging_cli_opts) - - self._orig_defaults = dict([(o.dest, o.default) - for o in _options.log_opts]) - self.addCleanup(self._restore_log_defaults) - - def _restore_log_defaults(self): - for opt in _options.log_opts: - opt.default = self._orig_defaults[opt.dest] - - def test_default_log_level_to_none(self): - log.set_defaults(logging_context_format_string=None, - default_log_levels=None) - self.conf([]) - self.assertEqual(_options.DEFAULT_LOG_LEVELS, - self.conf.default_log_levels) - - def test_default_log_level_method(self): - self.assertEqual(_options.DEFAULT_LOG_LEVELS, - log.get_default_log_levels()) - - def test_change_default(self): - my_default = '%(asctime)s %(levelname)s %(name)s [%(request_id)s '\ - '%(user_id)s %(project)s] %(instance)s'\ - '%(message)s' - log.set_defaults(logging_context_format_string=my_default) - self.conf([]) - self.assertEqual(self.conf.logging_context_format_string, my_default) - - def test_change_default_log_level(self): - package_log_level = 'foo=bar' - log.set_defaults(default_log_levels=[package_log_level]) - self.conf([]) - self.assertEqual([package_log_level], self.conf.default_log_levels) - self.assertIsNotNone(self.conf.logging_context_format_string) - - def test_tempest_set_log_file(self): - log_file = 'foo.log' - log.tempest_set_log_file(log_file) - self.addCleanup(log.tempest_set_log_file, None) - log.set_defaults() - self.conf([]) - self.assertEqual(log_file, self.conf.log_file) - - def test_log_file_defaults_to_none(self): - log.set_defaults() - self.conf([]) - self.assertIsNone(self.conf.log_file) - - -@testtools.skipIf(platform.system() != 'Linux', - 'pyinotify library works on Linux platform only.') -class FastWatchedFileHandlerTestCase(BaseTestCase): - - def setUp(self): - super(FastWatchedFileHandlerTestCase, self).setUp() - - def _config(self): - os_level, log_path = tempfile.mkstemp() - log_dir_path = os.path.dirname(log_path) - log_file_path = os.path.basename(log_path) - self.CONF(['--log-dir', log_dir_path, '--log-file', log_file_path]) - self.config(use_stderr=False) - self.config(watch_log_file=True) - log.setup(self.CONF, 'test', 'test') - return log_path - - def test_instantiate(self): - self._config() - logger = log._loggers[None].logger - self.assertEqual(1, len(logger.handlers)) - from oslo_log import watchers - self.assertIsInstance(logger.handlers[0], - watchers.FastWatchedFileHandler) - - def test_log(self): - log_path = self._config() - logger = log._loggers[None].logger - text = 'Hello World!' - logger.info(text) - with open(log_path, 'r') as f: - file_content = f.read() - self.assertTrue(text in file_content) - - def test_move(self): - log_path = self._config() - os_level_dst, log_path_dst = tempfile.mkstemp() - os.rename(log_path, log_path_dst) - time.sleep(6) - self.assertTrue(os.path.exists(log_path)) - - def test_remove(self): - log_path = self._config() - os.remove(log_path) - time.sleep(6) - self.assertTrue(os.path.exists(log_path)) - - -class MutateTestCase(BaseTestCase): - def setup_confs(self, *confs): - paths = self.create_tempfiles( - ('conf_%d' % i, conf) for i, conf in enumerate(confs)) - self.CONF(['--config-file', paths[0]]) - return paths - - def test_debug(self): - paths = self.setup_confs( - "[DEFAULT]\ndebug = false\n", - "[DEFAULT]\ndebug = true\n") - log_root = log.getLogger(None).logger - log._setup_logging_from_conf(self.CONF, 'test', 'test') - self.assertEqual(False, self.CONF.debug) - self.assertEqual(True, self.CONF.verbose) - self.assertEqual(log.INFO, log_root.getEffectiveLevel()) - - shutil.copy(paths[1], paths[0]) - self.CONF.mutate_config_files() - - self.assertEqual(True, self.CONF.debug) - self.assertEqual(True, self.CONF.verbose) - self.assertEqual(log.DEBUG, log_root.getEffectiveLevel()) - - @mock.patch.object(logging.config, "fileConfig") - def test_log_config_append(self, mock_fileConfig): - logini = self.create_tempfiles([('log.ini', MIN_LOG_INI)])[0] - paths = self.setup_confs( - "[DEFAULT]\nlog_config_append = no_exist\n", - "[DEFAULT]\nlog_config_append = %s\n" % logini) - self.assertRaises(log.LogConfigError, log.setup, self.CONF, '') - self.assertFalse(mock_fileConfig.called) - - shutil.copy(paths[1], paths[0]) - self.CONF.mutate_config_files() - - mock_fileConfig.assert_called_once_with( - logini, disable_existing_loggers=False) - - @mock.patch.object(logging.config, "fileConfig") - def test_log_config_append_no_touch(self, mock_fileConfig): - logini = self.create_tempfiles([('log.ini', MIN_LOG_INI)])[0] - self.setup_confs("[DEFAULT]\nlog_config_append = %s\n" % logini) - log.setup(self.CONF, '') - mock_fileConfig.assert_called_once_with( - logini, disable_existing_loggers=False) - mock_fileConfig.reset_mock() - - self.CONF.mutate_config_files() - - self.assertFalse(mock_fileConfig.called) - - @mock.patch.object(logging.config, "fileConfig") - def test_log_config_append_touch(self, mock_fileConfig): - logini = self.create_tempfiles([('log.ini', MIN_LOG_INI)])[0] - self.setup_confs("[DEFAULT]\nlog_config_append = %s\n" % logini) - log.setup(self.CONF, '') - mock_fileConfig.assert_called_once_with( - logini, disable_existing_loggers=False) - mock_fileConfig.reset_mock() - - # No thread sync going on here, just ensure the mtimes are different - time.sleep(0.1) - os.utime(logini, None) - self.CONF.mutate_config_files() - - mock_fileConfig.assert_called_once_with( - logini, disable_existing_loggers=False) - - def mk_log_config(self, data): - """Turns a dictConfig-like structure into one suitable for fileConfig. - - The schema is not validated as this is a test helper not production - code. Garbage in, garbage out. Particularly, don't try to use filters, - fileConfig doesn't support them. - - Handler args must be passed like 'args': (1, 2). dictConfig passes - keys by keyword name and fileConfig passes them by position so - accepting the dictConfig form makes it nigh impossible to produce the - fileConfig form. - - I traverse dicts by sorted keys for output stability but it doesn't - matter if defaulted keys are out of order. - """ - lines = [] - for section in ['formatters', 'handlers', 'loggers']: - items = data.get(section, {}) - keys = sorted(items) - skeys = ",".join(keys) - if section == 'loggers' and 'root' in data: - skeys = ("root," + skeys) if skeys else "root" - lines.extend(["[%s]" % section, - "keys=%s" % skeys]) - for key in keys: - lines.extend(["", - "[%s_%s]" % (section[:-1], key)]) - item = items[key] - lines.extend("%s=%s" % (k, item[k]) for k in sorted(item)) - if section == 'handlers': - if 'args' not in item: - lines.append("args=()") - elif section == 'loggers': - lines.append("qualname=%s" % key) - if 'handlers' not in item: - lines.append("handlers=") - lines.append("") - root = data.get('root', {}) - if root: - lines.extend(["[logger_root]"]) - lines.extend("%s=%s" % (k, root[k]) for k in sorted(root)) - if 'handlers' not in root: - lines.append("handlers=") - return "\n".join(lines) - - def test_mk_log_config_full(self): - data = {'loggers': {'aaa': {'level': 'INFO'}, - 'bbb': {'level': 'WARN', - 'propagate': False}}, - 'handlers': {'aaa': {'level': 'INFO'}, - 'bbb': {'level': 'WARN', - 'propagate': False, - 'args': (1, 2)}}, - 'formatters': {'aaa': {'level': 'INFO'}, - 'bbb': {'level': 'WARN', - 'propagate': False}}, - 'root': {'level': 'INFO', - 'handlers': 'aaa'}, - } - full = """[formatters] -keys=aaa,bbb - -[formatter_aaa] -level=INFO - -[formatter_bbb] -level=WARN -propagate=False - -[handlers] -keys=aaa,bbb - -[handler_aaa] -level=INFO -args=() - -[handler_bbb] -args=(1, 2) -level=WARN -propagate=False - -[loggers] -keys=root,aaa,bbb - -[logger_aaa] -level=INFO -qualname=aaa -handlers= - -[logger_bbb] -level=WARN -propagate=False -qualname=bbb -handlers= - -[logger_root] -handlers=aaa -level=INFO""" - self.assertEqual(full, self.mk_log_config(data)) - - def test_mk_log_config_empty(self): - """Ensure mk_log_config tolerates missing bits""" - empty = """[formatters] -keys= - -[handlers] -keys= - -[loggers] -keys= -""" - self.assertEqual(empty, self.mk_log_config({})) - - @contextmanager - def mutate_conf(self, conf1, conf2): - loginis = self.create_tempfiles([ - ('log1.ini', self.mk_log_config(conf1)), - ('log2.ini', self.mk_log_config(conf2))]) - confs = self.setup_confs( - "[DEFAULT]\nlog_config_append = %s\n" % loginis[0], - "[DEFAULT]\nlog_config_append = %s\n" % loginis[1]) - log.setup(self.CONF, '') - - yield loginis, confs - shutil.copy(confs[1], confs[0]) - self.CONF.mutate_config_files() - - @mock.patch.object(logging.config, "fileConfig") - def test_log_config_append_change_file(self, mock_fileConfig): - with self.mutate_conf({}, {}) as (loginis, confs): - mock_fileConfig.assert_called_once_with( - loginis[0], disable_existing_loggers=False) - mock_fileConfig.reset_mock() - - mock_fileConfig.assert_called_once_with( - loginis[1], disable_existing_loggers=False) - - def set_root_stream(self): - root = logging.getLogger() - self.assertEqual(1, len(root.handlers)) - handler = root.handlers[0] - handler.stream = six.StringIO() - return handler.stream - - def test_remove_handler(self): - fake_handler = {'class': 'logging.StreamHandler', - 'args': ()} - conf1 = {'root': {'handlers': 'fake'}, - 'handlers': {'fake': fake_handler}} - conf2 = {'root': {'handlers': ''}} - with self.mutate_conf(conf1, conf2) as (loginis, confs): - stream = self.set_root_stream() - root = logging.getLogger() - root.error("boo") - self.assertEqual("boo\n", stream.getvalue()) - stream.truncate(0) - root.error("boo") - self.assertEqual("", stream.getvalue()) - - def test_remove_logger(self): - fake_handler = {'class': 'logging.StreamHandler'} - fake_logger = {'level': 'WARN'} - conf1 = {'root': {'handlers': 'fake'}, - 'handlers': {'fake': fake_handler}, - 'loggers': {'a.a': fake_logger}} - conf2 = {'root': {'handlers': 'fake'}, - 'handlers': {'fake': fake_handler}} - stream = six.StringIO() - with self.mutate_conf(conf1, conf2) as (loginis, confs): - stream = self.set_root_stream() - log = logging.getLogger("a.a") - log.info("info") - log.warn("warn") - self.assertEqual("warn\n", stream.getvalue()) - stream = self.set_root_stream() - log.info("info") - log.warn("warn") - self.assertEqual("info\nwarn\n", stream.getvalue()) - - -class LogConfigOptsTestCase(BaseTestCase): - - def setUp(self): - super(LogConfigOptsTestCase, self).setUp() - - def test_print_help(self): - f = six.StringIO() - self.CONF([]) - self.CONF.print_help(file=f) - for option in ['debug', 'verbose', 'log-config', 'watch-log-file']: - self.assertIn(option, f.getvalue()) - - def test_debug_verbose(self): - self.CONF(['--debug', '--verbose']) - - self.assertEqual(True, self.CONF.debug) - self.assertEqual(True, self.CONF.verbose) - - def test_logging_opts(self): - self.CONF([]) - - self.assertIsNone(self.CONF.log_config_append) - self.assertIsNone(self.CONF.log_file) - self.assertIsNone(self.CONF.log_dir) - - self.assertEqual(_options._DEFAULT_LOG_DATE_FORMAT, - self.CONF.log_date_format) - - self.assertEqual(False, self.CONF.use_syslog) - - def test_log_file(self): - log_file = '/some/path/foo-bar.log' - self.CONF(['--log-file', log_file]) - self.assertEqual(log_file, self.CONF.log_file) - - def test_log_dir_handlers(self): - log_dir = tempfile.mkdtemp() - self.CONF(['--log-dir', log_dir]) - self.CONF.set_default('use_stderr', False) - log._setup_logging_from_conf(self.CONF, 'test', 'test') - logger = log._loggers[None].logger - self.assertEqual(1, len(logger.handlers)) - self.assertIsInstance(logger.handlers[0], - logging.handlers.WatchedFileHandler) - - def test_log_publish_errors_handlers(self): - fake_handler = mock.MagicMock() - with mock.patch('oslo_utils.importutils.import_object', - return_value=fake_handler) as mock_import: - log_dir = tempfile.mkdtemp() - self.CONF(['--log-dir', log_dir]) - self.CONF.set_default('use_stderr', False) - self.CONF.set_default('publish_errors', True) - log._setup_logging_from_conf(self.CONF, 'test', 'test') - logger = log._loggers[None].logger - self.assertEqual(2, len(logger.handlers)) - self.assertIsInstance(logger.handlers[0], - logging.handlers.WatchedFileHandler) - self.assertEqual(fake_handler, logger.handlers[1]) - mock_import.assert_called_once_with( - 'oslo_messaging.notify.log_handler.PublishErrorsHandler', - logging.ERROR) - - def test_logfile_deprecated(self): - logfile = '/some/other/path/foo-bar.log' - self.CONF(['--logfile', logfile]) - self.assertEqual(logfile, self.CONF.log_file) - - def test_log_dir(self): - log_dir = '/some/path/' - self.CONF(['--log-dir', log_dir]) - self.assertEqual(log_dir, self.CONF.log_dir) - - def test_logdir_deprecated(self): - logdir = '/some/other/path/' - self.CONF(['--logdir', logdir]) - self.assertEqual(logdir, self.CONF.log_dir) - - def test_default_formatter(self): - log._setup_logging_from_conf(self.CONF, 'test', 'test') - logger = log._loggers[None].logger - for handler in logger.handlers: - formatter = handler.formatter - self.assertTrue(isinstance(formatter, - formatters.ContextFormatter)) - - def test_handlers_cleanup(self): - """Test that all old handlers get removed from log_root.""" - old_handlers = [log.handlers.ColorHandler(), - log.handlers.ColorHandler()] - log._loggers[None].logger.handlers = list(old_handlers) - log._setup_logging_from_conf(self.CONF, 'test', 'test') - handlers = log._loggers[None].logger.handlers - self.assertEqual(1, len(handlers)) - self.assertNotIn(handlers[0], old_handlers) - - def test_list_opts(self): - all_options = _options.list_opts() - (group, options) = all_options[0] - self.assertIsNone(group) - self.assertEqual((_options.common_cli_opts + - _options.logging_cli_opts + - _options.generic_log_opts + - _options.log_opts + - _options.versionutils.deprecated_opts), options) - - -class LogConfigTestCase(BaseTestCase): - - def setUp(self): - super(LogConfigTestCase, self).setUp() - names = self.create_tempfiles([('logging', MIN_LOG_INI)]) - self.log_config_append = names[0] - - def test_log_config_append_ok(self): - self.config(log_config_append=self.log_config_append) - log.setup(self.CONF, 'test_log_config_append') - - def test_log_config_append_not_exist(self): - os.remove(self.log_config_append) - self.config(log_config_append=self.log_config_append) - self.assertRaises(log.LogConfigError, log.setup, - self.CONF, - 'test_log_config_append') - - def test_log_config_append_invalid(self): - names = self.create_tempfiles([('logging', MIN_LOG_INI[5:])]) - self.log_config_append = names[0] - self.config(log_config_append=self.log_config_append) - self.assertRaises(log.LogConfigError, log.setup, - self.CONF, - 'test_log_config_append') - - def test_log_config_append_unreadable(self): - os.chmod(self.log_config_append, 0) - self.config(log_config_append=self.log_config_append) - self.assertRaises(log.LogConfigError, log.setup, - self.CONF, - 'test_log_config_append') - - def test_log_config_append_disable_existing_loggers(self): - self.config(log_config_append=self.log_config_append) - with mock.patch('logging.config.fileConfig') as fileConfig: - log.setup(self.CONF, 'test_log_config_append') - - fileConfig.assert_called_once_with(self.log_config_append, - disable_existing_loggers=False) - - -class KeywordArgumentAdapterTestCase(BaseTestCase): - - def setUp(self): - super(KeywordArgumentAdapterTestCase, self).setUp() - # Construct a mock that will look like a Logger configured to - # emit messages at DEBUG or higher. - self.mock_log = mock.Mock() - self.mock_log.manager.disable = logging.NOTSET - self.mock_log.isEnabledFor.return_value = True - self.mock_log.getEffectiveLevel.return_value = logging.DEBUG - - def test_empty_kwargs(self): - a = log.KeywordArgumentAdapter(self.mock_log, {}) - msg, kwargs = a.process('message', {}) - self.assertEqual({'extra': {'extra_keys': []}}, kwargs) - - def test_include_constructor_extras(self): - key = 'foo' - val = 'blah' - data = {key: val} - a = log.KeywordArgumentAdapter(self.mock_log, data) - msg, kwargs = a.process('message', {}) - self.assertEqual({'extra': {key: val, 'extra_keys': [key]}}, - kwargs) - - def test_pass_through_exc_info(self): - a = log.KeywordArgumentAdapter(self.mock_log, {}) - exc_message = 'exception' - msg, kwargs = a.process('message', {'exc_info': exc_message}) - self.assertEqual( - {'extra': {'extra_keys': []}, - 'exc_info': exc_message}, - kwargs) - - def test_update_extras(self): - a = log.KeywordArgumentAdapter(self.mock_log, {}) - data = {'context': 'some context object', - 'instance': 'instance identifier', - 'resource_uuid': 'UUID for instance', - 'anything': 'goes'} - expected = copy.copy(data) - - msg, kwargs = a.process('message', data) - self.assertEqual( - {'extra': {'anything': expected['anything'], - 'context': expected['context'], - 'extra_keys': sorted(expected.keys()), - 'instance': expected['instance'], - 'resource_uuid': expected['resource_uuid']}}, - kwargs) - - def test_pass_args_to_log(self): - a = log.KeywordArgumentAdapter(self.mock_log, {}) - message = 'message' - exc_message = 'exception' - key = 'name' - val = 'value' - a.log(logging.DEBUG, message, name=val, exc_info=exc_message) - if six.PY3: - self.mock_log._log.assert_called_once_with( - logging.DEBUG, - message, - (), - extra={key: val, 'extra_keys': [key]}, - exc_info=exc_message - ) - else: - self.mock_log.log.assert_called_once_with( - logging.DEBUG, - message, - extra={key: val, 'extra_keys': [key]}, - exc_info=exc_message - ) - - def test_pass_args_via_debug(self): - a = log.KeywordArgumentAdapter(self.mock_log, {}) - message = 'message' - exc_message = 'exception' - key = 'name' - val = 'value' - a.debug(message, name=val, exc_info=exc_message) - # The adapter implementation for debug() is different for - # python 3, so we expect a different method to be called - # internally. - if six.PY3: - self.mock_log._log.assert_called_once_with( - logging.DEBUG, - message, - (), - extra={key: val, 'extra_keys': [key]}, - exc_info=exc_message - ) - else: - self.mock_log.debug.assert_called_once_with( - message, - extra={key: val, 'extra_keys': [key]}, - exc_info=exc_message - ) - - -class UnicodeConversionTestCase(BaseTestCase): - - _MSG = u'Message with unicode char \ua000 in the middle' - - def test_ascii_to_unicode(self): - msg = self._MSG - enc_msg = msg.encode('utf-8') - result = formatters._ensure_unicode(enc_msg) - self.assertEqual(msg, result) - self.assertIsInstance(result, six.text_type) - - def test_unicode_to_unicode(self): - msg = self._MSG - result = formatters._ensure_unicode(msg) - self.assertEqual(msg, result) - self.assertIsInstance(result, six.text_type) - - def test_exception_to_unicode(self): - msg = self._MSG - exc = Exception(msg) - result = formatters._ensure_unicode(exc) - self.assertEqual(msg, result) - self.assertIsInstance(result, six.text_type) - - -class LoggerNameTestCase(LoggerTestCase): - - def test_oslo_dot(self): - logger_name = 'oslo.subname' - l = log.getLogger(logger_name) - self.assertEqual(logger_name, l.logger.name) - - def test_oslo_underscore(self): - logger_name = 'oslo_subname' - expected = logger_name.replace('_', '.') - l = log.getLogger(logger_name) - self.assertEqual(expected, l.logger.name) diff --git a/oslo_log/tests/unit/test_versionutils.py b/oslo_log/tests/unit/test_versionutils.py deleted file mode 100644 index f3a65f9..0000000 --- a/oslo_log/tests/unit/test_versionutils.py +++ /dev/null @@ -1,371 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslotest import base as test_base -import six -from testtools import matchers -import unittest2 - -from oslo_log import versionutils - - -class DeprecatedTestCase(test_base.BaseTestCase): - def assert_deprecated(self, mock_reporter, no_removal=False, - **expected_details): - if 'in_favor_of' in expected_details: - if no_removal is False: - expected_msg = versionutils._deprecated_msg_with_alternative - else: - expected_msg = getattr( - versionutils, - '_deprecated_msg_with_alternative_no_removal') - else: - if no_removal is False: - expected_msg = versionutils._deprecated_msg_no_alternative - else: - expected_msg = getattr( - versionutils, - '_deprecated_msg_with_no_alternative_no_removal') - # The first argument is the logger, and we don't care about - # that, so ignore it with ANY. - mock_reporter.assert_called_with(mock.ANY, - expected_msg, - expected_details) - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecating_a_function_returns_correct_value(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE) - def do_outdated_stuff(data): - return data - - expected_rv = 'expected return value' - retval = do_outdated_stuff(expected_rv) - - self.assertThat(retval, matchers.Equals(expected_rv)) - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecating_a_method_returns_correct_value(self, mock_reporter): - - class C(object): - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE) - def outdated_method(self, *args): - return args - - retval = C().outdated_method(1, 'of anything') - - self.assertThat(retval, matchers.Equals((1, 'of anything'))) - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_unknown_future_release(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.BEXAR, - in_favor_of='different_stuff()') - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='do_outdated_stuff()', - in_favor_of='different_stuff()', - as_of='Bexar', - remove_in='D') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_known_future_release(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - in_favor_of='different_stuff()') - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='do_outdated_stuff()', - in_favor_of='different_stuff()', - as_of='Grizzly', - remove_in='Icehouse') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_without_replacement(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY) - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='do_outdated_stuff()', - as_of='Grizzly', - remove_in='Icehouse') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_custom_what(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - what='v2.0 API', - in_favor_of='v3 API') - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='v2.0 API', - in_favor_of='v3 API', - as_of='Grizzly', - remove_in='Icehouse') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_removed_next_release(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - remove_in=1) - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='do_outdated_stuff()', - as_of='Grizzly', - remove_in='Havana') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_removed_plus_3(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - remove_in=+3) - def do_outdated_stuff(): - return - - do_outdated_stuff() - - self.assert_deprecated(mock_reporter, - what='do_outdated_stuff()', - as_of='Grizzly', - remove_in='Juno') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_removed_zero(self, mock_reporter): - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - remove_in=0) - def do_outdated_stuff(): - return - - do_outdated_stuff() - self.assert_deprecated(mock_reporter, - no_removal=True, - what='do_outdated_stuff()', - as_of='Grizzly', - remove_in='Grizzly') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_removed_none(self, mock_reporter): - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - remove_in=None) - def do_outdated_stuff(): - return - - do_outdated_stuff() - self.assert_deprecated(mock_reporter, - no_removal=True, - what='do_outdated_stuff()', - as_of='Grizzly', - remove_in='Grizzly') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_with_removed_zero_and_alternative(self, mock_reporter): - @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, - in_favor_of='different_stuff()', - remove_in=0) - def do_outdated_stuff(): - return - - do_outdated_stuff() - self.assert_deprecated(mock_reporter, - no_removal=True, - what='do_outdated_stuff()', - as_of='Grizzly', - in_favor_of='different_stuff()', - remove_in='Grizzly') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_class_without_init(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.JUNO, - remove_in=+1) - class OutdatedClass(object): - pass - obj = OutdatedClass() - - self.assertIsInstance(obj, OutdatedClass) - self.assert_deprecated(mock_reporter, - what='OutdatedClass()', - as_of='Juno', - remove_in='Kilo') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_class_with_init(self, mock_reporter): - mock_arguments = mock.MagicMock() - args = (1, 5, 7) - kwargs = {'first': 10, 'second': 20} - - @versionutils.deprecated(as_of=versionutils.deprecated.JUNO, - remove_in=+1) - class OutdatedClass(object): - def __init__(self, *args, **kwargs): - """It is __init__ method.""" - mock_arguments.args = args - mock_arguments.kwargs = kwargs - super(OutdatedClass, self).__init__() - obj = OutdatedClass(*args, **kwargs) - - self.assertIsInstance(obj, OutdatedClass) - self.assertEqual('__init__', obj.__init__.__name__) - self.assertEqual('It is __init__ method.', obj.__init__.__doc__) - self.assertEqual(args, mock_arguments.args) - self.assertEqual(kwargs, mock_arguments.kwargs) - self.assert_deprecated(mock_reporter, - what='OutdatedClass()', - as_of='Juno', - remove_in='Kilo') - - @unittest2.skipIf( - six.PY3, - 'Deprecated exception detection does not work for Python 3') - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_exception(self, mock_log): - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE, - remove_in=+1) - class OldException(Exception): - pass - - class NewException(OldException): - pass - - try: - raise NewException() - except OldException: - pass - - self.assert_deprecated(mock_log, what='OldException()', - as_of='Icehouse', remove_in='Juno') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_exception_old(self, mock_log): - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE, - remove_in=+1) - class OldException(Exception): - pass - - try: - raise OldException() - except OldException: - pass - - self.assert_deprecated(mock_log, what='OldException()', - as_of='Icehouse', remove_in='Juno') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_exception_new(self, mock_log): - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE, - remove_in=+1) - class OldException(Exception): - pass - - class NewException(OldException): - pass - - try: - raise NewException() - except NewException: - pass - - mock_log.assert_not_called() - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_exception_unrelated(self, mock_log): - @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE, - remove_in=+1) - class OldException(Exception): - pass - - class UnrelatedException(Exception): - pass - - try: - raise UnrelatedException() - except UnrelatedException: - pass - - mock_log.assert_not_called() - - @mock.patch.object(versionutils.CONF, 'register_opts') - def test_register_options(self, mock_register_opts): - # Calling register_options registers the config options. - - versionutils.register_options() - - mock_register_opts.assert_called_once_with( - versionutils.deprecated_opts) - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_mitaka_plus_two(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.MITAKA, - remove_in=+2) - class OutdatedClass(object): - pass - obj = OutdatedClass() - - self.assertIsInstance(obj, OutdatedClass) - self.assert_deprecated(mock_reporter, - what='OutdatedClass()', - as_of='Mitaka', - remove_in='Ocata') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_newton_plus_two(self, mock_reporter): - - @versionutils.deprecated(as_of=versionutils.deprecated.NEWTON, - remove_in=+2) - class OutdatedClass(object): - pass - obj = OutdatedClass() - - self.assertIsInstance(obj, OutdatedClass) - self.assert_deprecated(mock_reporter, - what='OutdatedClass()', - as_of='Newton', - remove_in='P') - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_deprecated_message(self, mock_reporter): - - versionutils.deprecation_warning('outdated_stuff', - as_of=versionutils.deprecated.KILO, - in_favor_of='different_stuff', - remove_in=+2) - - self.assert_deprecated(mock_reporter, - what='outdated_stuff', - in_favor_of='different_stuff', - as_of='Kilo', - remove_in='Mitaka') diff --git a/oslo_log/version.py b/oslo_log/version.py deleted file mode 100644 index 7678b98..0000000 --- a/oslo_log/version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import pbr.version - -version_info = pbr.version.VersionInfo('oslo_log') diff --git a/oslo_log/versionutils.py b/oslo_log/versionutils.py deleted file mode 100644 index bc1e17b..0000000 --- a/oslo_log/versionutils.py +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Helpers for comparing version strings. -""" - -import functools -import inspect -import logging - -from oslo_config import cfg -import six - -from oslo_log._i18n import _ - - -LOG = logging.getLogger(__name__) -CONF = cfg.CONF -_DEPRECATED_EXCEPTIONS = set() - - -deprecated_opts = [ - cfg.BoolOpt('fatal_deprecations', - default=False, - help='Enables or disables fatal status of deprecations.'), -] - - -_deprecated_msg_with_alternative = _( - '%(what)s is deprecated as of %(as_of)s in favor of ' - '%(in_favor_of)s and may be removed in %(remove_in)s.') - -_deprecated_msg_no_alternative = _( - '%(what)s is deprecated as of %(as_of)s and may be ' - 'removed in %(remove_in)s. It will not be superseded.') - -_deprecated_msg_with_alternative_no_removal = _( - '%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s.') - -_deprecated_msg_with_no_alternative_no_removal = _( - '%(what)s is deprecated as of %(as_of)s. It will not be superseded.') - - -_RELEASES = { - # NOTE(morganfainberg): Bexar is used for unit test purposes, it is - # expected we maintain a gap between Bexar and Folsom in this list. - 'B': 'Bexar', - 'F': 'Folsom', - 'G': 'Grizzly', - 'H': 'Havana', - 'I': 'Icehouse', - 'J': 'Juno', - 'K': 'Kilo', - 'L': 'Liberty', - 'M': 'Mitaka', - 'N': 'Newton', - 'O': 'Ocata', -} - - -def register_options(): - """Register configuration options used by this library. - - .. note: This is optional since the options are also registered - automatically when the functions in this module are used. - - """ - CONF.register_opts(deprecated_opts) - - -class deprecated(object): - """A decorator to mark callables as deprecated. - - This decorator logs a deprecation message when the callable it decorates is - used. The message will include the release where the callable was - deprecated, the release where it may be removed and possibly an optional - replacement. It also logs a message when a deprecated exception is being - caught in a try-except block, but not when subclasses of that exception - are being caught. - - Examples: - - 1. Specifying the required deprecated release - - >>> @deprecated(as_of=deprecated.ICEHOUSE) - ... def a(): pass - - 2. Specifying a replacement: - - >>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()') - ... def b(): pass - - 3. Specifying the release where the functionality may be removed: - - >>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=+1) - ... def c(): pass - - 4. Specifying the deprecated functionality will not be removed: - - >>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=None) - ... def d(): pass - - 5. Specifying a replacement, deprecated functionality will not be removed: - - >>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()', - ... remove_in=None) - ... def e(): pass - - .. warning:: - - The hook used to detect when a deprecated exception is being - *caught* does not work under Python 3. Deprecated exceptions - are still logged if they are thrown. - - """ - - # NOTE(morganfainberg): Bexar is used for unit test purposes, it is - # expected we maintain a gap between Bexar and Folsom in this list. - BEXAR = 'B' - FOLSOM = 'F' - GRIZZLY = 'G' - HAVANA = 'H' - ICEHOUSE = 'I' - JUNO = 'J' - KILO = 'K' - LIBERTY = 'L' - MITAKA = 'M' - NEWTON = 'N' - OCATA = 'O' - - def __init__(self, as_of, in_favor_of=None, remove_in=2, what=None): - """Initialize decorator - - :param as_of: the release deprecating the callable. Constants - are define in this class for convenience. - :param in_favor_of: the replacement for the callable (optional) - :param remove_in: an integer specifying how many releases to wait - before removing (default: 2) - :param what: name of the thing being deprecated (default: the - callable's name) - - """ - self.as_of = as_of - self.in_favor_of = in_favor_of - self.remove_in = remove_in - self.what = what - - def __call__(self, func_or_cls): - report_deprecated = functools.partial( - deprecation_warning, - what=self.what or func_or_cls.__name__ + '()', - as_of=self.as_of, - in_favor_of=self.in_favor_of, - remove_in=self.remove_in) - - if inspect.isfunction(func_or_cls): - - @six.wraps(func_or_cls) - def wrapped(*args, **kwargs): - report_deprecated() - return func_or_cls(*args, **kwargs) - return wrapped - elif inspect.isclass(func_or_cls): - orig_init = func_or_cls.__init__ - - # TODO(tsufiev): change `functools` module to `six` as - # soon as six 1.7.4 (with fix for passing `assigned` - # argument to underlying `functools.wraps`) is released - # and added to the oslo-incubator requrements - @functools.wraps(orig_init, assigned=('__name__', '__doc__')) - def new_init(self, *args, **kwargs): - if self.__class__ in _DEPRECATED_EXCEPTIONS: - report_deprecated() - orig_init(self, *args, **kwargs) - func_or_cls.__init__ = new_init - _DEPRECATED_EXCEPTIONS.add(func_or_cls) - - if issubclass(func_or_cls, Exception): - # NOTE(dhellmann): The subclasscheck is called, - # sometimes, to test whether a class matches the type - # being caught in an exception. This lets us warn - # folks that they are trying to catch an exception - # that has been deprecated. However, under Python 3 - # the test for whether one class is a subclass of - # another has been optimized so that the abstract - # check is only invoked in some cases. (See - # PyObject_IsSubclass in cpython/Objects/abstract.c - # for the short-cut.) - class ExceptionMeta(type): - def __subclasscheck__(self, subclass): - if self in _DEPRECATED_EXCEPTIONS: - report_deprecated() - return super(ExceptionMeta, - self).__subclasscheck__(subclass) - func_or_cls = six.add_metaclass(ExceptionMeta)(func_or_cls) - _DEPRECATED_EXCEPTIONS.add(func_or_cls) - - return func_or_cls - else: - raise TypeError('deprecated can be used only with functions or ' - 'classes') - - -def _get_safe_to_remove_release(release, remove_in): - # TODO(dstanek): this method will have to be reimplemented once - # when we get to the X release because once we get to the Y - # release, what is Y+2? - if remove_in is None: - remove_in = 0 - new_release = chr(ord(release) + remove_in) - if new_release in _RELEASES: - return _RELEASES[new_release] - else: - return new_release - - -def deprecation_warning(what, as_of, in_favor_of=None, - remove_in=2, logger=LOG): - """Warn about the deprecation of a feature. - - :param what: name of the thing being deprecated. - :param as_of: the release deprecating the callable. - :param in_favor_of: the replacement for the callable (optional) - :param remove_in: an integer specifying how many releases to wait - before removing (default: 2) - :param logger: the logging object to use for reporting (optional). - """ - details = dict(what=what, - as_of=_RELEASES[as_of], - remove_in=_get_safe_to_remove_release(as_of, remove_in)) - - if in_favor_of: - details['in_favor_of'] = in_favor_of - if remove_in is not None and remove_in > 0: - msg = _deprecated_msg_with_alternative - else: - # There are no plans to remove this function, but it is - # now deprecated. - msg = _deprecated_msg_with_alternative_no_removal - else: - if remove_in is not None and remove_in > 0: - msg = _deprecated_msg_no_alternative - else: - # There are no plans to remove this function, but it is - # now deprecated. - msg = _deprecated_msg_with_no_alternative_no_removal - - report_deprecated_feature(logger, msg, details) - - -# Track the messages we have sent already. See -# report_deprecated_feature(). -_deprecated_messages_sent = {} - - -def report_deprecated_feature(logger, msg, *args, **kwargs): - """Call this function when a deprecated feature is used. - - If the system is configured for fatal deprecations then the message - is logged at the 'critical' level and :class:`DeprecatedConfig` will - be raised. - - Otherwise, the message will be logged (once) at the 'warn' level. - - :raises: :class:`DeprecatedConfig` if the system is configured for - fatal deprecations. - """ - stdmsg = _("Deprecated: %s") % msg - register_options() - if CONF.fatal_deprecations: - logger.critical(stdmsg, *args, **kwargs) - raise DeprecatedConfig(msg=stdmsg) - - # Using a list because a tuple with dict can't be stored in a set. - sent_args = _deprecated_messages_sent.setdefault(msg, list()) - - if args in sent_args: - # Already logged this message, so don't log it again. - return - - sent_args.append(args) - logger.warning(stdmsg, *args, **kwargs) - - -class DeprecatedConfig(Exception): - message = _("Fatal call to deprecated config: %(msg)s") - - def __init__(self, msg): - super(Exception, self).__init__(self.message % dict(msg=msg)) diff --git a/oslo_log/watchers.py b/oslo_log/watchers.py deleted file mode 100644 index d970f9d..0000000 --- a/oslo_log/watchers.py +++ /dev/null @@ -1,111 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import errno -import logging -import logging.config -import logging.handlers -import os -import pyinotify -import stat -import time -try: - import syslog -except ImportError: - syslog = None - -"""Linux specific pyinotify based logging handlers""" - - -class _FileKeeper(pyinotify.ProcessEvent): - def my_init(self, watched_handler, watched_file): - self._watched_handler = watched_handler - self._watched_file = watched_file - - def process_default(self, event): - if event.name == self._watched_file: - self._watched_handler.reopen_file() - - -class _EventletThreadedNotifier(pyinotify.ThreadedNotifier): - - def loop(self): - """Eventlet friendly ThreadedNotifier - - EventletFriendlyThreadedNotifier contains additional time.sleep() - call insude loop to allow switching to other thread when eventlet - is used. - It can be used with eventlet and native threads as well. - """ - - while not self._stop_event.is_set(): - self.process_events() - time.sleep(0) - ref_time = time.time() - if self.check_events(): - self._sleep(ref_time) - self.read_events() - - -class FastWatchedFileHandler(logging.handlers.WatchedFileHandler, object): - """Frequency of reading events. - - Watching thread sleeps max(0, READ_FREQ - (TIMEOUT / 1000)) seconds. - """ - READ_FREQ = 5 - - """Poll timeout in milliseconds. - - See https://docs.python.org/2/library/select.html#select.poll.poll""" - TIMEOUT = 5 - - def __init__(self, logpath, *args, **kwargs): - self._log_file = os.path.basename(logpath) - self._log_dir = os.path.dirname(logpath) - super(FastWatchedFileHandler, self).__init__(logpath, *args, **kwargs) - self._watch_file() - - def _watch_file(self): - mask = pyinotify.IN_MOVED_FROM | pyinotify.IN_DELETE - watch_manager = pyinotify.WatchManager() - handler = _FileKeeper(watched_handler=self, - watched_file=self._log_file) - notifier = _EventletThreadedNotifier( - watch_manager, - default_proc_fun=handler, - read_freq=FastWatchedFileHandler.READ_FREQ, - timeout=FastWatchedFileHandler.TIMEOUT) - notifier.daemon = True - watch_manager.add_watch(self._log_dir, mask) - notifier.start() - - def reopen_file(self): - try: - # stat the file by path, checking for existence - sres = os.stat(self.baseFilename) - except OSError as err: - if err.errno == errno.ENOENT: - sres = None - else: - raise - # compare file system stat with that of our stream file handle - if (not sres or - sres[stat.ST_DEV] != self.dev or - sres[stat.ST_INO] != self.ino): - if self.stream is not None: - # we have an open file handle, clean it up - self.stream.flush() - self.stream.close() - self.stream = None - # open a new file handle and get new stat info from that fd - self.stream = self._open() - self._statstream() diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/notes/add-reno-e4fedb11ece56f1e.yaml b/releasenotes/notes/add-reno-e4fedb11ece56f1e.yaml deleted file mode 100644 index 54d5cf8..0000000 --- a/releasenotes/notes/add-reno-e4fedb11ece56f1e.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -other: - - Switch to reno for managing release notes. diff --git a/releasenotes/notes/info-logging-7b7be9fc7a95aebc.yaml b/releasenotes/notes/info-logging-7b7be9fc7a95aebc.yaml deleted file mode 100644 index 935d35f..0000000 --- a/releasenotes/notes/info-logging-7b7be9fc7a95aebc.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - When removing the "verbose" option, the default logging level was set to - "WARNING" by mistake. Fixed it back to "INFO". diff --git a/releasenotes/notes/reload_log_config-743817192b1172b6.yaml b/releasenotes/notes/reload_log_config-743817192b1172b6.yaml deleted file mode 100644 index f21f727..0000000 --- a/releasenotes/notes/reload_log_config-743817192b1172b6.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - The log_config_append configuration option is now mutable and the logging - settings it controls are reconfigured when the configuration file is reread. - This can be used to, for example, change logger or handler levels. diff --git a/releasenotes/notes/remove-log-format-b4b949701cee3315.yaml b/releasenotes/notes/remove-log-format-b4b949701cee3315.yaml deleted file mode 100644 index 873b0c2..0000000 --- a/releasenotes/notes/remove-log-format-b4b949701cee3315.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -upgrade: -- The deprecated log_format configuration option has been removed. diff --git a/releasenotes/notes/remove-syslog-rfc-format-7a06772c0bb48e9b.yaml b/releasenotes/notes/remove-syslog-rfc-format-7a06772c0bb48e9b.yaml deleted file mode 100644 index 31563c4..0000000 --- a/releasenotes/notes/remove-syslog-rfc-format-7a06772c0bb48e9b.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: -- The deprecated use_syslog_rfc_format configuration option has been - removed. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 20f2064..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,274 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# oslo.log Release Notes documentation build configuration file, created by -# sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'oslosphinx', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.log Release Notes' -copyright = u'2016, oslo.log Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -from oslo_log.version import version_info as oslo_log_version -# The full version, including alpha/beta/rc tags. -release = oslo_log_version.version_string_with_vcs() -# The short X.Y version. -version = oslo_log_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'oslo.logReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'oslo.logReleaseNotes.tex', - u'oslo.log Release Notes Documentation', - u'oslo.log Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'oslo.logreleasenotes', u'oslo.log Release Notes Documentation', - [u'oslo.log Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'oslo.logReleaseNotes', u'oslo.log Release Notes Documentation', - u'oslo.log Developers', 'oslo.logReleaseNotes', - 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 64907aa..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -======================== - oslo.log Release Notes -======================== - - .. toctree:: - :maxdepth: 1 - - unreleased - liberty - mitaka diff --git a/releasenotes/source/liberty.rst b/releasenotes/source/liberty.rst deleted file mode 100644 index 3162ccb..0000000 --- a/releasenotes/source/liberty.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================== -Liberty Series Release Notes -============================== - -.. release-notes:: - :branch: origin/stable/liberty diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po deleted file mode 100644 index bc00d6d..0000000 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,63 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.log Release Notes 3.11.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-07-01 03:32+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-28 05:55+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "3.1.0" -msgstr "3.1.0" - -msgid "3.2.0" -msgstr "3.2.0" - -msgid "3.8.0" -msgstr "3.8.0" - -msgid "Bug Fixes" -msgstr "Bug Fixes" - -msgid "Liberty Series Release Notes" -msgstr "Liberty Series Release Notes" - -msgid "Mitaka Series Release Notes" -msgstr "Mitaka Series Release Notes" - -msgid "Other Notes" -msgstr "Other Notes" - -msgid "Switch to reno for managing release notes." -msgstr "Switch to reno for managing release notes." - -msgid "The deprecated log_format configuration option has been removed." -msgstr "The deprecated log_format configuration option has been removed." - -msgid "" -"The deprecated use_syslog_rfc_format configuration option has been removed." -msgstr "" -"The deprecated use_syslog_rfc_format configuration option has been removed." - -msgid "Unreleased Release Notes" -msgstr "Unreleased Release Notes" - -msgid "Upgrade Notes" -msgstr "Upgrade Notes" - -msgid "" -"When removing the \"verbose\" option, the default logging level was set to " -"\"WARNING\" by mistake. Fixed it back to \"INFO\"." -msgstr "" -"When removing the \"verbose\" option, the default logging level was set to " -"\"WARNING\" by mistake. Fixed it back to \"INFO\"." - -msgid "oslo.log Release Notes" -msgstr "oslo.log Release Notes" diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst deleted file mode 100644 index e545609..0000000 --- a/releasenotes/source/mitaka.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Mitaka Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/mitaka diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index 5860a46..0000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -========================== - Unreleased Release Notes -========================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e6a740d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr>=1.6 # Apache-2.0 -six>=1.9.0 # MIT -oslo.config>=3.14.0 # Apache-2.0 -oslo.context>=2.4.0 # Apache-2.0 -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.utils>=3.16.0 # Apache-2.0 -oslo.serialization>=1.10.0 # Apache-2.0 -debtcollector>=1.2.0 # Apache-2.0 -pyinotify>=0.9.6;sys_platform!='win32' and sys_platform!='darwin' and sys_platform!='sunos5' # MIT -python-dateutil>=2.4.2 # BSD diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index fa281bd..0000000 --- a/setup.cfg +++ /dev/null @@ -1,60 +0,0 @@ -[metadata] -name = oslo.log -summary = oslo.log library -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - Programming Language :: Python :: 3.5 - -[files] -packages = - oslo_log - -[extras] -fixtures = - fixtures>=3.0.0 # Apache-2.0/BSD - -[pbr] -warnerrors = true - -[entry_points] -oslo.config.opts = - oslo.log = oslo_log._options:list_opts - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo_log/locale -domain = oslo_log - -[update_catalog] -domain = oslo_log -output_dir = oslo_log/locale -input_file = oslo_log/locale/oslo_log.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = oslo_log/locale/oslo_log.pot - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 673f993..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking<0.11,>=0.10.0 - -python-subunit>=0.0.18 # Apache-2.0/BSD -testrepository>=0.0.18 # Apache-2.0/BSD -testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -mock>=2.0 # BSD -oslotest>=1.10.0 # Apache-2.0 - -# when we can require tox>= 1.4, this can go into tox.ini: -# [testenv:cover] -# deps = {[testenv]deps} coverage -coverage>=3.6 # Apache-2.0 - -# this is required for the docs build jobs -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 -reno>=1.8.0 # Apache2 - -# Bandit security code scanner -bandit>=1.0.1 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index f5c8e30..0000000 --- a/tox.ini +++ /dev/null @@ -1,52 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py35,py34,py27,pep8 - -[testenv] -deps = -r{toxinidir}/test-requirements.txt - -e.[fixtures] -commands = - python setup.py test --coverage --coverage-package-name=oslo_log --slowest --testr-args='{posargs}' - coverage report --show-missing - -[testenv:pep8] -commands = - flake8 - # Run security linter - bandit -r oslo_log -x tests -n5 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = - python setup.py test --coverage --coverage-package-name=oslo_log --testr-args='{posargs}' - coverage report --show-missing - -[testenv:bandit] -commands = bandit -r oslo_log -x tests -n5 - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125,H405 -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,__init__.py - -[hacking] -import_exceptions = oslo_log._i18n - -[testenv:pip-missing-reqs] -# do not install test-requirements as that will pollute the virtualenv for -# determining missing packages -# this also means that pip-missing-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_missing_reqs -commands = pip-missing-reqs -d --ignore-module=oslo_log* --ignore-file=oslo_log/tests/* --ignore-file=tests/ oslo_log - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html -