logging.py
184 lines
| 6.4 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r6966 | """Implementation of magic functions for IPython's own logging. | ||
""" | ||||
#----------------------------------------------------------------------------- | ||||
# Copyright (c) 2012 The IPython Development Team. | ||||
# | ||||
# Distributed under the terms of the Modified BSD License. | ||||
# | ||||
# The full license is in the file COPYING.txt, distributed with this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
# Stdlib | ||||
import os | ||||
import sys | ||||
# Our own packages | ||||
Fernando Perez
|
r6973 | from IPython.core.magic import Magics, magics_class, line_magic | ||
Pierre Gerold
|
r22092 | from warnings import warn | ||
Thomas Kluyver
|
r7081 | from IPython.utils.py3compat import str_to_unicode | ||
Fernando Perez
|
r6966 | |||
#----------------------------------------------------------------------------- | ||||
# Magic implementation classes | ||||
#----------------------------------------------------------------------------- | ||||
Fernando Perez
|
r6973 | @magics_class | ||
Fernando Perez
|
r6966 | class LoggingMagics(Magics): | ||
"""Magics related to all logging machinery.""" | ||||
@line_magic | ||||
def logstart(self, parameter_s=''): | ||||
"""Start logging anywhere in a session. | ||||
%logstart [-o|-r|-t] [log_name [log_mode]] | ||||
If no name is given, it defaults to a file named 'ipython_log.py' in your | ||||
current directory, in 'rotate' mode (see below). | ||||
'%logstart name' saves to file 'name' in 'backup' mode. It saves your | ||||
history up to that point and then continues logging. | ||||
%logstart takes a second optional parameter: logging mode. This can be one | ||||
Thomas Kluyver
|
r12553 | of (note that the modes are given unquoted): | ||
append | ||||
Keep logging at the end of any existing file. | ||||
backup | ||||
Rename any existing file to name~ and start name. | ||||
global | ||||
Append to a single logfile in your home directory. | ||||
over | ||||
Overwrite any existing log. | ||||
rotate | ||||
Create rotating logs: name.1~, name.2~, etc. | ||||
Fernando Perez
|
r6966 | |||
Options: | ||||
Thomas Kluyver
|
r12553 | -o | ||
log also IPython's output. In this mode, all commands which | ||||
generate an Out[NN] prompt are recorded to the logfile, right after | ||||
their corresponding input line. The output lines are always | ||||
prepended with a '#[Out]# ' marker, so that the log remains valid | ||||
Python code. | ||||
Fernando Perez
|
r6966 | |||
Since this marker is always the same, filtering only the output from | ||||
a log is very easy, using for example a simple awk call:: | ||||
awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py | ||||
Thomas Kluyver
|
r12553 | -r | ||
log 'raw' input. Normally, IPython's logs contain the processed | ||||
input, so that user lines are logged in their final form, converted | ||||
into valid Python. For example, %Exit is logged as | ||||
_ip.magic("Exit"). If the -r flag is given, all input is logged | ||||
exactly as typed, with no transformations applied. | ||||
-t | ||||
put timestamps before each input line logged (these are put in | ||||
comments). | ||||
""" | ||||
Fernando Perez
|
r6966 | |||
opts,par = self.parse_options(parameter_s,'ort') | ||||
log_output = 'o' in opts | ||||
log_raw_input = 'r' in opts | ||||
timestamp = 't' in opts | ||||
logger = self.shell.logger | ||||
# if no args are given, the defaults set in the logger constructor by | ||||
# ipython remain valid | ||||
if par: | ||||
try: | ||||
logfname,logmode = par.split() | ||||
except: | ||||
logfname = par | ||||
logmode = 'backup' | ||||
else: | ||||
logfname = logger.logfname | ||||
logmode = logger.logmode | ||||
# put logfname into rc struct as if it had been called on the command | ||||
# line, so it ends up saved in the log header Save it in case we need | ||||
# to restore it... | ||||
old_logfile = self.shell.logfile | ||||
if logfname: | ||||
logfname = os.path.expanduser(logfname) | ||||
self.shell.logfile = logfname | ||||
Thomas Kluyver
|
r7081 | loghead = u'# IPython log file\n\n' | ||
Fernando Perez
|
r6966 | try: | ||
logger.logstart(logfname, loghead, logmode, log_output, timestamp, | ||||
log_raw_input) | ||||
except: | ||||
self.shell.logfile = old_logfile | ||||
warn("Couldn't start log: %s" % sys.exc_info()[1]) | ||||
else: | ||||
# log input history up to this point, optionally interleaving | ||||
# output if requested | ||||
if timestamp: | ||||
# disable timestamping for the previous history, since we've | ||||
# lost those already (no time machine here). | ||||
logger.timestamp = False | ||||
if log_raw_input: | ||||
input_hist = self.shell.history_manager.input_hist_raw | ||||
else: | ||||
input_hist = self.shell.history_manager.input_hist_parsed | ||||
if log_output: | ||||
log_write = logger.log_write | ||||
output_hist = self.shell.history_manager.output_hist | ||||
for n in range(1,len(input_hist)-1): | ||||
Thomas Kluyver
|
r7081 | log_write(input_hist[n].rstrip() + u'\n') | ||
Fernando Perez
|
r6966 | if n in output_hist: | ||
Thomas Kluyver
|
r7081 | log_write(str_to_unicode(repr(output_hist[n])),'output') | ||
Fernando Perez
|
r6966 | else: | ||
Thomas Kluyver
|
r7081 | logger.log_write(u'\n'.join(input_hist[1:])) | ||
logger.log_write(u'\n') | ||||
Fernando Perez
|
r6966 | if timestamp: | ||
# re-enable timestamping | ||||
logger.timestamp = True | ||||
print ('Activating auto-logging. ' | ||||
'Current session state plus future input saved.') | ||||
logger.logstate() | ||||
@line_magic | ||||
def logstop(self, parameter_s=''): | ||||
"""Fully stop logging and close log file. | ||||
In order to start logging again, a new %logstart call needs to be made, | ||||
possibly (though not necessarily) with a new filename, mode and other | ||||
options.""" | ||||
Thomas Kluyver
|
r7081 | self.shell.logger.logstop() | ||
Fernando Perez
|
r6966 | |||
@line_magic | ||||
def logoff(self, parameter_s=''): | ||||
"""Temporarily stop logging. | ||||
You must have previously started logging.""" | ||||
self.shell.logger.switch_log(0) | ||||
@line_magic | ||||
def logon(self, parameter_s=''): | ||||
"""Restart logging. | ||||
This function is for restarting logging which you've temporarily | ||||
stopped with %logoff. For starting logging for the first time, you | ||||
must use the %logstart function, which allows you to specify an | ||||
optional log filename.""" | ||||
self.shell.logger.switch_log(1) | ||||
@line_magic | ||||
def logstate(self, parameter_s=''): | ||||
"""Print the status of the logging system.""" | ||||
self.shell.logger.logstate() | ||||