Debugging and Logging¶
Changed in version 1.6.0: Bluesky’s use of Python’s logging framework has been completely reworked to follow Python’s documented best practices for libraries.
Bluesky uses Python’s logging framework, which enables sophisticated log management. For common simple cases, including viewing logs in the terminal or writing them to a file, the next section illustrates streamlined, copy/paste-able examples. Users who are familiar with that framework or who need to route logs to multiple destinations may wish to skip ahead to Bluesky’s Logging-Related API.
Useful Snippets¶
Log warnings¶
This is the recommended standard setup.
from bluesky import config_bluesky_logging
config_bluesky_logging()
It will display 'bluesky'
log records of WARNING
level or higher in the
terminal (standard out) with a format tailored to bluesky.
Maximum verbosity¶
If the RunEngine is “hanging,” running slowly, or repeatedly encountering an error, it is useful to know exactly where in the plan the problem is occurring. To follow the RunEngine’s progress through the plan, crank up the verbosity of the logging.
This will display each message from the plan just before the RunEngine processes it, giving a clear indication of when plan execution is stuck.
from bluesky import config_bluesky_logging
config_bluesky_logging(level='DEBUG')
Log to a file¶
This will direct all log messages to a file instead of the terminal (standard out).
from bluesky import config_bluesky_logging
config_bluesky_logging(file='/tmp/bluesky.log', level='DEBUG')
Important
We strongly recommend setting levels on handlers not on loggers.
In previous versions of bluesky, we recommended adjusting the level on the
logger, as in RE.log.setLevel('DEBUG')
. We now recommended
that you avoid setting levels on loggers because it would affect all
handlers downstream, potentially inhibiting some other part of the program
from collecting the records it wants to collect.
Advanced Example¶
The flow of log event information in loggers and handlers is illustrated in the following diagram:
For further reference, see the Python 3 logging howto: https://docs.python.org/3/howto/logging.html#logging-flow
As an illustrative example, we will set up two handlers using the Python logging framework directly, ignoring bluesky’s convenience function.
Suppose we set up a handler aimed at a file:
import logging
file_handler = logging.FileHandler('bluesky.log')
And another aimed at Logstash:
import logstash # requires python-logstash package
logstash_handler = logstash.TCPLogstashHandler(<host>, <port>, version=1)
We can attach the handlers to the bluesky logger, to which all log records created by bluesky propagate:
logger = logging.getLogger('bluesky')
logger.addHandler(logstash_handler)
logger.addHandler(file_filter)
We can set the verbosity of each handler. Suppose want maximum verbosity in the file but only medium verbosity in logstash.
logstash_handler.setLevel('INFO')
file_handler.setLevel('DEBUG')
Finally, ensure that “effective level” of logger
is at least as verbose as
the most verbose handler—in this case, 'DEBUG'
. By default, at import,
its level is not set
In [1]: logging.getLevelName(logger.level)
In [2]: 'NOTSET'
and so it inherits the level of Python’s default
“handler of last resort,” logging.lastResort
, which is 'WARNING'
.
In [3]: logging.getLevelName(logger.getEffectiveLevel())
In [4]: 'WARNING'
In this case we should set it to 'DEBUG'
, to match the most verbose level
of the handler we have added.
logger.setLevel('DEBUG')
This makes DEBUG-level records available to all handlers. Our logstash
handler, set to 'INFO'
, will filter out DEBUG-level records.
To globally disable the generation of any log records at or below a certain
verbosity, which may be helpful for optimizing performance, Python provides
logging.disable()
.