1"""Implementation of magic functions for IPython's own logging. 2""" 3#----------------------------------------------------------------------------- 4# Copyright (c) 2012 The IPython Development Team. 5# 6# Distributed under the terms of the Modified BSD License. 7# 8# The full license is in the file COPYING.txt, distributed with this software. 9#----------------------------------------------------------------------------- 10 11#----------------------------------------------------------------------------- 12# Imports 13#----------------------------------------------------------------------------- 14 15# Stdlib 16import os 17import sys 18 19# Our own packages 20from IPython.core.magic import Magics, magics_class, line_magic 21from warnings import warn 22from IPython.utils.py3compat import str_to_unicode 23 24#----------------------------------------------------------------------------- 25# Magic implementation classes 26#----------------------------------------------------------------------------- 27 28@magics_class 29class LoggingMagics(Magics): 30 """Magics related to all logging machinery.""" 31 32 @line_magic 33 def logstart(self, parameter_s=''): 34 """Start logging anywhere in a session. 35 36 %logstart [-o|-r|-t] [log_name [log_mode]] 37 38 If no name is given, it defaults to a file named 'ipython_log.py' in your 39 current directory, in 'rotate' mode (see below). 40 41 '%logstart name' saves to file 'name' in 'backup' mode. It saves your 42 history up to that point and then continues logging. 43 44 %logstart takes a second optional parameter: logging mode. This can be one 45 of (note that the modes are given unquoted): 46 47 append 48 Keep logging at the end of any existing file. 49 50 backup 51 Rename any existing file to name~ and start name. 52 53 global 54 Append to a single logfile in your home directory. 55 56 over 57 Overwrite any existing log. 58 59 rotate 60 Create rotating logs: name.1~, name.2~, etc. 61 62 Options: 63 64 -o 65 log also IPython's output. In this mode, all commands which 66 generate an Out[NN] prompt are recorded to the logfile, right after 67 their corresponding input line. The output lines are always 68 prepended with a '#[Out]# ' marker, so that the log remains valid 69 Python code. 70 71 Since this marker is always the same, filtering only the output from 72 a log is very easy, using for example a simple awk call:: 73 74 awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py 75 76 -r 77 log 'raw' input. Normally, IPython's logs contain the processed 78 input, so that user lines are logged in their final form, converted 79 into valid Python. For example, %Exit is logged as 80 _ip.magic("Exit"). If the -r flag is given, all input is logged 81 exactly as typed, with no transformations applied. 82 83 -t 84 put timestamps before each input line logged (these are put in 85 comments). 86 """ 87 88 opts,par = self.parse_options(parameter_s,'ort') 89 log_output = 'o' in opts 90 log_raw_input = 'r' in opts 91 timestamp = 't' in opts 92 93 logger = self.shell.logger 94 95 # if no args are given, the defaults set in the logger constructor by 96 # ipython remain valid 97 if par: 98 try: 99 logfname,logmode = par.split() 100 except: 101 logfname = par 102 logmode = 'backup' 103 else: 104 logfname = logger.logfname 105 logmode = logger.logmode 106 # put logfname into rc struct as if it had been called on the command 107 # line, so it ends up saved in the log header Save it in case we need 108 # to restore it... 109 old_logfile = self.shell.logfile 110 if logfname: 111 logfname = os.path.expanduser(logfname) 112 self.shell.logfile = logfname 113 114 loghead = u'# IPython log file\n\n' 115 try: 116 logger.logstart(logfname, loghead, logmode, log_output, timestamp, 117 log_raw_input) 118 except: 119 self.shell.logfile = old_logfile 120 warn("Couldn't start log: %s" % sys.exc_info()[1]) 121 else: 122 # log input history up to this point, optionally interleaving 123 # output if requested 124 125 if timestamp: 126 # disable timestamping for the previous history, since we've 127 # lost those already (no time machine here). 128 logger.timestamp = False 129 130 if log_raw_input: 131 input_hist = self.shell.history_manager.input_hist_raw 132 else: 133 input_hist = self.shell.history_manager.input_hist_parsed 134 135 if log_output: 136 log_write = logger.log_write 137 output_hist = self.shell.history_manager.output_hist 138 for n in range(1,len(input_hist)-1): 139 log_write(input_hist[n].rstrip() + u'\n') 140 if n in output_hist: 141 log_write(str_to_unicode(repr(output_hist[n])),'output') 142 else: 143 logger.log_write(u'\n'.join(input_hist[1:])) 144 logger.log_write(u'\n') 145 if timestamp: 146 # re-enable timestamping 147 logger.timestamp = True 148 149 print ('Activating auto-logging. ' 150 'Current session state plus future input saved.') 151 logger.logstate() 152 153 @line_magic 154 def logstop(self, parameter_s=''): 155 """Fully stop logging and close log file. 156 157 In order to start logging again, a new %logstart call needs to be made, 158 possibly (though not necessarily) with a new filename, mode and other 159 options.""" 160 self.shell.logger.logstop() 161 162 @line_magic 163 def logoff(self, parameter_s=''): 164 """Temporarily stop logging. 165 166 You must have previously started logging.""" 167 self.shell.logger.switch_log(0) 168 169 @line_magic 170 def logon(self, parameter_s=''): 171 """Restart logging. 172 173 This function is for restarting logging which you've temporarily 174 stopped with %logoff. For starting logging for the first time, you 175 must use the %logstart function, which allows you to specify an 176 optional log filename.""" 177 178 self.shell.logger.switch_log(1) 179 180 @line_magic 181 def logstate(self, parameter_s=''): 182 """Print the status of the logging system.""" 183 184 self.shell.logger.logstate() 185