Rationalize logging helpers and docs
shade and openstacksdk each have a logging doc and a logging setup helper function. They both basically do the same thing, and we have a TODO item about collapsing them. This moves openstack.utils.enable_logging to openstack.enable_logging (leaving behind a compat piece at openstack.utils.enable_logging) It adds the shade functionality to it, and also changes the behavior to match shade's WRT behavior when no parameters are passed (defaults to logging to stdout) Update the codebase to call openstack._log.setup_logging instead of logging.getLogger directly, as setup_logging attaches a NullHandler by default. Collapse the docs into a single document. There were only two places where openstacksdk was already logging to something other than 'openstack'. Collapse those down to 'openstack' until we come up with a reason to break them out more logically. Change-Id: I45fd5ffd18255450d38a1f56c80f5c157ea19ae3
This commit is contained in:
parent
40d425c595
commit
da2406bace
100
README.rst
100
README.rst
@ -6,45 +6,95 @@ with OpenStack clouds. The project aims to provide a consistent and
|
||||
complete set of interactions with OpenStack's many services, along with
|
||||
complete documentation, examples, and tools.
|
||||
|
||||
It also contains a simple interface layer. Clouds can do many things, but
|
||||
It also contains an abstraction interface layer. Clouds can do many things, but
|
||||
there are probably only about 10 of them that most people care about with any
|
||||
regularity. If you want to do complicated things, the per-service oriented
|
||||
portions of the SDK are for you. However, if what you want is to be able to
|
||||
portions of the SDK are for you. However, if what you want to be able to
|
||||
write an application that talks to clouds no matter what crazy choices the
|
||||
deployer has made in an attempt to be more hipster than their self-entitled
|
||||
narcissist peers, then the ``openstack.cloud`` layer is for you.
|
||||
narcissist peers, then the Cloud Abstraction layer is for you.
|
||||
|
||||
A Brief History
|
||||
---------------
|
||||
|
||||
.. TODO(shade) This history section should move to the docs. We can put a
|
||||
link to the published URL here in the README, but it's too long.
|
||||
|
||||
openstacksdk started its life as three different libraries: shade,
|
||||
os-client-config and python-openstacksdk.
|
||||
|
||||
``shade`` started its life as some code inside of OpenStack Infra's nodepool
|
||||
project, and as some code inside of Ansible. Ansible had a bunch of different
|
||||
OpenStack related modules, and there was a ton of duplicated code. Eventually,
|
||||
between refactoring that duplication into an internal library, and adding logic
|
||||
and features that the OpenStack Infra team had developed to run client
|
||||
applications at scale, it turned out that we'd written nine-tenths of what we'd
|
||||
need to have a standalone library.
|
||||
``shade`` started its life as some code inside of OpenStack Infra's `nodepool`_
|
||||
project, and as some code inside of the `Ansible OpenStack Modules`_.
|
||||
Ansible had a bunch of different OpenStack related modules, and there was a
|
||||
ton of duplicated code. Eventually, between refactoring that duplication into
|
||||
an internal library, and adding the logic and features that the OpenStack Infra
|
||||
team had developed to run client applications at scale, it turned out that we'd
|
||||
written nine-tenths of what we'd need to have a standalone library.
|
||||
|
||||
Because of its background from nodepool, shade contained abstractions to
|
||||
work around deployment differences and is resource oriented rather than service
|
||||
oriented. This allows a user to think about Security Groups without having to
|
||||
know whether Security Groups are provided by Nova or Neutron on a given cloud.
|
||||
On the other hand, as an interface that provides an abstraction, it deviates
|
||||
from the published OpenStack REST API and adds its own opinions, which may not
|
||||
get in the way of more advanced users with specific needs.
|
||||
|
||||
``os-client-config`` was a library for collecting client configuration for
|
||||
using an OpenStack cloud in a consistent and comprehensive manner.
|
||||
In parallel, the python-openstacksdk team was working on a library to expose
|
||||
the OpenStack APIs to developers in a consistent and predictable manner. After
|
||||
a while it became clear that there was value in both a high-level layer that
|
||||
contains business logic, a lower-level SDK that exposes services and their
|
||||
resources as Python objects, and also to be able to make direct REST calls
|
||||
when needed with a properly configured Session or Adapter from python-requests.
|
||||
This led to the merger of the three projects.
|
||||
using an OpenStack cloud in a consistent and comprehensive manner, which
|
||||
introduced the ``clouds.yaml`` file for expressing named cloud configurations.
|
||||
|
||||
The contents of the shade library have been moved into ``openstack.cloud``
|
||||
and os-client-config has been moved in to ``openstack.config``. The next
|
||||
release of shade will be a thin compatibility layer that subclasses the objects
|
||||
from ``openstack.cloud`` and provides different argument defaults where needed
|
||||
for compat. Similarly the next release of os-client-config will be a compat
|
||||
``python-openstacksdk`` was a library that exposed the OpenStack APIs to
|
||||
developers in a consistent and predictable manner.
|
||||
|
||||
After a while it became clear that there was value in both the high-level
|
||||
layer that contains additional business logic and the lower-level SDK that
|
||||
exposes services and their resources faithfully and consistently as Python
|
||||
objects.
|
||||
|
||||
Even with both of those layers, it is still beneficial at times to be able to
|
||||
make direct REST calls and to do so with the same properly configured
|
||||
`Session`_ from `python-requests`_.
|
||||
|
||||
This led to the merge of the three projects.
|
||||
|
||||
The original contents of the shade library have been moved into
|
||||
``openstack.cloud`` and os-client-config has been moved in to
|
||||
``openstack.config``. The next release of shade will be a thin compatibility
|
||||
layer that subclasses the objects from ``openstack.cloud`` and provides
|
||||
different argument defaults where needed for compat.
|
||||
Similarly the next release of os-client-config will be a compat
|
||||
layer shim around ``openstack.config``.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``openstack.cloud.OpenStackCloud`` object and the
|
||||
``openstack.connection.Connection`` object are going to be merged. It is
|
||||
recommended to not write any new code which consumes objects from the
|
||||
``openstack.cloud`` namespace until that merge is complete.
|
||||
|
||||
.. _nodepool: https://docs.openstack.org/infra/nodepool/
|
||||
.. _Ansible OpenStack Modules: http://docs.ansible.com/ansible/latest/list_of_cloud_modules.html#openstack
|
||||
.. _Session: http://docs.python-requests.org/en/master/user/advanced/#session-objects
|
||||
.. _python-requests: http://docs.python-requests.org/en/master/
|
||||
|
||||
openstack
|
||||
=========
|
||||
|
||||
List servers using objects configured with the ``clouds.yaml`` file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
# Initialize cloud
|
||||
conn = openstack.connect(cloud='mordred')
|
||||
|
||||
for server in conn.compute.servers():
|
||||
print(server.to_dict())
|
||||
|
||||
openstack.config
|
||||
================
|
||||
|
||||
@ -88,10 +138,10 @@ Create a server using objects configured with the ``clouds.yaml`` file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
# Initialize cloud
|
||||
# Cloud configs are read with openstack.config
|
||||
|
@ -72,7 +72,6 @@ shade integration
|
||||
* Investigate auto-generating the bulk of shade's API based on introspection of
|
||||
SDK objects, leaving only the code with extra special logic in the shade
|
||||
layer.
|
||||
* Rationalize openstack.util.enable_logging and shade.simple_logging.
|
||||
|
||||
Service Proxies
|
||||
---------------
|
||||
|
@ -1,56 +1,44 @@
|
||||
=======
|
||||
Logging
|
||||
=======
|
||||
|
||||
Logging can save you time and effort when developing your code or looking
|
||||
for help. If your code is not behaving how you expect it to, enabling and
|
||||
configuring logging can quickly give you valuable insight into the root
|
||||
cause of the issue. If you need help from the OpenStack community, the
|
||||
logs can help the people there assist you.
|
||||
.. note:: TODO(shade) This document is written from a shade POV. It needs to
|
||||
be combined with the existing logging guide, but also the logging
|
||||
systems need to be rationalized.
|
||||
|
||||
.. note:: By default, no logging is done.
|
||||
`openstacksdk` uses `Python Logging`_. As `openstacksdk` is a library, it does
|
||||
not configure logging handlers automatically, expecting instead for that to be
|
||||
the purview of the consuming application.
|
||||
|
||||
Enable SDK Logging
|
||||
------------------
|
||||
Simple Usage
|
||||
------------
|
||||
|
||||
To enable logging you use :func:`~openstack.utils.enable_logging`.
|
||||
For consumers who just want to get a basic logging setup without thinking
|
||||
about it too deeply, there is a helper method. If used, it should be called
|
||||
before any other openstacksdk functionality.
|
||||
|
||||
The ``debug`` parameter controls the logging level. Set ``debug=True`` to
|
||||
log debug and higher messages. Set ``debug=False`` to log warning and higher
|
||||
messages.
|
||||
.. autofunction:: openstack.enable_logging
|
||||
|
||||
To log debug and higher messages::
|
||||
.. code-block:: python
|
||||
|
||||
import sys
|
||||
from openstack import utils
|
||||
|
||||
utils.enable_logging(debug=True, stream=sys.stdout)
|
||||
|
||||
The ``path`` parameter controls the location of a log file. If set, this
|
||||
parameter will send log messages to a file using a
|
||||
:py:class:`~logging.FileHandler`.
|
||||
|
||||
To log messages to a file called ``openstack.log``::
|
||||
|
||||
from openstack import utils
|
||||
|
||||
utils.enable_logging(debug=True, path='openstack.log')
|
||||
import openstack
|
||||
openstack.enable_logging()
|
||||
|
||||
The ``stream`` parameter controls the stream where log message are written to.
|
||||
If set to ``sys.stdout`` or ``sys.stderr``, this parameter will send log
|
||||
messages to that stream using a :py:class:`~logging.StreamHandler`
|
||||
It defaults to `sys.stdout` which will result in log messages being written
|
||||
to STDOUT. It can be set to another output stream, or to ``None`` to disable
|
||||
logging to the console.
|
||||
|
||||
To log messages to the console on ``stdout``::
|
||||
|
||||
import sys
|
||||
from openstack import utils
|
||||
|
||||
utils.enable_logging(debug=True, stream=sys.stdout)
|
||||
The ``path`` parameter sets up logging to log to a file. By default, if
|
||||
``path`` is given and ``stream`` is not, logging will only go to ``path``.
|
||||
|
||||
You can combine the ``path`` and ``stream`` parameters to log to both places
|
||||
simultaneously.
|
||||
|
||||
To log messages to a file called ``openstack.log`` and the console on
|
||||
``stdout``::
|
||||
``stdout``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sys
|
||||
from openstack import utils
|
||||
@ -58,23 +46,68 @@ To log messages to a file called ``openstack.log`` and the console on
|
||||
utils.enable_logging(debug=True, path='openstack.log', stream=sys.stdout)
|
||||
|
||||
|
||||
Enable requests Logging
|
||||
-----------------------
|
||||
`openstack.enable_logging` also sets up a few other loggers and
|
||||
squelches some warnings or log messages that are otherwise uninteresting or
|
||||
unactionable by an openstacksdk user.
|
||||
|
||||
The SDK depends on a small number other libraries. Notably, it uses
|
||||
`requests <https://pypi.python.org/pypi/requests>`_ for its transport layer.
|
||||
To get even more information about the request/response cycle, you enable
|
||||
logging of requests the same as you would any other library.
|
||||
Advanced Usage
|
||||
--------------
|
||||
|
||||
To log messages to the console on ``stdout``::
|
||||
`openstacksdk` logs to a set of different named loggers.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
Most of the logging is set up to log to the root ``openstack`` logger.
|
||||
There are additional sub-loggers that are used at times, primarily so that a
|
||||
user can decide to turn on or off a specific type of logging. They are listed
|
||||
below.
|
||||
|
||||
logger = logging.getLogger('requests')
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s %(levelname)s: %(name)s %(message)s')
|
||||
console = logging.StreamHandler(sys.stdout)
|
||||
console.setFormatter(formatter)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(console)
|
||||
openstack.config
|
||||
Issues pertaining to configuration are logged to the ``openstack.config``
|
||||
logger.
|
||||
|
||||
openstack.task_manager
|
||||
`openstacksdk` uses a Task Manager to perform remote calls. The
|
||||
``openstack.task_manager`` logger emits messages at the start and end
|
||||
of each Task announcing what it is going to run and then what it ran and
|
||||
how long it took. Logging ``openstack.task_manager`` is a good way to
|
||||
get a trace of external actions `openstacksdk` is taking without full
|
||||
`HTTP Tracing`_.
|
||||
|
||||
openstack.iterate_timeout
|
||||
When `openstacksdk` needs to poll a resource, it does so in a loop that waits
|
||||
between iterations and ultimately times out. The
|
||||
``openstack.iterate_timeout`` logger emits messages for each iteration
|
||||
indicating it is waiting and for how long. These can be useful to see for
|
||||
long running tasks so that one can know things are not stuck, but can also
|
||||
be noisy.
|
||||
|
||||
openstack.fnmatch
|
||||
`openstacksdk` will try to use `fnmatch`_ on given `name_or_id` arguments.
|
||||
It's a best effort attempt, so pattern misses are logged to
|
||||
``openstack.fnmatch``. A user may not be intending to use an fnmatch
|
||||
pattern - such as if they are trying to find an image named
|
||||
``Fedora 24 [official]``, so these messages are logged separately.
|
||||
|
||||
.. _fnmatch: https://pymotw.com/2/fnmatch/
|
||||
|
||||
HTTP Tracing
|
||||
------------
|
||||
|
||||
HTTP Interactions are handled by `keystoneauth`_. If you want to enable HTTP
|
||||
tracing while using openstacksdk and are not using `openstack.enable_logging`,
|
||||
set the log level of the ``keystoneauth`` logger to ``DEBUG``.
|
||||
|
||||
For more information see https://docs.openstack.org/keystoneauth/latest/using-sessions.html#logging
|
||||
|
||||
.. _keystoneauth: https://docs.openstack.org/keystoneauth/latest/
|
||||
|
||||
Python Logging
|
||||
--------------
|
||||
|
||||
Python logging is a standard feature of Python and is documented fully in the
|
||||
Python Documentation, which varies by version of Python.
|
||||
|
||||
For more information on Python Logging for Python v2, see
|
||||
https://docs.python.org/2/library/logging.html.
|
||||
|
||||
For more information on Python Logging for Python v3, see
|
||||
https://docs.python.org/3/library/logging.html.
|
||||
|
@ -22,8 +22,6 @@ These guides walk you through how to make use of the libraries we provide
|
||||
to work with each OpenStack service. If you're looking for a cookbook
|
||||
approach, this is where you'll want to begin.
|
||||
|
||||
.. TODO(shade) Merge guides/logging and logging
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
@ -32,7 +30,6 @@ approach, this is where you'll want to begin.
|
||||
Connect to an OpenStack Cloud Using a Config File <guides/connect_from_config>
|
||||
Using Cloud Abstration Layer <usage>
|
||||
Logging <guides/logging>
|
||||
Shade Logging <logging>
|
||||
Microversions <microversions>
|
||||
Baremetal <guides/baremetal>
|
||||
Block Storage <guides/block_storage>
|
||||
|
@ -1,99 +0,0 @@
|
||||
=======
|
||||
Logging
|
||||
=======
|
||||
|
||||
.. note:: TODO(shade) This document is written from a shade POV. It needs to
|
||||
be combined with the existing logging guide, but also the logging
|
||||
systems need to be rationalized.
|
||||
|
||||
`openstacksdk` uses `Python Logging`_. As `openstacksdk` is a library, it does
|
||||
not configure logging handlers automatically, expecting instead for that to be
|
||||
the purview of the consuming application.
|
||||
|
||||
Simple Usage
|
||||
------------
|
||||
|
||||
For consumers who just want to get a basic logging setup without thinking
|
||||
about it too deeply, there is a helper method. If used, it should be called
|
||||
before any other `shade` functionality.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging()
|
||||
|
||||
`openstack.cloud.simple_logging` takes two optional boolean arguments:
|
||||
|
||||
debug
|
||||
Turns on debug logging.
|
||||
|
||||
http_debug
|
||||
Turns on debug logging as well as debug logging of the underlying HTTP calls.
|
||||
|
||||
`openstack.cloud.simple_logging` also sets up a few other loggers and
|
||||
squelches some warnings or log messages that are otherwise uninteresting or
|
||||
unactionable by a `openstack.cloud` user.
|
||||
|
||||
Advanced Usage
|
||||
--------------
|
||||
|
||||
`openstack.cloud` logs to a set of different named loggers.
|
||||
|
||||
Most of the logging is set up to log to the root `openstack.cloud` logger.
|
||||
There are additional sub-loggers that are used at times, primarily so that a
|
||||
user can decide to turn on or off a specific type of logging. They are listed
|
||||
below.
|
||||
|
||||
openstack.task_manager
|
||||
`openstack.cloud` uses a Task Manager to perform remote calls. The
|
||||
`openstack.cloud.task_manager` logger emits messages at the start and end
|
||||
of each Task announcing what it is going to run and then what it ran and
|
||||
how long it took. Logging `openstack.cloud.task_manager` is a good way to
|
||||
get a trace of external actions `openstack.cloud` is taking without full
|
||||
`HTTP Tracing`_.
|
||||
|
||||
openstack.cloud.exc
|
||||
If `log_inner_exceptions` is set to True, `shade` will emit any wrapped
|
||||
exception to the `openstack.cloud.exc` logger. Wrapped exceptions are usually
|
||||
considered implementation details, but can be useful for debugging problems.
|
||||
|
||||
openstack.iterate_timeout
|
||||
When `shade` needs to poll a resource, it does so in a loop that waits
|
||||
between iterations and ultimately timesout. The
|
||||
`openstack.iterate_timeout` logger emits messages for each iteration
|
||||
indicating it is waiting and for how long. These can be useful to see for
|
||||
long running tasks so that one can know things are not stuck, but can also
|
||||
be noisy.
|
||||
|
||||
openstack.cloud.http
|
||||
`shade` will sometimes log additional information about HTTP interactions
|
||||
to the `openstack.cloud.http` logger. This can be verbose, as it sometimes
|
||||
logs entire response bodies.
|
||||
|
||||
openstack.cloud.fnmatch
|
||||
`shade` will try to use `fnmatch`_ on given `name_or_id` arguments. It's a
|
||||
best effort attempt, so pattern misses are logged to
|
||||
`openstack.cloud.fnmatch`. A user may not be intending to use an fnmatch
|
||||
pattern - such as if they are trying to find an image named
|
||||
``Fedora 24 [official]``, so these messages are logged separately.
|
||||
|
||||
.. _fnmatch: https://pymotw.com/2/fnmatch/
|
||||
|
||||
HTTP Tracing
|
||||
------------
|
||||
|
||||
HTTP Interactions are handled by `keystoneauth`. If you want to enable HTTP
|
||||
tracing while using `shade` and are not using `openstack.cloud.simple_logging`,
|
||||
set the log level of the `keystoneauth` logger to `DEBUG`.
|
||||
|
||||
Python Logging
|
||||
--------------
|
||||
|
||||
Python logging is a standard feature of Python and is documented fully in the
|
||||
Python Documentation, which varies by version of Python.
|
||||
|
||||
For more information on Python Logging for Python v2, see
|
||||
https://docs.python.org/2/library/logging.html.
|
||||
|
||||
For more information on Python Logging for Python v3, see
|
||||
https://docs.python.org/3/library/logging.html.
|
@ -62,10 +62,10 @@ Complete Example
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
@ -314,10 +314,10 @@ Complete Example Again
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
@ -346,27 +346,25 @@ Import the library
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
Logging
|
||||
=======
|
||||
|
||||
* `shade` uses standard python logging
|
||||
* Special `openstack.cloud.request_ids` logger for API request IDs
|
||||
* `simple_logging` does easy defaults
|
||||
* `openstacksdk` uses standard python logging
|
||||
* ``openstack.enable_logging`` does easy defaults
|
||||
* Squelches some meaningless warnings
|
||||
|
||||
* `debug`
|
||||
|
||||
* Logs shade loggers at debug level
|
||||
* Includes `openstack.cloud.request_ids` debug logging
|
||||
|
||||
* `http_debug` Implies `debug`, turns on HTTP tracing
|
||||
|
||||
.. code:: python
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
Example with Debug Logging
|
||||
==========================
|
||||
@ -375,8 +373,8 @@ Example with Debug Logging
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
@ -389,8 +387,8 @@ Example with HTTP Debug Logging
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(http_debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(http_debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
@ -486,10 +484,10 @@ Image and Flavor by Name or ID
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor in [
|
||||
('my-vexxhost', 'ca-ymq-1',
|
||||
@ -533,10 +531,10 @@ Image and Flavor by Dict
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor_id in [
|
||||
('my-vexxhost', 'ca-ymq-1', 'Ubuntu 16.04.1 LTS [2017-03-03]',
|
||||
@ -564,8 +562,8 @@ Munch Objects
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='zetta', region_name='no-osl1')
|
||||
image = cloud.get_image('Ubuntu 14.04 (AMD64) [Local Storage]')
|
||||
@ -596,10 +594,10 @@ Cleanup Script
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
@ -618,8 +616,8 @@ Normalization
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging()
|
||||
import openstack
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
image = cloud.get_image(
|
||||
@ -634,8 +632,8 @@ Strict Normalized Results
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging()
|
||||
import openstack
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='fuga', region_name='cystack', strict=True)
|
||||
@ -651,8 +649,8 @@ How Did I Find the Image Name for the Last Example?
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging()
|
||||
import openstack
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
cloud.pprint([
|
||||
@ -672,8 +670,8 @@ Added / Modified Information
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='my-citycloud', region_name='Buf1')
|
||||
try:
|
||||
@ -714,8 +712,8 @@ User Agent Info
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(http_debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(http_debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='datacentred', app_name='AmazingApp', app_version='1.0')
|
||||
@ -732,8 +730,8 @@ Uploading Large Objects
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
@ -753,8 +751,8 @@ Uploading Large Objects
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
@ -769,8 +767,8 @@ Service Conditionals
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='kiss', region_name='region1')
|
||||
print(cloud.has_service('network'))
|
||||
@ -783,8 +781,8 @@ Service Conditional Overrides
|
||||
|
||||
.. code:: python
|
||||
|
||||
import openstack.cloud
|
||||
openstack.cloud.simple_logging(debug=True)
|
||||
import openstack
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='rax', region_name='DFW')
|
||||
print(cloud.has_service('network'))
|
||||
|
@ -13,7 +13,7 @@
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name in [
|
||||
('my-vexxhost', 'ca-ymq-1'),
|
||||
|
@ -13,7 +13,7 @@
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor_id in [
|
||||
('my-vexxhost', 'ca-ymq-1', 'Ubuntu 16.04.1 LTS [2017-03-03]',
|
||||
|
@ -13,7 +13,7 @@
|
||||
import openstack
|
||||
|
||||
# Initialize and turn on debug logging
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
for cloud_name, region_name, image, flavor in [
|
||||
('my-vexxhost', 'ca-ymq-1',
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging()
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
cloud.pprint([
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(http_debug=True)
|
||||
openstack.enable_logging(http_debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='my-vexxhost', region_name='ca-ymq-1')
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
image = cloud.get_image('Ubuntu 16.10')
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging()
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='fuga', region_name='cystack')
|
||||
image = cloud.get_image(
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='my-citycloud', region_name='Buf1')
|
||||
try:
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='rax', region_name='DFW')
|
||||
print(cloud.has_service('network'))
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='kiss', region_name='region1')
|
||||
print(cloud.has_service('network'))
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging()
|
||||
openstack.enable_logging()
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='fuga', region_name='cystack', strict=True)
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(debug=True)
|
||||
openstack.enable_logging(debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(cloud='ovh', region_name='SBG1')
|
||||
cloud.create_object(
|
||||
|
@ -11,7 +11,7 @@
|
||||
# under the License.
|
||||
|
||||
import openstack
|
||||
openstack.simple_logging(http_debug=True)
|
||||
openstack.enable_logging(http_debug=True)
|
||||
|
||||
cloud = openstack.openstack_cloud(
|
||||
cloud='datacentred', app_name='AmazingApp', app_version='1.0')
|
||||
|
@ -12,15 +12,21 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
__all__ = [
|
||||
'__version__',
|
||||
'connect',
|
||||
'enable_logging',
|
||||
]
|
||||
|
||||
import warnings
|
||||
|
||||
import keystoneauth1.exceptions
|
||||
import pbr.version
|
||||
import requestsexceptions
|
||||
|
||||
from openstack import _log
|
||||
from openstack._log import enable_logging # noqa
|
||||
from openstack.cloud.exc import * # noqa
|
||||
# TODO(shade) These two want to be removed before we make a release
|
||||
from openstack.cloud.openstackcloud import OpenStackCloud
|
||||
from openstack.cloud.operatorcloud import OperatorCloud
|
||||
import openstack.connection
|
||||
@ -34,43 +40,11 @@ if requestsexceptions.SubjectAltNameWarning:
|
||||
|
||||
def _get_openstack_config(app_name=None, app_version=None):
|
||||
import openstack.config
|
||||
# Protect against older versions of os-client-config that don't expose this
|
||||
try:
|
||||
return openstack.config.OpenStackConfig(
|
||||
app_name=app_name, app_version=app_version)
|
||||
except Exception:
|
||||
return openstack.config.OpenStackConfig()
|
||||
return openstack.config.OpenStackConfig(
|
||||
app_name=app_name, app_version=app_version)
|
||||
|
||||
|
||||
def simple_logging(debug=False, http_debug=False):
|
||||
if http_debug:
|
||||
debug = True
|
||||
if debug:
|
||||
log_level = logging.DEBUG
|
||||
else:
|
||||
log_level = logging.INFO
|
||||
if http_debug:
|
||||
# Enable HTTP level tracing
|
||||
log = _log.setup_logging('keystoneauth')
|
||||
log.addHandler(logging.StreamHandler())
|
||||
log.setLevel(log_level)
|
||||
# We only want extra shade HTTP tracing in http debug mode
|
||||
log = _log.setup_logging('openstack.cloud.http')
|
||||
log.setLevel(log_level)
|
||||
else:
|
||||
# We only want extra shade HTTP tracing in http debug mode
|
||||
log = _log.setup_logging('openstack.cloud.http')
|
||||
log.setLevel(logging.WARNING)
|
||||
log = _log.setup_logging('openstack.cloud')
|
||||
log.addHandler(logging.StreamHandler())
|
||||
log.setLevel(log_level)
|
||||
# Suppress warning about keystoneauth loggers
|
||||
log = _log.setup_logging('keystoneauth.identity.base')
|
||||
log = _log.setup_logging('keystoneauth.identity.generic.base')
|
||||
|
||||
|
||||
# TODO(shade) Document this and add some examples
|
||||
# TODO(shade) This wants to be renamed before we make a release.
|
||||
# TODO(shade) This wants to be remove before we make a release.
|
||||
def openstack_clouds(
|
||||
config=None, debug=False, cloud=None, strict=False,
|
||||
app_name=None, app_version=None):
|
||||
@ -99,10 +73,7 @@ def openstack_clouds(
|
||||
"Invalid cloud configuration: {exc}".format(exc=str(e)))
|
||||
|
||||
|
||||
# TODO(shade) This wants to be renamed before we make a release - there is
|
||||
# ultimately no reason to have an openstack_cloud and a connect
|
||||
# factory function - but we have a few steps to go first and this is used
|
||||
# in the imported tests from shade.
|
||||
# TODO(shade) This wants to be removed before we make a release.
|
||||
def openstack_cloud(
|
||||
config=None, strict=False, app_name=None, app_version=None, **kwargs):
|
||||
if not config:
|
||||
@ -115,10 +86,7 @@ def openstack_cloud(
|
||||
return OpenStackCloud(cloud_config=cloud_region, strict=strict)
|
||||
|
||||
|
||||
# TODO(shade) This wants to be renamed before we make a release - there is
|
||||
# ultimately no reason to have an operator_cloud and a connect
|
||||
# factory function - but we have a few steps to go first and this is used
|
||||
# in the imported tests from shade.
|
||||
# TODO(shade) This wants to be removed before we make a release.
|
||||
def operator_cloud(
|
||||
config=None, strict=False, app_name=None, app_version=None, **kwargs):
|
||||
if not config:
|
||||
@ -134,3 +102,16 @@ def operator_cloud(
|
||||
def connect(*args, **kwargs):
|
||||
"""Create a `openstack.connection.Connection`."""
|
||||
return openstack.connection.Connection(*args, **kwargs)
|
||||
|
||||
|
||||
def connect_all(config=None, app_name=None, app_version=None):
|
||||
if not config:
|
||||
config = _get_openstack_config(app_name, app_version)
|
||||
try:
|
||||
return [
|
||||
openstack.connection.Connection(config=cloud_region)
|
||||
for cloud_region in config.get_all()
|
||||
]
|
||||
except keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin as e:
|
||||
raise OpenStackCloudException(
|
||||
"Invalid cloud configuration: {exc}".format(exc=str(e)))
|
||||
|
@ -13,16 +13,102 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
def setup_logging(name, handlers=None, level=None):
|
||||
"""Set up logging for a named logger.
|
||||
|
||||
Gets and initializes a named logger, ensuring it at least has a
|
||||
`logging.NullHandler` attached.
|
||||
|
||||
def setup_logging(name):
|
||||
:param str name:
|
||||
Name of the logger.
|
||||
:param list handlers:
|
||||
A list of `logging.Handler` objects to attach to the logger.
|
||||
:param int level:
|
||||
Log level to set the logger at.
|
||||
|
||||
:returns: A `logging.Logger` object that can be used to emit log messages.
|
||||
"""
|
||||
handlers = handlers or []
|
||||
log = logging.getLogger(name)
|
||||
if len(log.handlers) == 0:
|
||||
h = NullHandler()
|
||||
if len(log.handlers) == 0 and not handlers:
|
||||
h = logging.NullHandler()
|
||||
log.addHandler(h)
|
||||
for h in handlers:
|
||||
log.addHandler(h)
|
||||
if level:
|
||||
log.setLevel(level)
|
||||
return log
|
||||
|
||||
|
||||
def enable_logging(
|
||||
debug=False, http_debug=False, path=None, stream=None,
|
||||
format_stream=False,
|
||||
format_template='%(asctime)s %(levelname)s: %(name)s %(message)s'):
|
||||
"""Enable logging output.
|
||||
|
||||
Helper function to enable logging. This function is available for
|
||||
debugging purposes and for folks doing simple applications who want an
|
||||
easy 'just make it work for me'. For more complex applications or for
|
||||
those who want more flexibility, the standard library ``logging`` package
|
||||
will receive these messages in any handlers you create.
|
||||
|
||||
:param bool debug:
|
||||
Set this to ``True`` to receive debug messages.
|
||||
:param bool http_debug:
|
||||
Set this to ``True`` to receive debug messages including
|
||||
HTTP requests and responses. This implies ``debug=True``.
|
||||
:param str path:
|
||||
If a *path* is specified, logging output will written to that file
|
||||
in addition to sys.stderr.
|
||||
The path is passed to logging.FileHandler, which will append messages
|
||||
the file (and create it if needed).
|
||||
:param stream:
|
||||
One of ``None `` or ``sys.stdout`` or ``sys.stderr``.
|
||||
If it is ``None``, nothing is logged to a stream.
|
||||
If it isn't ``None``, console output is logged to this stream.
|
||||
:param bool format_stream:
|
||||
If format_stream is False, the default, apply ``format_template`` to
|
||||
``path`` but not to ``stream`` outputs. If True, apply
|
||||
``format_template`` to ``stream`` outputs as well.
|
||||
:param str format_template:
|
||||
Template to pass to :class:`logging.Formatter`.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if not stream and not path:
|
||||
stream = sys.stdout
|
||||
|
||||
if http_debug:
|
||||
debug = True
|
||||
if debug:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.INFO
|
||||
|
||||
formatter = logging.Formatter(format_template)
|
||||
|
||||
handlers = []
|
||||
|
||||
if stream is not None:
|
||||
console = logging.StreamHandler(stream)
|
||||
if format_stream:
|
||||
console.setFormatter(formatter)
|
||||
handlers.append(console)
|
||||
|
||||
if path is not None:
|
||||
file_handler = logging.FileHandler(path)
|
||||
file_handler.setFormatter(formatter)
|
||||
handlers.append(file_handler)
|
||||
|
||||
if http_debug:
|
||||
# Enable HTTP level tracing
|
||||
setup_logging('keystoneauth', handlers=handlers, level=level)
|
||||
|
||||
setup_logging('openstack', handlers=handlers, level=level)
|
||||
# Suppress warning about keystoneauth loggers
|
||||
setup_logging('keystoneauth.discovery')
|
||||
setup_logging('keystoneauth.identity.base')
|
||||
setup_logging('keystoneauth.identity.generic.base')
|
||||
|
@ -94,7 +94,7 @@ def _filter_list(data, name_or_id, filters):
|
||||
# The logger is openstack.cloud.fmmatch to allow a user/operator to
|
||||
# configure logging not to communicate about fnmatch misses
|
||||
# (they shouldn't be too spammy, but one never knows)
|
||||
log = _log.setup_logging('openstack.cloud.fnmatch')
|
||||
log = _log.setup_logging('openstack.fnmatch')
|
||||
if name_or_id:
|
||||
# name_or_id might already be unicode
|
||||
name_or_id = _make_unicode(name_or_id)
|
||||
|
@ -232,7 +232,7 @@ def find_best_address(addresses, family, public=False, cloud_public=True):
|
||||
pass
|
||||
# Give up and return the first - none work as far as we can tell
|
||||
if do_check:
|
||||
log = _log.setup_logging('shade')
|
||||
log = _log.setup_logging('openstack')
|
||||
log.debug(
|
||||
'The cloud returned multiple addresses, and none of them seem'
|
||||
' to work. That might be what you wanted, but we have no clue'
|
||||
@ -381,7 +381,7 @@ def _get_supplemental_addresses(cloud, server):
|
||||
# This SHOULD return one and only one FIP - but doing
|
||||
# it as a search/list lets the logic work regardless
|
||||
if fip['fixed_ip_address'] not in fixed_ip_mapping:
|
||||
log = _log.setup_logging('shade')
|
||||
log = _log.setup_logging('openstack')
|
||||
log.debug(
|
||||
"The cloud returned floating ip %(fip)s attached"
|
||||
" to server %(server)s but the fixed ip associated"
|
||||
|
@ -152,7 +152,7 @@ class OpenStackCloud(_normalize.Normalizer):
|
||||
if log_inner_exceptions:
|
||||
OpenStackCloudException.log_inner_exceptions = True
|
||||
|
||||
self.log = _log.setup_logging('openstack.cloud')
|
||||
self.log = _log.setup_logging('openstack')
|
||||
|
||||
if not cloud_config:
|
||||
config = openstack.config.OpenStackConfig(
|
||||
|
@ -69,7 +69,7 @@ class CloudRegion(object):
|
||||
self.name = name
|
||||
self.region_name = region_name
|
||||
self.config = config
|
||||
self.log = _log.setup_logging(__name__)
|
||||
self.log = _log.setup_logging('openstack.config')
|
||||
self._force_ipv4 = force_ipv4
|
||||
self._auth = auth_plugin
|
||||
self._openstack_config = openstack_config
|
||||
|
@ -182,7 +182,7 @@ class OpenStackConfig(object):
|
||||
pw_func=None, session_constructor=None,
|
||||
app_name=None, app_version=None,
|
||||
load_yaml_config=True):
|
||||
self.log = _log.setup_logging(__name__)
|
||||
self.log = _log.setup_logging('openstack.config')
|
||||
self._session_constructor = session_constructor
|
||||
self._app_name = app_name
|
||||
self._app_version = app_version
|
||||
|
@ -75,22 +75,20 @@ try to find it and if that fails, you would create it::
|
||||
|
||||
"""
|
||||
import importlib
|
||||
import logging
|
||||
import sys
|
||||
|
||||
import keystoneauth1.exceptions
|
||||
import os_service_types
|
||||
from six.moves import urllib
|
||||
|
||||
from openstack import _log
|
||||
import openstack.config
|
||||
from openstack.config import cloud_region
|
||||
from openstack import exceptions
|
||||
from openstack import proxy
|
||||
from openstack import proxy2
|
||||
from openstack import task_manager
|
||||
from openstack import utils
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = _log.setup_logging('openstack')
|
||||
|
||||
|
||||
def from_config(cloud=None, config=None, options=None, **kwargs):
|
||||
@ -119,9 +117,6 @@ def from_config(cloud=None, config=None, options=None, **kwargs):
|
||||
config = openstack.config.OpenStackConfig().get_one(
|
||||
cloud=cloud, argparse=options)
|
||||
|
||||
if config.debug:
|
||||
utils.enable_logging(True, stream=sys.stdout)
|
||||
|
||||
return Connection(config=config)
|
||||
|
||||
|
||||
|
@ -11,16 +11,16 @@
|
||||
# under the License.
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
import jsonpatch
|
||||
|
||||
from openstack import _log
|
||||
from openstack import exceptions
|
||||
from openstack.image import image_service
|
||||
from openstack import resource2
|
||||
from openstack import utils
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = _log.setup_logging('openstack')
|
||||
|
||||
|
||||
class Image(resource2.Resource):
|
||||
|
@ -52,8 +52,8 @@ The resulting preference print out would look something like::
|
||||
"""
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
from openstack import _log
|
||||
from openstack.baremetal import baremetal_service
|
||||
from openstack.block_storage import block_storage_service
|
||||
from openstack.clustering import clustering_service
|
||||
@ -72,7 +72,7 @@ from openstack.object_store import object_store_service
|
||||
from openstack.orchestration import orchestration_service
|
||||
from openstack.workflow import workflow_service
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger = _log.setup_logging('openstack')
|
||||
|
||||
|
||||
class Profile(object):
|
||||
|
@ -22,10 +22,10 @@ import time
|
||||
import keystoneauth1.exceptions
|
||||
import six
|
||||
|
||||
import openstack._log
|
||||
from openstack import exceptions
|
||||
from openstack import utils
|
||||
|
||||
_log = utils.setup_logging(__name__)
|
||||
_log = openstack._log.setup_logging('openstack.task_manager')
|
||||
|
||||
|
||||
class Task(object):
|
||||
|
@ -272,7 +272,7 @@ class TestImage(testtools.TestCase):
|
||||
|
||||
self.sess.get.side_effect = [resp1, resp2]
|
||||
|
||||
with self.assertLogs(logger=image.__name__, level="WARNING") as log:
|
||||
with self.assertLogs(logger='openstack', level="WARNING") as log:
|
||||
rv = sot.download(self.sess)
|
||||
|
||||
self.assertEqual(len(log.records), 1,
|
||||
|
@ -10,67 +10,83 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import mock
|
||||
import sys
|
||||
import testtools
|
||||
|
||||
import fixtures
|
||||
|
||||
from openstack import utils
|
||||
|
||||
|
||||
class Test_enable_logging(testtools.TestCase):
|
||||
|
||||
def _console_tests(self, fake_logging, level, debug, stream):
|
||||
the_logger = mock.Mock()
|
||||
fake_logging.getLogger.return_value = the_logger
|
||||
def setUp(self):
|
||||
super(Test_enable_logging, self).setUp()
|
||||
self.openstack_logger = mock.Mock()
|
||||
self.openstack_logger.handlers = []
|
||||
self.ksa_logger_1 = mock.Mock()
|
||||
self.ksa_logger_1.handlers = []
|
||||
self.ksa_logger_2 = mock.Mock()
|
||||
self.ksa_logger_2.handlers = []
|
||||
self.ksa_logger_3 = mock.Mock()
|
||||
self.ksa_logger_3.handlers = []
|
||||
self.fake_get_logger = mock.Mock()
|
||||
self.fake_get_logger.side_effect = [
|
||||
self.openstack_logger,
|
||||
self.ksa_logger_1,
|
||||
self.ksa_logger_2,
|
||||
self.ksa_logger_3
|
||||
]
|
||||
self.useFixture(
|
||||
fixtures.MonkeyPatch('logging.getLogger', self.fake_get_logger))
|
||||
|
||||
def _console_tests(self, level, debug, stream):
|
||||
|
||||
utils.enable_logging(debug=debug, stream=stream)
|
||||
|
||||
self.assertEqual(the_logger.addHandler.call_count, 2)
|
||||
the_logger.setLevel.assert_called_with(level)
|
||||
self.assertEqual(self.openstack_logger.addHandler.call_count, 1)
|
||||
self.openstack_logger.setLevel.assert_called_with(level)
|
||||
|
||||
def _file_tests(self, fake_logging, level, debug):
|
||||
the_logger = mock.Mock()
|
||||
fake_logging.getLogger.return_value = the_logger
|
||||
def _file_tests(self, level, debug):
|
||||
file_handler = mock.Mock()
|
||||
self.useFixture(
|
||||
fixtures.MonkeyPatch('logging.FileHandler', file_handler))
|
||||
fake_path = "fake/path.log"
|
||||
|
||||
utils.enable_logging(debug=debug, path=fake_path)
|
||||
|
||||
fake_logging.FileHandler.assert_called_with(fake_path)
|
||||
self.assertEqual(the_logger.addHandler.call_count, 2)
|
||||
the_logger.setLevel.assert_called_with(level)
|
||||
file_handler.assert_called_with(fake_path)
|
||||
self.assertEqual(self.openstack_logger.addHandler.call_count, 1)
|
||||
self.openstack_logger.setLevel.assert_called_with(level)
|
||||
|
||||
def test_none(self):
|
||||
self.assertRaises(
|
||||
ValueError, utils.enable_logging,
|
||||
debug=True, path=None, stream=None)
|
||||
utils.enable_logging(debug=True)
|
||||
self.fake_get_logger.assert_has_calls([])
|
||||
self.openstack_logger.setLevel.assert_called_with(logging.DEBUG)
|
||||
self.assertEqual(self.openstack_logger.addHandler.call_count, 1)
|
||||
self.assertIsInstance(
|
||||
self.openstack_logger.addHandler.call_args_list[0][0][0],
|
||||
logging.StreamHandler)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_debug_console_stderr(self, fake_logging):
|
||||
self._console_tests(fake_logging,
|
||||
fake_logging.DEBUG, True, sys.stderr)
|
||||
def test_debug_console_stderr(self):
|
||||
self._console_tests(logging.DEBUG, True, sys.stderr)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_warning_console_stderr(self, fake_logging):
|
||||
self._console_tests(fake_logging,
|
||||
fake_logging.WARNING, False, sys.stderr)
|
||||
def test_warning_console_stderr(self):
|
||||
self._console_tests(logging.INFO, False, sys.stderr)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_debug_console_stdout(self, fake_logging):
|
||||
self._console_tests(fake_logging,
|
||||
fake_logging.DEBUG, True, sys.stdout)
|
||||
def test_debug_console_stdout(self):
|
||||
self._console_tests(logging.DEBUG, True, sys.stdout)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_warning_console_stdout(self, fake_logging):
|
||||
self._console_tests(fake_logging,
|
||||
fake_logging.WARNING, False, sys.stdout)
|
||||
def test_warning_console_stdout(self):
|
||||
self._console_tests(logging.INFO, False, sys.stdout)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_debug_file(self, fake_logging):
|
||||
self._file_tests(fake_logging, fake_logging.DEBUG, True)
|
||||
def test_debug_file(self):
|
||||
self._file_tests(logging.DEBUG, True)
|
||||
|
||||
@mock.patch("openstack.utils.logging")
|
||||
def test_warning_file(self, fake_logging):
|
||||
self._file_tests(fake_logging, fake_logging.WARNING, False)
|
||||
def test_warning_file(self):
|
||||
self._file_tests(logging.INFO, False)
|
||||
|
||||
|
||||
class Test_urljoin(testtools.TestCase):
|
||||
|
@ -11,12 +11,13 @@
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import logging
|
||||
import time
|
||||
|
||||
import deprecation
|
||||
|
||||
from openstack import _log
|
||||
# SDK has had enable_logging in utils. Import the symbol here to not break them
|
||||
from openstack._log import enable_logging # noqa
|
||||
from openstack import exceptions
|
||||
from openstack import version
|
||||
|
||||
@ -47,67 +48,6 @@ def deprecated(deprecated_in=None, removed_in=None,
|
||||
details=details)
|
||||
|
||||
|
||||
class NullHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
|
||||
|
||||
def setup_logging(name):
|
||||
'''Get a logging.Logger and make sure there is at least a NullHandler.'''
|
||||
log = logging.getLogger(name)
|
||||
if len(log.handlers) == 0:
|
||||
h = NullHandler()
|
||||
log.addHandler(h)
|
||||
return log
|
||||
|
||||
|
||||
def enable_logging(debug=False, path=None, stream=None):
|
||||
"""Enable logging to a file at path and/or a console stream.
|
||||
|
||||
This function is available for debugging purposes. If you wish to
|
||||
log this package's message in your application, the standard library
|
||||
``logging`` package will receive these messages in any handlers you
|
||||
create.
|
||||
|
||||
:param bool debug: Set this to ``True`` to receive debug messages,
|
||||
which includes HTTP requests and responses,
|
||||
or ``False`` for warning messages.
|
||||
:param str path: If a *path* is specified, logging output will
|
||||
written to that file in addition to sys.stderr.
|
||||
The path is passed to logging.FileHandler,
|
||||
which will append messages the file (and create
|
||||
it if needed).
|
||||
:param stream: One of ``None `` or ``sys.stdout`` or ``sys.stderr``.
|
||||
If it is ``None``, nothing is logged to a stream.
|
||||
If it isn't ``None``, console output is logged
|
||||
to this stream.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if path is None and stream is None:
|
||||
raise ValueError("path and/or stream must be set")
|
||||
|
||||
logger = logging.getLogger('openstack')
|
||||
ksalog = logging.getLogger('keystoneauth')
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s %(levelname)s: %(name)s %(message)s')
|
||||
|
||||
if stream is not None:
|
||||
console = logging.StreamHandler(stream)
|
||||
console.setFormatter(formatter)
|
||||
logger.addHandler(console)
|
||||
ksalog.addHandler(console)
|
||||
|
||||
if path is not None:
|
||||
file_handler = logging.FileHandler(path)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
ksalog.addHandler(file_handler)
|
||||
|
||||
logger.setLevel(logging.DEBUG if debug else logging.WARNING)
|
||||
ksalog.setLevel(logging.DEBUG if debug else logging.WARNING)
|
||||
|
||||
|
||||
def urljoin(*args):
|
||||
"""A custom version of urljoin that simply joins strings into a path.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user