logging.py 6.4 KB

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