mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
Merged revisions 59323-59332 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r59324 | georg.brandl | 2007-12-04 17:10:02 +0100 (Tue, 04 Dec 2007) | 3 lines Add "Python on Unix" document, mostly written for GHOP by Shriphani Palakodety. ........ r59325 | facundo.batista | 2007-12-04 17:31:53 +0100 (Tue, 04 Dec 2007) | 3 lines fma speedup by avoiding to create a Context. Thanks Mark Dickinson. ........ r59326 | christian.heimes | 2007-12-04 17:36:20 +0100 (Tue, 04 Dec 2007) | 2 lines Added warning that make install may overwrite or masquerade the default python binary. Use make altinstall instead. A native English speaker may want to rephrase the paragraph. ;) ........ r59327 | georg.brandl | 2007-12-04 17:50:28 +0100 (Tue, 04 Dec 2007) | 2 lines Fix duplicate label and a typo. ........ r59329 | georg.brandl | 2007-12-04 18:46:27 +0100 (Tue, 04 Dec 2007) | 2 lines Add tutorial and examples to logging docs, from GHOP student "oscar8thegrouch". ........ r59332 | christian.heimes | 2007-12-04 19:43:19 +0100 (Tue, 04 Dec 2007) | 1 line These optimizations create smaller and a bit faster code on my machine. I've also disabled an optimization that may be dangerous. Intrinsic functions conflict with errno. ........
This commit is contained in:
parent
43f827b9fa
commit
8b0facf89e
5 changed files with 779 additions and 30 deletions
|
|
@ -9,10 +9,6 @@
|
|||
.. sectionauthor:: Vinay Sajip <vinay_sajip@red-dove.com>
|
||||
|
||||
|
||||
.. % These apply to all modules, and may be given more than once:
|
||||
|
||||
|
||||
|
||||
.. index:: pair: Errors; logging
|
||||
|
||||
This module defines functions and classes which implement a flexible error
|
||||
|
|
@ -34,6 +30,400 @@ importance of a logged message by calling an appropriate method of
|
|||
constrained to use these levels: you can specify your own and use a more general
|
||||
:class:`Logger` method, :meth:`log`, which takes an explicit level argument.
|
||||
|
||||
|
||||
Logging tutorial
|
||||
----------------
|
||||
|
||||
The key benefit of having the logging API provided by a standard library module
|
||||
is that all Python modules can participate in logging, so your application log
|
||||
can include messages from third-party modules.
|
||||
|
||||
It is, of course, possible to log messages with different verbosity levels or to
|
||||
different destinations. Support for writing log messages to files, HTTP
|
||||
GET/POST locations, email via SMTP, generic sockets, or OS-specific logging
|
||||
mechnisms are all supported by the standard module. You can also create your
|
||||
own log destination class if you have special requirements not met by any of the
|
||||
built-in classes.
|
||||
|
||||
Simple examples
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. sectionauthor:: Doug Hellmann
|
||||
.. (see <http://blog.doughellmann.com/2007/05/pymotw-logging.html>)
|
||||
|
||||
Most applications are probably going to want to log to a file, so let's start
|
||||
with that case. Using the :func:`basicConfig` function, we can set up the
|
||||
default handler so that debug messages are written to a file::
|
||||
|
||||
import logging
|
||||
LOG_FILENAME = '/tmp/logging_example.out'
|
||||
logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
|
||||
|
||||
logging.debug('This message should go to the log file')
|
||||
|
||||
And now if we open the file and look at what we have, we should find the log
|
||||
message::
|
||||
|
||||
DEBUG:root:This message should go to the log file
|
||||
|
||||
If you run the script repeatedly, the additional log messages are appended to
|
||||
the file. To create a new file each time, you can pass a filemode argument to
|
||||
:func:`basicConfig` with a value of ``'w'``. Rather than managing the file size
|
||||
yourself, though, it is simpler to use a :class:`RotatingFileHandler`::
|
||||
|
||||
import glob
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
||||
LOG_FILENAME = '/tmp/logging_rotatingfile_example.out'
|
||||
|
||||
# Set up a specific logger with our desired output level
|
||||
my_logger = logging.getLogger('MyLogger')
|
||||
my_logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Add the log message handler to the logger
|
||||
handler = logging.handlers.RotatingFileHandler(
|
||||
LOG_FILENAME, maxBytes=20, backupCount=5)
|
||||
|
||||
my_logger.addHandler(handler)
|
||||
|
||||
# Log some messages
|
||||
for i in range(20):
|
||||
my_logger.debug('i = %d' % i)
|
||||
|
||||
# See what files are created
|
||||
logfiles = glob.glob('%s*' % LOG_FILENAME)
|
||||
|
||||
for filename in logfiles:
|
||||
print filename
|
||||
|
||||
The result should be 6 separate files, each with part of the log history for the
|
||||
application::
|
||||
|
||||
/tmp/logging_rotatingfile_example.out
|
||||
/tmp/logging_rotatingfile_example.out.1
|
||||
/tmp/logging_rotatingfile_example.out.2
|
||||
/tmp/logging_rotatingfile_example.out.3
|
||||
/tmp/logging_rotatingfile_example.out.4
|
||||
/tmp/logging_rotatingfile_example.out.5
|
||||
|
||||
The most current file is always :file:`/tmp/logging_rotatingfile_example.out`,
|
||||
and each time it reaches the size limit it is renamed with the suffix
|
||||
``.1``. Each of the existing backup files is renamed to increment the suffix
|
||||
(``.1`` becomes ``.2``, etc.) and the ``.5`` file is erased.
|
||||
|
||||
Obviously this example sets the log length much much too small as an extreme
|
||||
example. You would want to set *maxBytes* to an appropriate value.
|
||||
|
||||
Another useful feature of the logging API is the ability to produce different
|
||||
messages at different log levels. This allows you to instrument your code with
|
||||
debug messages, for example, but turning the log level down so that those debug
|
||||
messages are not written for your production system. The default levels are
|
||||
``CRITICAL``, ``ERROR``, ``WARNING``, ``INFO``, ``DEBUG`` and ``UNSET``.
|
||||
|
||||
The logger, handler, and log message call each specify a level. The log message
|
||||
is only emitted if the handler and logger are configured to emit messages of
|
||||
that level or lower. For example, if a message is ``CRITICAL``, and the logger
|
||||
is set to ``ERROR``, the message is emitted. If a message is a ``WARNING``, and
|
||||
the logger is set to produce only ``ERROR``\s, the message is not emitted::
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
LEVELS = {'debug': logging.DEBUG,
|
||||
'info': logging.INFO,
|
||||
'warning': logging.WARNING,
|
||||
'error': logging.ERROR,
|
||||
'critical': logging.CRITICAL}
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
level_name = sys.argv[1]
|
||||
level = LEVELS.get(level_name, logging.NOTSET)
|
||||
logging.basicConfig(level=level)
|
||||
|
||||
logging.debug('This is a debug message')
|
||||
logging.info('This is an info message')
|
||||
logging.warning('This is a warning message')
|
||||
logging.error('This is an error message')
|
||||
logging.critical('This is a critical error message')
|
||||
|
||||
Run the script with an argument like 'debug' or 'warning' to see which messages
|
||||
show up at different levels::
|
||||
|
||||
$ python logging_level_example.py debug
|
||||
DEBUG:root:This is a debug message
|
||||
INFO:root:This is an info message
|
||||
WARNING:root:This is a warning message
|
||||
ERROR:root:This is an error message
|
||||
CRITICAL:root:This is a critical error message
|
||||
|
||||
$ python logging_level_example.py info
|
||||
INFO:root:This is an info message
|
||||
WARNING:root:This is a warning message
|
||||
ERROR:root:This is an error message
|
||||
CRITICAL:root:This is a critical error message
|
||||
|
||||
You will notice that these log messages all have ``root`` embedded in them. The
|
||||
logging module supports a hierarchy of loggers with different names. An easy
|
||||
way to tell where a specific log message comes from is to use a separate logger
|
||||
object for each of your modules. Each new logger "inherits" the configuration
|
||||
of its parent, and log messages sent to a logger include the name of that
|
||||
logger. Optionally, each logger can be configured differently, so that messages
|
||||
from different modules are handled in different ways. Let's look at a simple
|
||||
example of how to log from different modules so it is easy to trace the source
|
||||
of the message::
|
||||
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
logger1 = logging.getLogger('package1.module1')
|
||||
logger2 = logging.getLogger('package2.module2')
|
||||
|
||||
logger1.warning('This message comes from one module')
|
||||
logger2.warning('And this message comes from another module')
|
||||
|
||||
And the output::
|
||||
|
||||
$ python logging_modules_example.py
|
||||
WARNING:package1.module1:This message comes from one module
|
||||
WARNING:package2.module2:And this message comes from another module
|
||||
|
||||
There are many more options for configuring logging, including different log
|
||||
message formatting options, having messages delivered to multiple destinations,
|
||||
and changing the configuration of a long-running application on the fly using a
|
||||
socket interface. All of these options are covered in depth in the library
|
||||
module documentation.
|
||||
|
||||
Loggers
|
||||
^^^^^^^
|
||||
|
||||
The logging library takes a modular approach and offers the several categories
|
||||
of components: loggers, handlers, filters, and formatters. Loggers expose the
|
||||
interface that application code directly uses. Handlers send the log records to
|
||||
the appropriate destination. Filters provide a finer grained facility for
|
||||
determining which log records to send on to a handler. Formatters specify the
|
||||
layout of the resultant log record.
|
||||
|
||||
:class:`Logger` objects have a threefold job. First, they expose several
|
||||
methods to application code so that applications can log messages at runtime.
|
||||
Second, logger objects determine which log messages to act upon based upon
|
||||
severity (the default filtering facility) or filter objects. Third, logger
|
||||
objects pass along relevant log messages to all interested log handlers.
|
||||
|
||||
The most widely used methods on logger objects fall into two categories:
|
||||
configuration and message sending.
|
||||
|
||||
* :meth:`Logger.setLevel` specifies the lowest-severity log message a logger
|
||||
will handle, where debug is the lowest built-in severity level and critical is
|
||||
the highest built-in severity. For example, if the severity level is info,
|
||||
the logger will handle only info, warning, error, and critical messages and
|
||||
will ignore debug messages.
|
||||
|
||||
* :meth:`Logger.addFilter` and :meth:`Logger.removeFilter` add and remove filter
|
||||
objects from the logger object. This tutorial does not address filters.
|
||||
|
||||
With the logger object configured, the following methods create log messages:
|
||||
|
||||
* :meth:`Logger.debug`, :meth:`Logger.info`, :meth:`Logger.warning`,
|
||||
:meth:`Logger.error`, and :meth:`Logger.critical` all create log records with
|
||||
a message and a level that corresponds to their respective method names. The
|
||||
message is actually a format string, which may contain the standard string
|
||||
substitution syntax of :const:`%s`, :const:`%d`, :const:`%f`, and so on. The
|
||||
rest of their arguments is a list of objects that correspond with the
|
||||
substitution fields in the message. With regard to :const:`**kwargs`, the
|
||||
logging methods care only about a keyword of :const:`exc_info` and use it to
|
||||
determine whether to log exception information.
|
||||
|
||||
* :meth:`Logger.exception` creates a log message similar to
|
||||
:meth:`Logger.error`. The difference is that :meth:`Logger.exception` dumps a
|
||||
stack trace along with it. Call this method only from an exception handler.
|
||||
|
||||
* :meth:`Logger.log` takes a log level as an explicit argument. This is a
|
||||
little more verbose for logging messages than using the log level convenience
|
||||
methods listed above, but this is how to log at custom log levels.
|
||||
|
||||
:func:`getLogger` returns a reference to a logger instance with a name of name
|
||||
if a name is provided, or root if not. The names are period-separated
|
||||
hierarchical structures. Multiple calls to :func:`getLogger` with the same name
|
||||
will return a reference to the same logger object. Loggers that are further
|
||||
down in the hierarchical list are children of loggers higher up in the list.
|
||||
For example, given a logger with a name of ``foo``, loggers with names of
|
||||
``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all children of ``foo``.
|
||||
Child loggers propagate messages up to their parent loggers. Because of this,
|
||||
it is unnecessary to define and configure all the loggers an application uses.
|
||||
It is sufficient to configure a top-level logger and create child loggers as
|
||||
needed.
|
||||
|
||||
|
||||
Handlers
|
||||
^^^^^^^^
|
||||
|
||||
:class:`Handler` objects are responsible for dispatching the appropriate log
|
||||
messages (based on the log messages' severity) to the handler's specified
|
||||
destination. Logger objects can add zero or more handler objects to themselves
|
||||
with an :func:`addHandler` method. As an example scenario, an application may
|
||||
want to send all log messages to a log file, all log messages of error or higher
|
||||
to stdout, and all messages of critical to an email address. This scenario
|
||||
requires three individual handlers where each hander is responsible for sending
|
||||
messages of a specific severity to a specific location.
|
||||
|
||||
The standard library includes quite a few handler types; this tutorial uses only
|
||||
:class:`StreamHandler` and :class:`FileHandler` in its examples.
|
||||
|
||||
There are very few methods in a handler for application developers to concern
|
||||
themselves with. The only handler methods that seem relevant for application
|
||||
developers who are using the built-in handler objects (that is, not creating
|
||||
custom handlers) are the following configuration methods:
|
||||
|
||||
* The :meth:`Handler.setLevel` method, just as in logger objects, specifies the
|
||||
lowest severity that will be dispatched to the appropriate destination. Why
|
||||
are there two :func:`setLevel` methods? The level set in the logger
|
||||
determines which severity of messages it will pass to its handlers. The level
|
||||
set in each handler determines which messages that handler will send on.
|
||||
:func:`setFormatter` selects a Formatter object for this handler to use.
|
||||
|
||||
* :func:`addFilter` and :func:`removeFilter` respectively configure and
|
||||
deconfigure filter objects on handlers.
|
||||
|
||||
Application code should not directly instantiate and use handlers. Instead, the
|
||||
:class:`Handler` class is a base class that defines the interface that all
|
||||
Handlers should have and establishes some default behavior that child classes
|
||||
can use (or override).
|
||||
|
||||
|
||||
Formatters
|
||||
^^^^^^^^^^
|
||||
|
||||
Formatter objects configure the final order, structure, and contents of the log
|
||||
message. Unlike the base logging.Handler class, application code may
|
||||
instantiate formatter classes, although you could likely subclass the formatter
|
||||
if your application needs special behavior. The constructor takes two optional
|
||||
arguments: a message format string and a date format string. If there is no
|
||||
message format string, the default is to use the raw message. If there is no
|
||||
date format string, the default date format is::
|
||||
|
||||
%Y-%m-%d %H:%M:%S
|
||||
|
||||
with the milliseconds tacked on at the end.
|
||||
|
||||
The message format string uses ``%(<dictionary key>)s`` styled string
|
||||
substitution; the possible keys are documented in :ref:`formatter-objects`.
|
||||
|
||||
The following message format string will log the time in a human-readable
|
||||
format, the severity of the message, and the contents of the message, in that
|
||||
order::
|
||||
|
||||
"%(asctime)s - %(levelname)s - %(message)s"
|
||||
|
||||
|
||||
Configuring Logging
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Programmers can configure logging either by creating loggers, handlers, and
|
||||
formatters explicitly in a main module with the configuration methods listed
|
||||
above (using Python code), or by creating a logging config file. The following
|
||||
code is an example of configuring a very simple logger, a console handler, and a
|
||||
simple formatter in a Python module::
|
||||
|
||||
import logging
|
||||
|
||||
# create logger
|
||||
logger = logging.getLogger("simple_example")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
# create console handler and set level to debug
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.DEBUG)
|
||||
# create formatter
|
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
# add formatter to ch
|
||||
ch.setFormatter(formatter)
|
||||
# add ch to logger
|
||||
logger.addHandler(ch)
|
||||
|
||||
# "application" code
|
||||
logger.debug("debug message")
|
||||
logger.info("info message")
|
||||
logger.warn("warn message")
|
||||
logger.error("error message")
|
||||
logger.critical("critical message")
|
||||
|
||||
Running this module from the command line produces the following output::
|
||||
|
||||
$ python simple_logging_module.py
|
||||
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
|
||||
2005-03-19 15:10:26,620 - simple_example - INFO - info message
|
||||
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
|
||||
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
|
||||
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message
|
||||
|
||||
The following Python module creates a logger, handler, and formatter nearly
|
||||
identical to those in the example listed above, with the only difference being
|
||||
the names of the objects::
|
||||
|
||||
import logging
|
||||
import logging.config
|
||||
|
||||
logging.config.fileConfig("logging.conf")
|
||||
|
||||
# create logger
|
||||
logger = logging.getLogger("simpleExample")
|
||||
|
||||
# "application" code
|
||||
logger.debug("debug message")
|
||||
logger.info("info message")
|
||||
logger.warn("warn message")
|
||||
logger.error("error message")
|
||||
logger.critical("critical message")
|
||||
|
||||
Here is the logging.conf file::
|
||||
|
||||
[loggers]
|
||||
keys=root,simpleExample
|
||||
|
||||
[handlers]
|
||||
keys=consoleHandler
|
||||
|
||||
[formatters]
|
||||
keys=simpleFormatter
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
|
||||
[logger_simpleExample]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
qualname=simpleExample
|
||||
propagate=0
|
||||
|
||||
[handler_consoleHandler]
|
||||
class=StreamHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=(sys.stdout,)
|
||||
|
||||
[formatter_simpleFormatter]
|
||||
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
||||
datefmt=
|
||||
|
||||
The output is nearly identical to that of the non-config-file-based example::
|
||||
|
||||
$ python simple_logging_config.py
|
||||
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
|
||||
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
|
||||
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
|
||||
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
|
||||
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message
|
||||
|
||||
You can see that the config file approach has a few advantages over the Python
|
||||
code approach, mainly separation of configuration and code and the ability of
|
||||
noncoders to easily modify the logging properties.
|
||||
|
||||
|
||||
Logging Levels
|
||||
--------------
|
||||
|
||||
The numeric values of logging levels are given in the following table. These are
|
||||
primarily of interest if you want to define your own levels, and need them to
|
||||
have specific values relative to the predefined levels. If you define a level
|
||||
|
|
@ -1446,6 +1836,8 @@ supports sending logging messages to a Web server, using either ``GET`` or
|
|||
Sends the record to the Web server as an URL-encoded dictionary.
|
||||
|
||||
|
||||
.. _formatter-objects:
|
||||
|
||||
Formatter Objects
|
||||
-----------------
|
||||
|
||||
|
|
@ -1654,15 +2046,17 @@ in :mod:`logging` itself) and defining handlers which are declared either in
|
|||
sent as a file suitable for processing by :func:`fileConfig`. Returns a
|
||||
:class:`Thread` instance on which you can call :meth:`start` to start the
|
||||
server, and which you can :meth:`join` when appropriate. To stop the server,
|
||||
call :func:`stopListening`. To send a configuration to the socket, read in the
|
||||
configuration file and send it to the socket as a string of bytes preceded by a
|
||||
four-byte length packed in binary using struct.\ ``pack('>L', n)``.
|
||||
call :func:`stopListening`.
|
||||
|
||||
To send a configuration to the socket, read in the configuration file and
|
||||
send it to the socket as a string of bytes preceded by a four-byte length
|
||||
string packed in binary using ``struct.pack('>L', n)``.
|
||||
|
||||
|
||||
.. function:: stopListening()
|
||||
|
||||
Stops the listening server which was created with a call to :func:`listen`. This
|
||||
is typically called before calling :meth:`join` on the return value from
|
||||
Stops the listening server which was created with a call to :func:`listen`.
|
||||
This is typically called before calling :meth:`join` on the return value from
|
||||
:func:`listen`.
|
||||
|
||||
|
||||
|
|
@ -1671,8 +2065,6 @@ in :mod:`logging` itself) and defining handlers which are declared either in
|
|||
Configuration file format
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. %
|
||||
|
||||
The configuration file format understood by :func:`fileConfig` is based on
|
||||
ConfigParser functionality. The file must contain sections called ``[loggers]``,
|
||||
``[handlers]`` and ``[formatters]`` which identify by name the entities of each
|
||||
|
|
@ -1825,3 +2217,194 @@ The ``class`` entry is optional. It indicates the name of the formatter's class
|
|||
:class:`Formatter` subclass. Subclasses of :class:`Formatter` can present
|
||||
exception tracebacks in an expanded or condensed format.
|
||||
|
||||
|
||||
Configuration server example
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here is an example of a module using the logging configuration server::
|
||||
|
||||
import logging
|
||||
import logging.config
|
||||
import time
|
||||
import os
|
||||
|
||||
# read initial config file
|
||||
logging.config.fileConfig("logging.conf")
|
||||
|
||||
# create and start listener on port 9999
|
||||
t = logging.config.listen(9999)
|
||||
t.start()
|
||||
|
||||
logger = logging.getLogger("simpleExample")
|
||||
|
||||
try:
|
||||
# loop through logging calls to see the difference
|
||||
# new configurations make, until Ctrl+C is pressed
|
||||
while True:
|
||||
logger.debug("debug message")
|
||||
logger.info("info message")
|
||||
logger.warn("warn message")
|
||||
logger.error("error message")
|
||||
logger.critical("critical message")
|
||||
time.sleep(5)
|
||||
except KeyboardInterrupt:
|
||||
# cleanup
|
||||
logging.config.stopListening()
|
||||
t.join()
|
||||
|
||||
And here is a script that takes a filename and sends that file to the server,
|
||||
properly preceded with the binary-encoded length, as the new logging
|
||||
configuration::
|
||||
|
||||
#!/usr/bin/env python
|
||||
import socket, sys, struct
|
||||
|
||||
data_to_send = open(sys.argv[1], "r").read()
|
||||
|
||||
HOST = 'localhost'
|
||||
PORT = 9999
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
print "connecting..."
|
||||
s.connect((HOST, PORT))
|
||||
print "sending config..."
|
||||
s.send(struct.pack(">L", len(data_to_send)))
|
||||
s.send(data_to_send)
|
||||
s.close()
|
||||
print "complete"
|
||||
|
||||
|
||||
More examples
|
||||
-------------
|
||||
|
||||
Multiple handlers and formatters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Loggers are plain Python objects. The :func:`addHandler` method has no minimum
|
||||
or maximum quota for the number of handlers you may add. Sometimes it will be
|
||||
beneficial for an application to log all messages of all severities to a text
|
||||
file while simultaneously logging errors or above to the console. To set this
|
||||
up, simply configure the appropriate handlers. The logging calls in the
|
||||
application code will remain unchanged. Here is a slight modification to the
|
||||
previous simple module-based configuration example::
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("simple_example")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
# create file handler which logs even debug messages
|
||||
fh = logging.FileHandler("spam.log")
|
||||
fh.setLevel(logging.DEBUG)
|
||||
# create console handler with a higher log level
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.ERROR)
|
||||
# create formatter and add it to the handlers
|
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
ch.setFormatter(formatter)
|
||||
fh.setFormatter(formatter)
|
||||
# add the handlers to logger
|
||||
logger.addHandler(ch)
|
||||
logger.addHandler(fh)
|
||||
|
||||
# "application" code
|
||||
logger.debug("debug message")
|
||||
logger.info("info message")
|
||||
logger.warn("warn message")
|
||||
logger.error("error message")
|
||||
logger.critical("critical message")
|
||||
|
||||
Notice that the "application" code does not care about multiple handlers. All
|
||||
that changed was the addition and configuration of a new handler named *fh*.
|
||||
|
||||
The ability to create new handlers with higher- or lower-severity filters can be
|
||||
very helpful when writing and testing an application. Instead of using many
|
||||
``print`` statements for debugging, use ``logger.debug``: Unlike the print
|
||||
statements, which you will have to delete or comment out later, the logger.debug
|
||||
statements can remain intact in the source code and remain dormant until you
|
||||
need them again. At that time, the only change that needs to happen is to
|
||||
modify the severity level of the logger and/or handler to debug.
|
||||
|
||||
|
||||
Using logging in multiple modules
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It was mentioned above that multiple calls to
|
||||
``logging.getLogger('someLogger')`` return a reference to the same logger
|
||||
object. This is true not only within the same module, but also across modules
|
||||
as long as it is in the same Python interpreter process. It is true for
|
||||
references to the same object; additionally, application code can define and
|
||||
configure a parent logger in one module and create (but not configure) a child
|
||||
logger in a separate module, and all logger calls to the child will pass up to
|
||||
the parent. Here is a main module::
|
||||
|
||||
import logging
|
||||
import auxiliary_module
|
||||
|
||||
# create logger with "spam_application"
|
||||
logger = logging.getLogger("spam_application")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
# create file handler which logs even debug messages
|
||||
fh = logging.FileHandler("spam.log")
|
||||
fh.setLevel(logging.DEBUG)
|
||||
# create console handler with a higher log level
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.ERROR)
|
||||
# create formatter and add it to the handlers
|
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
fh.setFormatter(formatter)
|
||||
ch.setFormatter(formatter)
|
||||
# add the handlers to the logger
|
||||
logger.addHandler(fh)
|
||||
logger.addHandler(ch)
|
||||
|
||||
logger.info("creating an instance of auxiliary_module.Auxiliary")
|
||||
a = auxiliary_module.Auxiliary()
|
||||
logger.info("created an instance of auxiliary_module.Auxiliary")
|
||||
logger.info("calling auxiliary_module.Auxiliary.do_something")
|
||||
a.do_something()
|
||||
logger.info("finished auxiliary_module.Auxiliary.do_something")
|
||||
logger.info("calling auxiliary_module.some_function()")
|
||||
auxiliary_module.some_function()
|
||||
logger.info("done with auxiliary_module.some_function()")
|
||||
|
||||
Here is the auxiliary module::
|
||||
|
||||
import logging
|
||||
|
||||
# create logger
|
||||
module_logger = logging.getLogger("spam_application.auxiliary")
|
||||
|
||||
class Auxiliary:
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary")
|
||||
self.logger.info("creating an instance of Auxiliary")
|
||||
def do_something(self):
|
||||
self.logger.info("doing something")
|
||||
a = 1 + 1
|
||||
self.logger.info("done doing something")
|
||||
|
||||
def some_function():
|
||||
module_logger.info("received a call to \"some_function\"")
|
||||
|
||||
The output looks like this::
|
||||
|
||||
2005-03-23 23:47:11,663 - spam_application - INFO -
|
||||
creating an instance of auxiliary_module.Auxiliary
|
||||
2005-03-23 23:47:11,665 - spam_application.auxiliary.Auxiliary - INFO -
|
||||
creating an instance of Auxiliary
|
||||
2005-03-23 23:47:11,665 - spam_application - INFO -
|
||||
created an instance of auxiliary_module.Auxiliary
|
||||
2005-03-23 23:47:11,668 - spam_application - INFO -
|
||||
calling auxiliary_module.Auxiliary.do_something
|
||||
2005-03-23 23:47:11,668 - spam_application.auxiliary.Auxiliary - INFO -
|
||||
doing something
|
||||
2005-03-23 23:47:11,669 - spam_application.auxiliary.Auxiliary - INFO -
|
||||
done doing something
|
||||
2005-03-23 23:47:11,670 - spam_application - INFO -
|
||||
finished auxiliary_module.Auxiliary.do_something
|
||||
2005-03-23 23:47:11,671 - spam_application - INFO -
|
||||
calling auxiliary_module.some_function()
|
||||
2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO -
|
||||
received a call to "some_function"
|
||||
2005-03-23 23:47:11,673 - spam_application - INFO -
|
||||
done with auxiliary_module.some_function()
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ interpreter and things that make working with Python easier.
|
|||
.. toctree::
|
||||
|
||||
cmdline.rst
|
||||
unix.rst
|
||||
windows.rst
|
||||
mac.rst
|
||||
|
||||
|
|
|
|||
151
Doc/using/unix.rst
Normal file
151
Doc/using/unix.rst
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
.. highlightlang:: none
|
||||
|
||||
.. _using-on-unix:
|
||||
|
||||
********************************
|
||||
Using Python on Unix platforms
|
||||
********************************
|
||||
|
||||
.. sectionauthor:: Shriphani Palakodety
|
||||
|
||||
|
||||
Getting and installing the latest version of Python
|
||||
===================================================
|
||||
|
||||
On Linux
|
||||
--------
|
||||
|
||||
Python comes preinstalled on most Linux distributions, and is available as a
|
||||
package on all others. However there are certain features you might want to use
|
||||
that are not available on your distro's package. You can easily compile the
|
||||
latest version of Python from source.
|
||||
|
||||
In the event Python doesn't come preinstalled and isn't in the repositories as
|
||||
well, you can easily make packages for your own distro. Have a look at the
|
||||
following links:
|
||||
|
||||
.. seealso::
|
||||
|
||||
http://www.linux.com/articles/60383
|
||||
for Debian users
|
||||
http://linuxmafia.com/pub/linux/suse-linux-internals/chapter35.html
|
||||
for OpenSuse users
|
||||
http://docs.fedoraproject.org/drafts/rpm-guide-en/ch-creating-rpms.html
|
||||
for Fedora users
|
||||
http://www.slackbook.org/html/package-management-making-packages.html
|
||||
for Slackware users
|
||||
|
||||
|
||||
On FreeBSD and OpenBSD
|
||||
----------------------
|
||||
|
||||
* FreeBSD users, to add the package use::
|
||||
|
||||
pkg_add -r python
|
||||
|
||||
* OpenBSD users use::
|
||||
|
||||
pkg_add ftp://ftp.openbsd.org/pub/OpenBSD/4.2/packages/<insert your architecture here>/python-<version>.tgz
|
||||
|
||||
For example i386 users get the 2.5.1 version of Python using::
|
||||
|
||||
pkg_add ftp://ftp.openbsd.org/pub/OpenBSD/4.2/packages/i386/python-2.5.1p2.tgz
|
||||
|
||||
|
||||
On OpenSolaris
|
||||
--------------
|
||||
|
||||
To install the newest Python versions on OpenSolaris, install blastwave
|
||||
(http://www.blastwave.org/howto.html) and type "pkg_get -i python" at the
|
||||
prompt.
|
||||
|
||||
|
||||
Building Python
|
||||
===============
|
||||
|
||||
If you want to compile CPython yourself, first thing you should do is get the
|
||||
`source <http://python.org/download/source/>`_. You can download either the
|
||||
latest release's source or just grab a fresh `checkout
|
||||
<http://www.python.org/dev/faq/#how-do-i-get-a-checkout-of-the-repository-read-only-and-read-write>`_.
|
||||
|
||||
The build process consists the usual ::
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
invocations. Configuration options and caveats for specific Unix platforms are
|
||||
extensively documented in the :file:`README` file in the root of the Python
|
||||
source tree.
|
||||
|
||||
.. warning::
|
||||
|
||||
``make install`` can overwrite or masquerade the :file:`python` binary.
|
||||
``make altinstall`` is therefore recommended instead of ``make install``
|
||||
since it only installs :file:`{exec_prefix}/bin/python{version}`.
|
||||
|
||||
|
||||
Python-related paths and files
|
||||
==============================
|
||||
|
||||
These are subject to difference depending on local installation conventions;
|
||||
:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``)
|
||||
are installation-dependent and should be interpreted as for GNU software; they
|
||||
may be the same.
|
||||
|
||||
For example, on most Linux systems, the default for both is :file:`/usr`.
|
||||
|
||||
+-----------------------------------------------+------------------------------------------+
|
||||
| File/directory | Meaning |
|
||||
+===============================================+==========================================+
|
||||
| :file:`{exec_prefix}/bin/python` | Recommended location of the interpreter. |
|
||||
+-----------------------------------------------+------------------------------------------+
|
||||
| :file:`{prefix}/lib/python{version}`, | Recommended locations of the directories |
|
||||
| :file:`{exec_prefix}/lib/python{version}` | containing the standard modules. |
|
||||
+-----------------------------------------------+------------------------------------------+
|
||||
| :file:`{prefix}/include/python{version}`, | Recommended locations of the directories |
|
||||
| :file:`{exec_prefix}/include/python{version}` | containing the include files needed for |
|
||||
| | developing Python extensions and |
|
||||
| | embedding the interpreter. |
|
||||
+-----------------------------------------------+------------------------------------------+
|
||||
| :file:`~/.pythonrc.py` | User-specific initialization file loaded |
|
||||
| | by the user module; not used by default |
|
||||
| | or by most applications. |
|
||||
+-----------------------------------------------+------------------------------------------+
|
||||
|
||||
|
||||
Miscellaneous
|
||||
=============
|
||||
|
||||
To easily use Python scripts on Unix, you need to make them executable,
|
||||
e.g. with ::
|
||||
|
||||
$ chmod +x script
|
||||
|
||||
and put an appropriate Shebang line at the top of the script. A good choice is
|
||||
usually ::
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
which searches for the Python interpreter in the whole :envvar:`PATH`. However,
|
||||
some Unices may not have the :program:`env` command, so you may need to hardcode
|
||||
``/usr/bin/python`` as the interpreter path.
|
||||
|
||||
To use shell commands in your python scripts, look at the :mod:`subprocess` module.
|
||||
|
||||
|
||||
Editors
|
||||
=======
|
||||
|
||||
Vim and Emacs are excellent editors which support Python very well. For more
|
||||
information on how to code in python in these editors, look at:
|
||||
|
||||
http://www.vim.org/scripts/script.php?script_id=790
|
||||
http://sourceforge.net/projects/python-mode
|
||||
|
||||
Geany is an excellent IDE with support for a lot of languages. For more
|
||||
information, read: http://geany.uvena.de/
|
||||
|
||||
Komodo edit is another extremely good IDE. It also has support for a lot of
|
||||
languages. For more information, read:
|
||||
http://www.activestate.com/store/productdetail.aspx?prdGuid=20f4ed15-6684-4118-a78b-d37ff4058c5f
|
||||
|
|
@ -260,8 +260,7 @@ Compiling Python on Windows
|
|||
If you want to compile CPython yourself, first thing you should do is get the
|
||||
`source <http://python.org/download/source/>`_. You can download either the
|
||||
latest release's source or just grab a fresh `checkout
|
||||
<http://www.python.org/dev/faq/
|
||||
#how-do-i-get-a-checkout-of-the-repository-read-only-and-read-write>`_.
|
||||
<http://www.python.org/dev/faq/#how-do-i-get-a-checkout-of-the-repository-read-only-and-read-write>`_.
|
||||
|
||||
For Microsoft Visual C++, which is the compiler with which official Python
|
||||
releases are built, the source tree contains solutions/project files. View the
|
||||
|
|
|
|||
|
|
@ -1646,24 +1646,39 @@ class Decimal(object):
|
|||
"""
|
||||
|
||||
other = _convert_other(other, raiseit=True)
|
||||
|
||||
# compute product; raise InvalidOperation if either operand is
|
||||
# a signaling NaN or if the product is zero times infinity.
|
||||
if self._is_special or other._is_special:
|
||||
if context is None:
|
||||
context = getcontext()
|
||||
if self._exp == 'N':
|
||||
return context._raise_error(InvalidOperation, 'sNaN',
|
||||
1, self)
|
||||
if other._exp == 'N':
|
||||
return context._raise_error(InvalidOperation, 'sNaN',
|
||||
1, other)
|
||||
if self._exp == 'n':
|
||||
product = self
|
||||
elif other._exp == 'n':
|
||||
product = other
|
||||
elif self._exp == 'F':
|
||||
if not other:
|
||||
return context._raise_error(InvalidOperation,
|
||||
'INF * 0 in fma')
|
||||
product = Infsign[self._sign ^ other._sign]
|
||||
elif other._exp == 'F':
|
||||
if not self:
|
||||
return context._raise_error(InvalidOperation,
|
||||
'0 * INF in fma')
|
||||
product = Infsign[self._sign ^ other._sign]
|
||||
else:
|
||||
product = _dec_from_triple(self._sign ^ other._sign,
|
||||
str(int(self._int) * int(other._int)),
|
||||
self._exp + other._exp)
|
||||
|
||||
third = _convert_other(third, raiseit=True)
|
||||
|
||||
if context is None:
|
||||
context = getcontext()
|
||||
|
||||
# do self*other in fresh context with no traps and no rounding
|
||||
mul_context = Context(traps=[], flags=[],
|
||||
_rounding_decision=NEVER_ROUND)
|
||||
product = self.__mul__(other, mul_context)
|
||||
|
||||
if mul_context.flags[InvalidOperation]:
|
||||
# reraise in current context
|
||||
return context._raise_error(InvalidOperation,
|
||||
'invalid multiplication in fma',
|
||||
1, product)
|
||||
|
||||
ans = product.__add__(third, context)
|
||||
return ans
|
||||
return product.__add__(third, context)
|
||||
|
||||
def _power_modulo(self, other, modulo, context=None):
|
||||
"""Three argument version of __pow__"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue