123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- """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
- from IPython.core.magic import Magics, magics_class, line_magic
- from warnings import warn
- from IPython.utils.py3compat import str_to_unicode
- #-----------------------------------------------------------------------------
- # Magic implementation classes
- #-----------------------------------------------------------------------------
- @magics_class
- 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
- 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.
- Options:
- -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.
- 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
- -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).
- """
- 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
- loghead = u'# IPython log file\n\n'
- 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):
- log_write(input_hist[n].rstrip() + u'\n')
- if n in output_hist:
- log_write(str_to_unicode(repr(output_hist[n])),'output')
- else:
- logger.log_write(u'\n'.join(input_hist[1:]))
- logger.log_write(u'\n')
- 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."""
- self.shell.logger.logstop()
- @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()
|