From 5ef6f8015d2fb2b24c45f279ed0442b31b484e87 Mon Sep 17 00:00:00 2001 From: Andreas Jaeger Date: Mon, 17 Apr 2017 19:37:22 +0200 Subject: [PATCH] Retire repo This repo was created by accident, use deb-python-oslo.log instead. Needed-By: I1ac1a06931c8b6dd7c2e73620a0302c29e605f03 Change-Id: I81894aea69b9d09b0977039623c26781093a397a --- .coveragerc | 7 - .gitignore | 55 - .gitreview | 4 - .mailmap | 3 - .testr.conf | 7 - CONTRIBUTING.rst | 16 - HACKING.rst | 4 - LICENSE | 175 -- README.rst | 21 - README.txt | 13 + babel.cfg | 1 - doc/source/api/fixtures.rst | 9 - doc/source/api/formatters.rst | 8 - doc/source/api/handlers.rst | 8 - doc/source/api/helpers.rst | 8 - doc/source/api/log.rst | 12 - doc/source/api/versionutils.rst | 6 - doc/source/api/watchers.rst | 12 - doc/source/conf.py | 77 - doc/source/configfiles/example_nova.rst | 84 - doc/source/configfiles/index.rst | 47 - doc/source/configfiles/nova_sample.conf | 84 - doc/source/contributing.rst | 5 - doc/source/examples.rst | 60 - doc/source/examples/_i18n.py | 49 - doc/source/examples/oslo_logging.py | 30 - doc/source/examples/python_logging.py | 26 - doc/source/examples/usage.py | 86 - doc/source/examples/usage_context.py | 85 - doc/source/examples/usage_helper.py | 103 -- doc/source/examples/usage_i18n.py | 87 - doc/source/history.rst | 7 - doc/source/index.rst | 36 - doc/source/installation.rst | 12 - doc/source/migration.rst | 119 -- doc/source/opts.rst | 9 - doc/source/usage.rst | 167 -- oslo_log/__init__.py | 0 oslo_log/_i18n.py | 37 - oslo_log/_options.py | 171 -- oslo_log/fixture/__init__.py | 16 - oslo_log/fixture/logging_error.py | 37 - oslo_log/fixture/setlevel.py | 49 - oslo_log/formatters.py | 335 ---- oslo_log/handlers.py | 76 - oslo_log/helpers.py | 49 - oslo_log/locale/de/LC_MESSAGES/oslo_log.po | 60 - oslo_log/locale/en_GB/LC_MESSAGES/oslo_log.po | 55 - oslo_log/locale/es/LC_MESSAGES/oslo_log.po | 64 - oslo_log/locale/ja/LC_MESSAGES/oslo_log.po | 57 - oslo_log/log.py | 455 ----- oslo_log/loggers.py | 29 - oslo_log/tests/__init__.py | 0 oslo_log/tests/unit/__init__.py | 13 - oslo_log/tests/unit/fixture/__init__.py | 13 - .../tests/unit/fixture/test_logging_error.py | 31 - oslo_log/tests/unit/fixture/test_setlevel.py | 36 - oslo_log/tests/unit/test_formatters.py | 85 - oslo_log/tests/unit/test_helpers.py | 62 - oslo_log/tests/unit/test_log.py | 1519 ----------------- oslo_log/tests/unit/test_versionutils.py | 371 ---- oslo_log/version.py | 18 - oslo_log/versionutils.py | 302 ---- oslo_log/watchers.py | 111 -- releasenotes/notes/.placeholder | 0 .../notes/add-reno-e4fedb11ece56f1e.yaml | 3 - .../notes/info-logging-7b7be9fc7a95aebc.yaml | 4 - .../reload_log_config-743817192b1172b6.yaml | 5 - .../remove-log-format-b4b949701cee3315.yaml | 3 - ...ve-syslog-rfc-format-7a06772c0bb48e9b.yaml | 4 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 274 --- releasenotes/source/index.rst | 10 - releasenotes/source/liberty.rst | 6 - .../locale/en_GB/LC_MESSAGES/releasenotes.po | 63 - releasenotes/source/mitaka.rst | 6 - releasenotes/source/unreleased.rst | 5 - requirements.txt | 14 - setup.cfg | 60 - setup.py | 29 - test-requirements.txt | 25 - tox.ini | 52 - 83 files changed, 13 insertions(+), 6143 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 README.rst create mode 100644 README.txt delete mode 100644 babel.cfg delete mode 100644 doc/source/api/fixtures.rst delete mode 100644 doc/source/api/formatters.rst delete mode 100644 doc/source/api/handlers.rst delete mode 100644 doc/source/api/helpers.rst delete mode 100644 doc/source/api/log.rst delete mode 100644 doc/source/api/versionutils.rst delete mode 100644 doc/source/api/watchers.rst delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/configfiles/example_nova.rst delete mode 100644 doc/source/configfiles/index.rst delete mode 100644 doc/source/configfiles/nova_sample.conf delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/examples.rst delete mode 100644 doc/source/examples/_i18n.py delete mode 100644 doc/source/examples/oslo_logging.py delete mode 100644 doc/source/examples/python_logging.py delete mode 100644 doc/source/examples/usage.py delete mode 100644 doc/source/examples/usage_context.py delete mode 100644 doc/source/examples/usage_helper.py delete mode 100644 doc/source/examples/usage_i18n.py delete mode 100644 doc/source/history.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/migration.rst delete mode 100644 doc/source/opts.rst delete mode 100644 doc/source/usage.rst delete mode 100644 oslo_log/__init__.py delete mode 100644 oslo_log/_i18n.py delete mode 100644 oslo_log/_options.py delete mode 100644 oslo_log/fixture/__init__.py delete mode 100644 oslo_log/fixture/logging_error.py delete mode 100644 oslo_log/fixture/setlevel.py delete mode 100644 oslo_log/formatters.py delete mode 100644 oslo_log/handlers.py delete mode 100644 oslo_log/helpers.py delete mode 100644 oslo_log/locale/de/LC_MESSAGES/oslo_log.po delete mode 100644 oslo_log/locale/en_GB/LC_MESSAGES/oslo_log.po delete mode 100644 oslo_log/locale/es/LC_MESSAGES/oslo_log.po delete mode 100644 oslo_log/locale/ja/LC_MESSAGES/oslo_log.po delete mode 100644 oslo_log/log.py delete mode 100644 oslo_log/loggers.py delete mode 100644 oslo_log/tests/__init__.py delete mode 100644 oslo_log/tests/unit/__init__.py delete mode 100644 oslo_log/tests/unit/fixture/__init__.py delete mode 100644 oslo_log/tests/unit/fixture/test_logging_error.py delete mode 100644 oslo_log/tests/unit/fixture/test_setlevel.py delete mode 100644 oslo_log/tests/unit/test_formatters.py delete mode 100644 oslo_log/tests/unit/test_helpers.py delete mode 100644 oslo_log/tests/unit/test_log.py delete mode 100644 oslo_log/tests/unit/test_versionutils.py delete mode 100644 oslo_log/version.py delete mode 100644 oslo_log/versionutils.py delete mode 100644 oslo_log/watchers.py delete mode 100644 releasenotes/notes/.placeholder delete mode 100644 releasenotes/notes/add-reno-e4fedb11ece56f1e.yaml delete mode 100644 releasenotes/notes/info-logging-7b7be9fc7a95aebc.yaml delete mode 100644 releasenotes/notes/reload_log_config-743817192b1172b6.yaml delete mode 100644 releasenotes/notes/remove-log-format-b4b949701cee3315.yaml delete mode 100644 releasenotes/notes/remove-syslog-rfc-format-7a06772c0bb48e9b.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/liberty.rst delete mode 100644 releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/mitaka.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini 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 -