Retire Packaging Deb project repos

This commit is part of a series to retire the Packaging Deb
project. Step 2 is to remove all content from the project
repos, replacing it with a README notification where to find
ongoing work, and how to recover the repo if needed at some
future point (as in
https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project).

Change-Id: I9fec1fbe4198abd8eba934b3162cee1aea128a1d
This commit is contained in:
Tony Breeds 2017-09-12 16:06:09 -06:00
parent 8bb44cdedd
commit 0d57be62d4
101 changed files with 14 additions and 7748 deletions

View File

@ -1,7 +0,0 @@
[run]
branch = True
source = oslo_log
omit = oslo_log/tests/*
[report]
ignore_errors = True

55
.gitignore vendored
View File

@ -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

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/oslo.log.git

View File

@ -1,3 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>

View File

@ -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

View File

@ -1,16 +0,0 @@
If you would like to contribute to the development of OpenStack,
you must follow the steps in this page:
https://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:
https://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

View File

@ -1,4 +0,0 @@
Style Commandments
==================
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

175
LICENSE
View File

@ -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.

14
README Normal file
View File

@ -0,0 +1,14 @@
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".
For ongoing work on maintaining OpenStack packages in the Debian
distribution, please see the Debian OpenStack packaging team at
https://wiki.debian.org/OpenStack/.
For any further questions, please email
openstack-dev@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1,30 +0,0 @@
========================
Team and repository tags
========================
.. image:: https://governance.openstack.org/badges/oslo.log.svg
:target: https://governance.openstack.org/reference/tags/index.html
.. Change things from this point on
================================
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: https://docs.openstack.org/oslo.log/latest
* Source: https://git.openstack.org/cgit/openstack/oslo.log
* Bugs: https://bugs.launchpad.net/oslo.log

View File

@ -1 +0,0 @@
[python: **.py]

View File

@ -1,47 +0,0 @@
==============================
Advanced Configuration Files
==============================
The oslo.config options described in :ref:`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

View File

@ -1,102 +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.
A Fluentd formatter is also shown.
.. 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: 85-86
The ``stdout`` and ``syslog`` handlers are defined, but not used.
The ``fluent`` handler is useful to send logs to ``fluentd``.
It is a part of fluent-logger-python and you can install it as following.
::
$ pip install fluent-logger
This handler is configured to use ``fluent`` formatter.
.. literalinclude:: nova_sample.conf
:language: ini
:lines: 75-78
.. literalinclude:: nova_sample.conf
:language: ini
:lines: 91-92

View File

@ -1,9 +0,0 @@
==============================================
Administering Applications that use oslo.log
==============================================
.. toctree::
:maxdepth: 2
advanced_config
journal

View File

@ -1,158 +0,0 @@
=========================
Systemd Journal Support
=========================
One of the newer features in oslo.log is the ability to integrate with
the systemd journal service (journald) natively on newer Linux
systems. When using native journald support, additional metadata will
be logged on each log message in addition to the message itself, which
can later be used to do some interesting searching through your logs.
Enabling
========
In order to enable the support you must have Python bindings for
systemd installed. On Red Hat based systems, run::
yum install systemd-python
On Ubuntu/Debian based systems, run::
apt install python-systemd
If there is no native package for your distribution, or you are
running in a virtualenv, you can install with pip.::
pip install systemd-python
.. note::
There are also many non official systemd python modules on pypi,
with confusingly close names. Make sure you install `systemd-python
<https://pypi.python.org/pypi/systemd-python>`_.
After the package is installed, you must enable journald support
manually in all services that will be using it. Add the following to
the config files for all services:
.. code-block:: ini
[DEFAULT]
use_journal = True
In all relevant config files.
Extra Metadata
==============
Journald supports the concept of adding structured metadata in
addition to the log message in question. This makes it much easier to
take the output of journald and push it into other logging systems
like Elastic Search, without needing to regex guess relevant data. It
also allows you to search the journal by these fields using
``journalctl``.
We use this facility to add our own structured information, if it is
known at the time of logging the message.
CODE_FILE=, CODE_LINE=, CODE_FUNC=
The code location generating this message, if known. Contains the
source filename, the line number and the function name. (This is the
same as systemd uses)
THREAD_NAME=, PROCESS_NAME=
Information about the thread and process, if known. (This is the same
as systemd uses)
EXCEPTION_TEXT=, EXCEPTION_INFO=
Information about an exception, if an exception has been logged.
LOGGER_NAME=
The name of the python logger that emitted the log
message. Very often this is the module where the log message was
emitted from.
LOGGER_LEVEL=
The name of the python logging level, which allows seeing all
'ERROR' messages very easily without remembering how they are
translated to syslog priorities.
SYSLOG_IDENTIFIER=
The binary name identified for syslog compatibility. It will be the
basename of the process that emits the log messages
(e.g. ``nova-api``, ``neutron-l3-agent``)
PRIORITY=
The syslog priority (based on LOGGER_LEVEL), which allows syslog
style filtering of messages based on their priority (an
openstack.err log file for instance).
REQUEST_ID=
Most OpenStack services generate a unique ``request-id`` on every
REST API call, which is then passed between it's sub services as
that request is handled. For example, this can be very useful in
tracking the build of a nova server from the initial HTTP POST to
final VM create.
PROJECT_ID=, PROJECT_NAME=, USER_ID=, USER_NAME=
The keystone known user and project information about the
requestor. Both the id and name are provided for easier
searching. This can be used to understand when particular users or
projects are reporting issues in the environment.
Additional fields may be added over time. It is unlikely that fields
will be removed, but if so they will be deprecated for one release
cycle before that happens.
Using Journalctl
================
Because systemd is relatively new in the Linux ecosystem, it's worth
noting how one can effectively use journal control.
If you want to follow all the journal logs you would do so with::
journalctl -f
That's going to be nearly everything on your system, which you will
probably find overwhelming. You can limit this to a smaller number of
things using the ``SYSLOG_IDENTIFIER=``::
journalctl -f SYSLOG_IDENTIFIER=nova-compute SYSLOG_IDENTIFIER=neutron-l3-agent
Specifying a query parameter multiple times defaults to an ``OR``
operation, so that will show either nova-compute or neutron-l3-agent
logs.
You can also query by request id to see the entire flow of a REST
call::
journalctl REQUEST_ID=req-b1903300-77a8-401d-984c-8e7d17e4a15f
References
==========
- A complete list of the systemd journal fields is here, it is worth
making yourself familiar with them -
https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
- The complete journalctl manual is worth reading, especially the
``-o`` parameter, as default displayed time resolution is only in
seconds (even though systemd internally is tracking microsecs) -
https://www.freedesktop.org/software/systemd/man/journalctl.html
- The guide for using systemd in devstack provides additional examples
of effective journalctl queries -
http://git.openstack.org/cgit/openstack-dev/devstack/tree/SYSTEMD.rst

View File

@ -1,92 +0,0 @@
[loggers]
keys = root, nova
[handlers]
keys = stderr, stdout, watchedfile, syslog, fluent, null
[formatters]
keys = context, default, fluent
[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_fluent]
class = fluent.handler.FluentHandler
args = ('openstack.nova', 'localhost', 24224)
formatter = fluent
[handler_null]
class = logging.NullHandler
formatter = default
args = ()
[formatter_context]
class = oslo_log.formatters.ContextFormatter
[formatter_default]
format = %(message)s
[formatter_fluent]
class = oslo_log.formatters.FluentFormatter

View File

@ -1,84 +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',
'oslo_config.sphinxext',
'openstackdocstheme',
]
# openstackdocstheme options
repository_name = 'openstack/oslo.log'
bug_project = 'oslo.log'
bug_tag = ''
# Must set this variable to include year, month, day, hours, and minutes.
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# 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_static_path = ['static']
html_theme = 'openstackdocs'
# 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}

View File

@ -1,149 +0,0 @@
.. _opts:
=======================
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
Format Strings and Log Record Metadata
======================================
oslo.log builds on top of the Python standard library logging
module. The format string supports all of the built-in replacement
keys provided by that library, with some additions. Some of the more
useful keys are listed here. Refer to the `section on LogRecord
attributes
<https://docs.python.org/3.5/library/logging.html#logrecord-attributes>`__
in the library documentation for complete details about the built-in
values.
Basic Information
-----------------
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(message)s``
* The message passed from the application code.
Time Information
----------------
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(asctime)s``
* Human-readable time stamp of when the logging record was
created, formatted as '2003-07-08 16:49:45,896' (the numbers
after the comma are milliseconds).
- * ``%(isotime)s``
* Human-readable time stamp of when the logging record was
created, using `Python's isoformat()
<https://docs.python.org/3.5/library/datetime.html#datetime.datetime.isoformat>`__
function in ISO 8601 format (``YYYY-MM-DDTHH:MM:SS.mmmmmm`` or,
if the microseconds value is 0, ``YYYY-MM-DDTHH:MM:SS``).
Location Information
--------------------
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(pathname)s``
* Full name of the source file where the logging call was issued,
when it is available.
- * ``%(filename)s``
* Filename portion of ``pathname``.
- * ``%(lineno)d``
* Source line number where the logging call was issued, when it
is available.
- * ``%(module)s``
* The module name is derived from the filename.
- * ``%(name)s``
* The name of the logger used to log the call. For OpenStack
projects, this usually corresponds to the full module name
(i.e., ``nova.api`` or ``oslo_config.cfg``).
Severity Information
--------------------
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(levelname)s``
* Text logging level for the message (``DEBUG``, ``INFO``,
``WARNING``, ``ERROR``, ``CRITICAL``).
- * ``%(levelno)s``
* Numeric logging level for the message. DEBUG level messages
have a lower numerical value than INFO, which have a lower
value than WARNING, etc.
Error Handling Information
--------------------------
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(error_summary)s``
* The name of the exception being processed and any message
associated with it.
Identity Information
--------------------
*These keys are only available in OpenStack applications that also use
oslo.context.*
.. list-table::
:header-rows: 1
:widths: 25,75
- * Format key
* Description
- * ``%(user_identity)s``
* The pre-formatted identity information about the user. See the
``logging_user_identity_format`` configuration option.
- * ``%(user_name)s``
* The name of the authenticated user, if available.
- * ``%(user)s``
* The ID of the authenticated user, if available.
- * ``%(tenant_name)s``
* The name of the authenticated tenant, if available.
- * ``%(tenant)s``
* The ID of the authenticated tenant, if available.
- * ``%(user_domain)s``
* The ID of the authenticated user domain, if available.
- * ``%(project_domain)s``
* The ID of the authenticated project/tenant, if available.
- * ``%(request_id)s``
* The ID of the current request. This value can be used to tie
multiple log messages together as relating to the same
operation.
- * ``%(resource_uuid)s``
* The ID of the resource on which the current operation will have
effect. For example, the instance, network, volume, etc.
.. seealso::
* `Python logging library LogRecord attributes
<https://docs.python.org/3.5/library/logging.html#logrecord-attributes>`__

View File

@ -1,5 +0,0 @@
============
Contributing
============
.. include:: ../../../CONTRIBUTING.rst

View File

@ -1,25 +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
install/index
user/index
reference/index
configuration/index
admin/index
contributor/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -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]'

View File

@ -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

View File

@ -1,8 +0,0 @@
=====================
oslo_log.formatters
=====================
.. automodule:: oslo_log.formatters
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,8 +0,0 @@
=====================
oslo_log.handlers
=====================
.. automodule:: oslo_log.handlers
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,8 +0,0 @@
==================
oslo_log.helpers
==================
.. automodule:: oslo_log.helpers
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,8 +0,0 @@
========================
oslo.log API Reference
========================
.. toctree::
:glob:
*

View File

@ -1,12 +0,0 @@
==============
oslo_log.log
==============
.. automodule:: oslo_log.log
:members:
:undoc-members:
:show-inheritance:
.. seealso::
:ref:`using`

View File

@ -1,6 +0,0 @@
=======================
oslo_log.versionutils
=======================
.. automodule:: oslo_log.versionutils
:members:

View File

@ -1,12 +0,0 @@
==================
oslo_log.watchers
==================
.. automodule:: oslo_log.watchers
:members:
:undoc-members:
:show-inheritance:
.. seealso::
:ref:`using`

View File

@ -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 in the
`online git repository`_ of this project.
.. _online git repository: 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:

View File

@ -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)

View File

@ -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")

View File

@ -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")

View File

@ -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, oslo.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")

View File

@ -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, oslo.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")

View File

@ -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, oslo.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")

View File

@ -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, oslo.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"))

View File

@ -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

View File

@ -1,13 +0,0 @@
.. _using:
================
Using oslo.log
================
.. toctree::
:maxdepth: 2
usage
examples
migration
history

View File

@ -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.

View File

@ -1,167 +0,0 @@
=======
Usage
=======
.. _usage-app:
In an Application
=================
When using `Python's standard logging library`_ the following minimal setup
demonstrates 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 <example_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 <example_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 <example_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 <example_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 <example_usage.py>` provides a documented
example of Oslo Logging setup.
:ref:`examples/usage_helper.py <example_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 <example_usage_i18n.py>` provides a
documented example of Oslo Logging with Oslo i18n supported messages.
:ref:`examples/usage_context.py <example_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.

View File

View File

@ -1,27 +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

View File

@ -1,189 +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', '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.'),
]
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.BoolOpt('use-journal',
default=False,
help='Enable journald for logging. '
'If running in a systemd environment you may wish '
'to enable journal support. Doing so will use the '
'journal native protocol which includes structured '
'metadata in addition to log messages.'
+ _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=False,
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.'),
cfg.IntOpt('rate_limit_interval',
default=0,
help='Interval, number of seconds, of log rate limiting.'),
cfg.IntOpt('rate_limit_burst',
default=0,
help='Maximum number of logged messages per '
'rate_limit_interval.'),
cfg.StrOpt('rate_limit_except_level',
default='CRITICAL',
help='Log level name used by rate limiting: CRITICAL, ERROR, '
'INFO, WARNING, DEBUG or empty string. Logs with level '
'greater or equal to rate_limit_except_level are not '
'filtered. An empty string means that all levels are '
'filtered.'),
]
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))]

View File

@ -1,187 +0,0 @@
#!/usr/bin/env python
# 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 __future__ import print_function
import argparse
import collections
import functools
import sys
import time
from oslo_serialization import jsonutils
from oslo_utils import importutils
import six
from oslo_log import log
termcolor = importutils.try_import('termcolor')
_USE_COLOR = False
def main():
global _USE_COLOR
args = parse_args()
_USE_COLOR = args.color
formatter = functools.partial(
console_format,
args.prefix,
args.locator,
loggers=args.loggers,
levels=args.levels,
)
if args.lines:
# Read backward until we find all of our newline characters
# or reach the beginning of the file
args.file.seek(0, 2)
newlines = 0
pos = args.file.tell()
while newlines <= args.lines and pos > 0:
pos = pos - 1
args.file.seek(pos)
if args.file.read(1) == '\n':
newlines = newlines + 1
try:
for line in reformat_json(args.file, formatter, args.follow):
print(line)
except KeyboardInterrupt:
sys.exit(0)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("file",
nargs='?', default=sys.stdin,
type=argparse.FileType(),
help="JSON log file to read from (if not provided"
" standard input is used instead)")
parser.add_argument("--prefix",
default='%(asctime)s.%(msecs)03d'
' %(process)s %(levelname)s %(name)s',
help="Message prefixes")
parser.add_argument("--locator",
default='[%(funcname)s %(pathname)s:%(lineno)s]',
help="Locator to append to DEBUG records")
parser.add_argument("-c", "--color",
action='store_true', default=False,
help="Color log levels (requires `termcolor`)")
parser.add_argument("-f", "--follow",
action='store_true', default=False,
help="Continue parsing new data until"
" KeyboardInterrupt")
parser.add_argument("-n", "--lines",
required=False, type=int,
help="Last N number of records to view."
" (May show less than N records when used"
" in conjuction with --loggers or --levels)")
parser.add_argument("--loggers",
nargs='*', default=[],
help="only return results matching given logger(s)")
parser.add_argument("--levels",
nargs='*', default=[],
help="Only return lines matching given log level(s)")
args = parser.parse_args()
if args.color and not termcolor:
raise ImportError("Coloring requested but `termcolor` is not"
" importable")
return args
def colorise(key, text=None):
if text is None:
text = key
if not _USE_COLOR:
return text
colors = {
'exc': ('red', ['reverse', 'bold']),
'FATAL': ('red', ['reverse', 'bold']),
'ERROR': ('red', ['bold']),
'WARNING': ('yellow', ['bold']),
'WARN': ('yellow', ['bold']),
'INFO': ('white', ['bold']),
}
color, attrs = colors.get(key, ('', []))
if color:
return termcolor.colored(text, color=color, attrs=attrs)
return text
def warn(prefix, msg):
return "%s: %s" % (colorise('exc', prefix), msg)
def reformat_json(fh, formatter, follow=False):
# using readline allows interactive stdin to respond to every line
while True:
line = fh.readline()
if not line:
if follow:
time.sleep(0.1)
continue
else:
break
line = line.strip()
if not line:
continue
try:
record = jsonutils.loads(line)
except ValueError:
yield warn("Not JSON", line)
continue
for out_line in formatter(record):
yield out_line
def console_format(prefix, locator, record, loggers=[], levels=[]):
# Provide an empty string to format-specifiers the record is
# missing, instead of failing. Doesn't work for non-string
# specifiers.
record = collections.defaultdict(str, record)
# skip if the record doesn't match a logger we are looking at
if loggers:
name = record.get('name')
if not any(name.startswith(n) for n in loggers):
return
if levels:
if record.get('levelname') not in levels:
return
levelname = record.get('levelname')
if levelname:
record['levelname'] = colorise(levelname)
try:
prefix = prefix % record
except TypeError:
# Thrown when a non-string format-specifier can't be filled in.
# Dict comprehension cleans up the output
yield warn('Missing non-string placeholder in record',
{str(k): str(v) if isinstance(v, six.string_types) else v
for k, v in six.iteritems(record)})
return
locator = ''
if (record.get('levelno', 100) <= log.DEBUG or levelname == 'DEBUG'):
locator = locator % record
yield ' '.join(x for x in [prefix, record['message'], locator] if x)
tb = record.get('traceback')
if tb:
for tb_line in tb:
yield ' '.join([prefix, tb_line])
if __name__ == '__main__':
main()

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -1,486 +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
if six.PY3:
from functools import reduce
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')
def _get_error_summary(record):
"""Return the error summary
If there is no active exception, return the default.
If the record is being logged below the warning level, return an
empty string.
If there is an active exception, format it and return the
resulting string.
"""
error_summary = ''
if record.levelno < logging.WARNING:
return ''
if record.exc_info:
# Save the exception we were given so we can include the
# summary in the log line.
exc_info = record.exc_info
else:
# Check to see if there is an active exception that was
# not given to us explicitly. If so, save it so we can
# include the summary in the log line.
exc_info = sys.exc_info()
# If we get (None, None, None) because there is no
# exception, convert it to a simple None to make the logic
# that uses the value simpler.
if not exc_info[0]:
exc_info = None
elif exc_info[0] in (TypeError, ValueError,
KeyError, AttributeError, ImportError):
# NOTE(dhellmann): Do not include information about
# common built-in exceptions used to detect cases of
# bad or missing data. We don't use isinstance() here
# to limit this filter to only the built-in
# classes. This check is only performed for cases
# where the exception info is being detected
# automatically so if a caller gives us an exception
# we will definitely log it.
exc_info = None
# If we have an exception, format it to be included in the
# output.
if exc_info:
# Build the exception summary in the line with the
# primary log message, to serve as a mnemonic for error
# and warning cases.
error_summary = traceback.format_exception_only(
exc_info[0],
exc_info[1],
)[0].rstrip()
# Remove the local reference to the exception and
# traceback to avoid a memory leak through the frame
# references.
del exc_info
return error_summary
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,
'error_summary': _get_error_summary(record)}
# 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 FluentFormatter(logging.Formatter):
"""A formatter for fluentd.
format() returns dict, not string.
It expects to be used by fluent.handler.FluentHandler.
(included in fluent-logger-python)
.. versionadded:: 3.17
"""
def __init__(self, fmt=None, datefmt=None):
# NOTE(masaki) we ignore the fmt argument because of the same reason
# with JSONFormatter.
self.datefmt = datefmt
try:
self.hostname = socket.gethostname()
except socket.error:
self.hostname = None
def formatException(self, exc_info, strip_newlines=True):
lines = traceback.format_exception(*exc_info)
if strip_newlines:
lines = reduce(lambda a, line: a + line.rstrip().splitlines(),
lines, [])
return lines
def format(self, record):
message = {'message': record.getMessage(),
'time': self.formatTime(record, self.datefmt),
'name': record.name,
'level': record.levelname,
'filename': record.filename,
'lineno': record.lineno,
'module': record.module,
'funcname': record.funcName,
'process_name': record.processName,
'hostname': self.hostname,
'traceback': None,
'error_summary': _get_error_summary(record)}
# 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 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
args = (record.args.values() if isinstance(record.args, dict)
else record.args)
for arg in args or []:
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(_dictify_context(context))
)
if record.__dict__.get('request_id'):
fmt = self.conf.logging_context_format_string
else:
fmt = self.conf.logging_default_format_string
# Cache the formatted traceback on the record, Logger will
# respect our formatted copy
if record.exc_info:
record.exc_text = self.formatException(record.exc_info, record)
record.error_summary = _get_error_summary(record)
if '%(error_summary)s' in fmt:
# If we have been told explicitly how to format the error
# summary, make sure there is always a default value for
# it.
record.error_summary = record.error_summary or '-'
elif record.error_summary:
# If we have not been told how to format the error and
# there is an error to summarize, make sure the format
# string includes the bits we need to include it.
fmt += ': %(error_summary)s'
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
try:
return logging.Formatter.format(self, record)
except TypeError as err:
# Something went wrong, report that instead so we at least
# get the error message.
record.msg = 'Error formatting log line msg={!r} err={!r}'.format(
record.msg, err).replace('%', '*')
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:])

View File

@ -1,161 +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 inspect
import logging
import logging.config
import logging.handlers
import os
import six
try:
from systemd import journal
except ImportError:
journal = None
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
# This is a copy of the numerical constants from syslog.h. The
# definition of these goes back at least 20 years, and is specifically
# 3 bits in a packed field, so these aren't likely to ever need
# changing.
SYSLOG_MAP = {
"CRITICAL": 2,
"ERROR": 3,
"WARNING": 4,
"WARN": 4,
"INFO": 6,
"DEBUG": 7,
}
class OSSysLogHandler(logging.Handler):
"""Syslog based handler. Only available on UNIX-like platforms."""
def __init__(self, facility=None):
# Default values always get evaluated, for which reason we avoid
# using 'syslog' directly, which may not be available.
facility = facility if facility is not None else syslog.LOG_USER
# Do not use super() unless type(logging.Handler) is 'type'
# (i.e. >= Python 2.7).
if not syslog:
raise RuntimeError("Syslog not available on this platform")
logging.Handler.__init__(self)
binary_name = _get_binary_name()
syslog.openlog(binary_name, 0, facility)
def emit(self, record):
priority = SYSLOG_MAP.get(record.levelname, 7)
message = self.format(record)
# NOTE(gangila): In python2, the syslog function takes in 's' as
# the format argument, which means it either accepts python string
# (str = 'a') or unicode strings (str = u'a'), the PyArg_ParseTuple
# then if needed converts the unicode objects to C strings using
# the *default encoding*. This default encoding is 'ascii' in case
# of python2 while it has been changed to 'utf-8' in case of
# python3. What this leads to is when we supply a syslog message
# like:
# >>> syslog.syslog(syslog.LOG_DEBUG, u"François Deppierraz")
# In case of python2 the above fails with TypeError: [priority,]
# message string. Because python2 doesn't explicitly encode as
# 'utf-8' and use the system default encoding ascii, which raises
# a UnicodeEncodeError (UnicodeEncodeError: 'ascii' codec can't
# encode character u'\xe7' in position 4: ordinal not in
# range(128)), and hence the error message that's set in the code
# (TypeError: [priority,] message string) gets shown to the user.
# However, this in the case of Python3, where the system default
# encoding is 'utf-8' works without any issues. Therefore, we need
# to safe_encode in case of python2 and not in case of Python3.
if six.PY2:
message = encodeutils.safe_encode(self.format(record))
syslog.syslog(priority, message)
class OSJournalHandler(logging.Handler):
custom_fields = (
'project_name',
'project_id',
'user_name',
'user_id',
'request_id',
)
def __init__(self):
# Do not use super() unless type(logging.Handler) is 'type'
# (i.e. >= Python 2.7).
if not journal:
raise RuntimeError("Systemd bindings do not exist")
logging.Handler.__init__(self)
self.binary_name = _get_binary_name()
def emit(self, record):
priority = SYSLOG_MAP.get(record.levelname, 7)
message = self.format(record)
extras = {
'CODE_FILE': record.pathname,
'CODE_LINE': record.lineno,
'CODE_FUNC': record.funcName,
'THREAD_NAME': record.threadName,
'PROCESS_NAME': record.processName,
'LOGGER_NAME': record.name,
'LOGGER_LEVEL': record.levelname,
'SYSLOG_IDENTIFIER': self.binary_name,
'PRIORITY': priority
}
if record.exc_text:
extras['EXCEPTION_TEXT'] = record.exc_text
if record.exc_info:
extras['EXCEPTION_INFO'] = record.exc_info
for field in self.custom_fields:
value = record.__dict__.get(field)
if value:
extras[field.upper()] = value
journal.send(message, **extras)
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)

View File

@ -1,68 +0,0 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# 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 inspect
import logging
def _get_full_class_name(cls):
return '%s.%s' % (cls.__module__,
getattr(cls, '__qualname__', cls.__name__))
def _is_method(obj, method):
"""Returns True if a given method is obj's method.
You can not simply test a given method like:
return inspect.ismethod(method)
This is because functools.wraps converts the method to a function
in log_method_call function.
"""
return inspect.ismethod(getattr(obj, method.__name__, None))
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):
args_start_pos = 0
if args:
first_arg = args[0]
if _is_method(first_arg, method):
cls = (first_arg if isinstance(first_arg, type)
else first_arg.__class__)
caller = _get_full_class_name(cls)
args_start_pos = 1
else:
caller = 'static'
else:
caller = 'static'
data = {'caller': caller,
'method_name': method.__name__,
'args': args[args_start_pos:], 'kwargs': kwargs}
log.debug('%(caller)s method %(method_name)s '
'called with arguments %(args)s %(kwargs)s', data)
return method(*args, **kwargs)
return wrapper

View File

@ -1,60 +0,0 @@
# Andreas Jaeger <jaegerandi@gmail.com>, 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 <jaegerandi@gmail.com>\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."

View File

@ -1,55 +0,0 @@
# Andi Chandler <andi@gowling.com>, 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 <andi@gowling.com>\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"

View File

@ -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 <achisco94@gmail.com>, 2015
# Andreas Jaeger <jaegerandi@gmail.com>, 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 <achisco94@gmail.com>\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"

View File

@ -1,57 +0,0 @@
# Andreas Jaeger <jaegerandi@gmail.com>, 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 <kato.tomoyuki@jp.fujitsu.com>\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"

View File

@ -1,463 +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
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-<uuid>'
# 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 <resource_type>-<uuid>, 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('Unhandled error', **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."""
if (None, 'debug') in fresh:
_refresh_root_level(conf.debug)
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):
"""Set the level of the root logger.
:param debug: If 'debug' is True, the level will be DEBUG.
Otherwise the level will be INFO.
"""
log_root = getLogger(None).logger
if debug:
log_root.setLevel(logging.DEBUG)
else:
log_root.setLevel(logging.INFO)
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)
if conf.use_journal:
journal = handlers.OSJournalHandler()
log_root.addHandler(journal)
# if None of the above are True, then fall back to standard out
if not logpath and not conf.use_stderr and not conf.use_journal:
# pass sys.stdout as a positional argument
# python2.6 calls the argument strm, in 2.7 it's stream
streamlog = handlers.ColorHandler(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)
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)
if conf.rate_limit_burst >= 1 and conf.rate_limit_interval >= 1:
from oslo_log import rate_limit
rate_limit.install_filter(conf.rate_limit_burst,
conf.rate_limit_interval,
conf.rate_limit_except)
_loggers = {}
def get_loggers():
"""Return a copy of the oslo loggers dictionary."""
return _loggers.copy()
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)
def is_debug_enabled(conf):
"""Determine if debug logging mode is enabled."""
return conf.debug

View File

@ -1,157 +0,0 @@
# Copyright 2016 Red Hat, Inc. 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
try:
from time import monotonic as monotonic_clock # noqa
except ImportError:
from monotonic import monotonic as monotonic_clock # noqa
class _LogRateLimit(logging.Filter):
def __init__(self, burst, interval, except_level=None):
logging.Filter.__init__(self)
self.burst = burst
self.interval = interval
self.except_level = except_level
self.logger = logging.getLogger()
self._reset()
def _reset(self, now=None):
if now is None:
now = monotonic_clock()
self.counter = 0
self.end_time = now + self.interval
self.emit_warn = False
def filter(self, record):
if (self.except_level is not None
and record.levelno >= self.except_level):
# don't limit levels >= except_level
return True
timestamp = monotonic_clock()
if timestamp >= self.end_time:
self._reset(timestamp)
self.counter += 1
return True
self.counter += 1
if self.counter <= self.burst:
return True
if self.emit_warn:
# Allow to log our own warning: self.logger is also filtered by
# rate limiting
return True
if self.counter == self.burst + 1:
self.emit_warn = True
self.logger.error("Logging rate limit: "
"drop after %s records/%s sec",
self.burst, self.interval)
self.emit_warn = False
# Drop the log
return False
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
_LOG_LEVELS = {
'CRITICAL': logging.CRITICAL,
'ERROR': logging.ERROR,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'DEBUG': logging.DEBUG,
}
def install_filter(burst, interval, except_level='CRITICAL'):
"""Install a rate limit filter on existing and future loggers.
Limit logs to *burst* messages every *interval* seconds, except of levels
>= *except_level*. *except_level* is a log level name like 'CRITICAL'. If
*except_level* is an empty string, all levels are filtered.
The filter uses a monotonic clock, the timestamp of log records is not
used.
Raise an exception if a rate limit filter is already installed.
"""
if install_filter.log_filter is not None:
raise RuntimeError("rate limit filter already installed")
try:
except_levelno = _LOG_LEVELS[except_level]
except KeyError:
raise ValueError("invalid log level name: %r" % except_level)
log_filter = _LogRateLimit(burst, interval, except_levelno)
install_filter.log_filter = log_filter
install_filter.logger_class = logging.getLoggerClass()
class RateLimitLogger(install_filter.logger_class):
def __init__(self, *args, **kw):
logging.Logger.__init__(self, *args, **kw)
self.addFilter(log_filter)
# Setup our own logger class to automatically add the filter
# to new loggers.
logging.setLoggerClass(RateLimitLogger)
# Add the filter to all existing loggers
for logger in _iter_loggers():
logger.addFilter(log_filter)
install_filter.log_filter = None
install_filter.logger_class = None
def uninstall_filter():
"""Uninstall the rate filter installed by install_filter().
Do nothing if the filter was already uninstalled.
"""
if install_filter.log_filter is None:
# not installed (or already uninstalled)
return
# Restore the old logger class
logging.setLoggerClass(install_filter.logger_class)
# Remove the filter from all existing loggers
for logger in _iter_loggers():
logger.removeFilter(install_filter.log_filter)
install_filter.logger_class = None
install_filter.log_filter = None

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -1,70 +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 six
from oslo_log.cmds import convert_json
from oslo_serialization import jsonutils
from oslotest import base as test_base
TRIVIAL_RECORD = {'message': 'msg'}
DEBUG_LEVELNAME_RECORD = {
'message': 'msg',
'levelname': 'DEBUG',
}
DEBUG_LEVELNO_RECORD = {
'message': 'msg',
'levelno': 0,
}
TRACEBACK_RECORD = {
'message': 'msg',
'traceback': "abc\ndef",
}
class ConvertJsonTestCase(test_base.BaseTestCase):
def setUp(self):
super(ConvertJsonTestCase, self).setUp()
def _reformat(self, text):
fh = six.StringIO(text)
return list(convert_json.reformat_json(fh, lambda x: [x]))
def test_reformat_json_single(self):
text = jsonutils.dumps(TRIVIAL_RECORD)
self.assertEqual([TRIVIAL_RECORD], self._reformat(text))
def test_reformat_json_blanks(self):
text = jsonutils.dumps(TRIVIAL_RECORD)
self.assertEqual([TRIVIAL_RECORD], self._reformat(text + "\n\n"))
def test_reformat_json_double(self):
text = jsonutils.dumps(TRIVIAL_RECORD)
self.assertEqual(
[TRIVIAL_RECORD, TRIVIAL_RECORD],
self._reformat("\n".join([text, text])))
def _lines(self, record, pre='pre', loc='loc'):
return list(convert_json.console_format(pre, loc, record))
def test_console_format_trivial(self):
lines = self._lines(TRIVIAL_RECORD)
self.assertEqual(['pre msg'], lines)
def test_console_format_debug_levelname(self):
lines = self._lines(DEBUG_LEVELNAME_RECORD)
self.assertEqual(['pre msg'], lines)
def test_console_format_debug_levelno(self):
lines = self._lines(DEBUG_LEVELNO_RECORD)
self.assertEqual(['pre msg'], lines)

View File

@ -1,51 +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 with custom log handler"""
import logging
from oslo_log import log
from oslo_log.tests.unit.test_log import LogTestBase
class CustomLogHandler(logging.StreamHandler):
# Custom loghandler to mimick the error which was later fixed by
# https://github.com/openstack/oslo.privsep/commit/3c47348ced0d3ace1113ba8de8dff015792b0b89
def emit(self, record):
# Make args None; this was the error, which broke oslo_log formatting
record.args = None # This is intentionally wrong
super(CustomLogHandler, self).emit(record)
class CustomLogHandlerTestCase(LogTestBase):
def setUp(self):
super(CustomLogHandlerTestCase, 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, handler=CustomLogHandler)
self._set_log_level_with_cleanup(self.log, logging.DEBUG)
def test_log(self):
message = 'foo'
self.log.info(message)
self.assertEqual("NOCTXT: %s\n" % message, self.stream.getvalue())

View File

@ -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')

View File

@ -1,77 +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
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.'''
@helpers.log_method_call
def _static_method():
pass
class test_class(object):
@staticmethod
@helpers.log_method_call
def test_staticmethod(arg1, arg2, arg3, *args, **kwargs):
pass
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)
args = tuple(range(6))
kwargs = {'kwarg1': 6, 'kwarg2': 7}
data = {'caller': 'static',
'method_name': 'test_staticmethod',
'args': args,
'kwargs': kwargs}
with mock.patch('logging.Logger.debug') as debug:
test_class.test_staticmethod(*args, **kwargs)
debug.assert_called_with(mock.ANY, data)

File diff suppressed because it is too large Load Diff

View File

@ -1,110 +0,0 @@
# Copyright 2016 Red Hat, Inc. 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 mock
from oslotest import base as test_base
import six
from oslo_log import rate_limit
class LogRateLimitTestCase(test_base.BaseTestCase):
def tearDown(self):
super(LogRateLimitTestCase, self).tearDown()
rate_limit.uninstall_filter()
def install_filter(self, *args):
rate_limit.install_filter(*args)
logger = logging.getLogger()
# remove handlers to not pollute stdout
def restore_handlers(logger, handlers):
for handler in handlers:
logger.addHandler(handler)
self.addCleanup(restore_handlers, logger, list(logger.handlers))
for handler in list(logger.handlers):
logger.removeHandler(handler)
# install our handler writing logs into a StringIO
stream = six.StringIO()
handler = logging.StreamHandler(stream)
logger.addHandler(handler)
return (logger, stream)
@mock.patch('oslo_log.rate_limit.monotonic_clock')
def test_rate_limit(self, mock_clock):
mock_clock.return_value = 1
logger, stream = self.install_filter(2, 1)
# first burst
logger.error("message 1")
logger.error("message 2")
logger.error("message 3")
self.assertEqual(stream.getvalue(),
'message 1\n'
'message 2\n'
'Logging rate limit: drop after 2 records/1 sec\n')
# second burst (clock changed)
stream.seek(0)
stream.truncate()
mock_clock.return_value = 2
logger.error("message 4")
logger.error("message 5")
logger.error("message 6")
self.assertEqual(stream.getvalue(),
'message 4\n'
'message 5\n'
'Logging rate limit: drop after 2 records/1 sec\n')
@mock.patch('oslo_log.rate_limit.monotonic_clock')
def test_rate_limit_except_level(self, mock_clock):
mock_clock.return_value = 1
logger, stream = self.install_filter(1, 1, 'CRITICAL')
# first burst
logger.error("error 1")
logger.error("error 2")
logger.critical("critical 3")
logger.critical("critical 4")
self.assertEqual(stream.getvalue(),
'error 1\n'
'Logging rate limit: drop after 1 records/1 sec\n'
'critical 3\n'
'critical 4\n')
def test_install_twice(self):
rate_limit.install_filter(100, 1)
self.assertRaises(RuntimeError, rate_limit.install_filter, 100, 1)
@mock.patch('oslo_log.rate_limit.monotonic_clock')
def test_uninstall(self, mock_clock):
mock_clock.return_value = 1
logger, stream = self.install_filter(1, 1)
rate_limit.uninstall_filter()
# not limited
logger.error("message 1")
logger.error("message 2")
logger.error("message 3")
self.assertEqual(stream.getvalue(),
'message 1\n'
'message 2\n'
'message 3\n')

View File

@ -1,386 +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='Pike')
@mock.patch('oslo_log.versionutils.report_deprecated_feature')
def test_deprecated_ocata_plus_two(self, mock_reporter):
@versionutils.deprecated(as_of=versionutils.deprecated.OCATA,
remove_in=+2)
class OutdatedClass(object):
pass
obj = OutdatedClass()
self.assertIsInstance(obj, OutdatedClass)
self.assert_deprecated(mock_reporter,
what='OutdatedClass()',
as_of='Ocata',
remove_in='Queens')
@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')

View File

@ -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')

View File

@ -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',
'P': 'Pike',
'Q': 'Queens',
}
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'
PIKE = 'P'
QUEENS = 'Q'
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__
@six.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))

View File

@ -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()

View File

@ -1,3 +0,0 @@
---
other:
- Switch to reno for managing release notes.

View File

@ -1,9 +0,0 @@
---
features:
- |
If the log format string includes ``%(error_summary)s``, it will
be replaced with a summary of the current error when there is one
and with "``-``" when there is no error. If the log format string
does not include ``%(error_summary)s`` the error summary will be
appended to the end of the line automatically, only if there is an
error.

View File

@ -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".

View File

@ -1,5 +0,0 @@
---
features:
- |
A new ``oslo_log.log.is_debug_enabled`` helper function is added that
allows to determine whether debug mode is enabled for logging.

View File

@ -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.

View File

@ -1,3 +0,0 @@
---
upgrade:
- The deprecated log_format configuration option has been removed.

View File

@ -1,4 +0,0 @@
---
upgrade:
- The deprecated use_syslog_rfc_format configuration option has been
removed.

View File

@ -1,3 +0,0 @@
---
upgrade:
- The deprecated 'verbose' option has been removed.

View File

@ -1,5 +0,0 @@
---
features:
- |
Systemd native journal support is added. You can enable this in
services with the ``use_journal`` flag.

View File

@ -1,5 +0,0 @@
---
upgrade:
- Configuration option `use_stderr`'s default value is
False now, this will avoid same logs on service log and
specific log file by option --log-file.

View File

@ -1,279 +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('.'))
import openstackdocstheme
# -- 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 = [
'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 = 'openstackdocs'
# 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 = []
html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> 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 <link> 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
# -- Options for Internationalization output ------------------------------
locale_dirs = ['locale/']

View File

@ -1,12 +0,0 @@
========================
oslo.log Release Notes
========================
.. toctree::
:maxdepth: 1
unreleased
ocata
newton
mitaka
liberty

View File

@ -1,6 +0,0 @@
==============================
Liberty Series Release Notes
==============================
.. release-notes::
:branch: origin/stable/liberty

View File

@ -1,63 +0,0 @@
# Andi Chandler <andi@gowling.com>, 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 <andi@gowling.com>\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"

View File

@ -1,60 +0,0 @@
# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata
msgid ""
msgstr ""
"Project-Id-Version: oslo.log Release Notes 3.16.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-13 11:46+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2016-10-22 06:01+0000\n"
"Last-Translator: Gérald LONLAS <g.lonlas@gmail.com>\n"
"Language-Team: French\n"
"Language: fr\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.12.0"
msgstr "3.12.0"
msgid "3.16.0-24"
msgstr "3.16.0-24"
msgid "3.2.0"
msgstr "3.2.0"
msgid "3.8.0"
msgstr "3.8.0"
msgid "Bug Fixes"
msgstr "Corrections de bugs"
msgid "Liberty Series Release Notes"
msgstr "Note de release pour Liberty"
msgid "Mitaka Series Release Notes"
msgstr "Note de release pour Mitaka"
msgid "New Features"
msgstr "Nouvelles fonctionnalités"
msgid "Newton Series Release Notes"
msgstr "Note de release pour Newton"
msgid "Other Notes"
msgstr "Autres notes"
msgid "Switch to reno for managing release notes."
msgstr "Commence à utiliser reno pour la gestion des notes de release"
msgid "Unreleased Release Notes"
msgstr "Note de release pour les changements non déployées"
msgid "Upgrade Notes"
msgstr "Notes de mises à jours"
msgid "oslo.log Release Notes"
msgstr "Note de release pour oslo.log"

View File

@ -1,6 +0,0 @@
===================================
Mitaka Series Release Notes
===================================
.. release-notes::
:branch: origin/stable/mitaka

View File

@ -1,6 +0,0 @@
=============================
Newton Series Release Notes
=============================
.. release-notes::
:branch: origin/stable/newton

View File

@ -1,6 +0,0 @@
===================================
Ocata Series Release Notes
===================================
.. release-notes::
:branch: origin/stable/ocata

View File

@ -1,5 +0,0 @@
==========================
Unreleased Release Notes
==========================
.. release-notes::

View File

@ -1,15 +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!=2.1.0,>=2.0.0 # Apache-2.0
six>=1.9.0 # MIT
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
oslo.context>=2.14.0 # Apache-2.0
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
oslo.serialization!=2.19.1,>=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
monotonic>=0.6 # Apache-2.0

View File

@ -1,61 +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 = https://docs.openstack.org/oslo.log/latest
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.5
[files]
packages =
oslo_log
[extras]
fixtures =
fixtures>=3.0.0 # Apache-2.0/BSD
systemd =
systemd-python>=234 # LGPLv2+
[entry_points]
oslo.config.opts =
oslo.log = oslo_log._options:list_opts
console_scripts =
convert-json = oslo_log.cmds.convert_json:main
[build_sphinx]
all-files = 1
warning-is-error = 1
source-dir = doc/source
build-dir = doc/build
[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

View File

@ -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>=2.0.0'],
pbr=True)

View File

@ -1,24 +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.13.0,<0.14,>=0.12.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
testrepository>=0.0.18 # 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!=4.4,>=4.0 # Apache-2.0
# this is required for the docs build jobs
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.11.0 # Apache-2.0
reno!=2.3.1,>=1.8.0 # Apache-2.0
# Bandit security code scanner
bandit>=1.1.0 # Apache-2.0

View File

@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Client constraint file contains this client version pin that is in conflict
# with installing the client from source. We should remove the version pin in
# the constraints file before applying it for from-source installation.
CONSTRAINTS_FILE="$1"
shift 1
set -e
# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
# published to logs.openstack.org for easy debugging.
localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
if [[ "$CONSTRAINTS_FILE" != http* ]]; then
CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
fi
# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
pip install -c"$localfile" openstack-requirements
# This is the main purpose of the script: Allow local installation of
# the current repo. It is listed in constraints file and thus any
# install will be constrained and we need to unconstrain it.
edit-constraints "$localfile" -- "$CLIENT_NAME"
pip install -c"$localfile" -U "$@"
exit $?

Some files were not shown because too many files have changed in this diff Show More