【问题标题】:How to log everything that occurs in a Python interactive shell session?如何记录 Python 交互式 shell 会话中发生的所有事情?
【发布时间】:2011-12-24 15:08:18
【问题描述】:

我想实时访问解释器输入以及错误和标准输出。最好将此信息写入文件,以便在输入每个解释器命令后轮询文件以进行更改。例如,给定一个解释器会话:

>>> 5 * 7
35
>>> print("Hello, world!")
Hello, world!
>>> "Hello, world!"
'Hello, world!'

我想在日志文件中看到以下内容:

> 5 * 7
35
> print("Hello, world!")
Hello, world!
> "Hello, world!"
'Hello, world!'

格式不重要;重要的是我可以在文件中搜索关键词以在会话期间触发交互事件。

到目前为止,我为了实现这一目标而学到了什么:

Python 的code 模块允许我创建一个InteractiveConsole 对象,我可以重新定义该raw_input 方法以记录到文件,如下所示:

import code
class LoggedConsole(code.InteractiveConsole):
  def __init__(self, locals):
    super(LoggedConsole, self).__init__(locals)
    self.file = open('consolelog.dat', 'a')

  def __del__(self):
    self.file.close()

  def raw_input(self, prompt=""):
    data = input(prompt)
    self.file.write(data+'\n')
    return data

此外,InteractiveConsole 使用内置的write 方法记录错误,我可以将其重新定义为:

def write(self, data):
  sys.stderr.write(data)
  self.file.write(data+'\n')

我还了解到以下 sn-p 将记录所有标准输出:

class Tee(object):
  def __init__(self):
    self.file = open('consolelog.dat', 'a')
    self.stdout = sys.stdout

  def __del__(self):
    sys.stdout = self.stdout
    self.file.close()

  def write(self, data):
    self.file.write(data)
    self.stdout.write(data)

sys.stdout = Tee()

我(失败的)尝试将这一切结合在一起,然后创建一个LoggedConsole 对象,并在本地传递它Tee

console = LoggedConsole(locals={sys.stdout:LoggedExec()})
console.interact()

(我之前没有通过本地人,所以也许我在这里做错了,但我没有收到错误。)

无论如何,这将打开一个新的交互式控制台,并将记录(关闭后)所有输入和错误,但不输出。我一直在努力解决这个问题,我觉得我已经接近了,但也许还没有。

另外,有没有办法让所有这些都发生在会议期间?目前,所有日志记录都会在会话关闭后进行。

感谢您的宝贵时间,对不起,文字墙。

编辑: 出于可移植性目的,我希望能够在标准 Python 解释器中完成此操作。

编辑2: Jaime 的 sn-p 非常适合记录我需要的所有内容。不过,有什么方法可以让它实时完成,而不是等待会话关闭?

编辑3: 想通了:)。最终的工作 sn-p:

import code
import sys

class Tee(object):
  def __init__(self, log_fname, mode='a'):
    self.log = open(log_fname, mode)

  def __del__(self):
    # Restore sin, so, se
    sys.stdout = sys.__stdout__
    sys.stdir = sys.__stdin__
    sys.stderr = sys.__stderr__
    self.log.close()

  def write(self, data):
    self.log.write(data)
    self.log.flush()
    sys.__stdout__.write(data)
    sys.__stdout__.flush()

  def readline(self):
    s = sys.__stdin__.readline()
    sys.__stdin__.flush()
    self.log.write(s)
    self.log.flush()
    return s

  def flush(foo):
    return

sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')

console = code.InteractiveConsole()
console.interact()

【问题讨论】:

  • 顺便说一句,不确定您的用例是什么,但 ipython notebook 是交互式工作流程的一个很好的补充,以防您还没有看到它。

标签: python logging python-3.x


【解决方案1】:

您可以尝试使用我的日志记录工具。它还不完美,但它解决了我的问题,这似乎与你的相似。

https://github.com/hholst80/loginteractive

它通过使用 LD_PRELOAD 将 stdin.txt(或 $STDIN)通过管道传输到 stdout 来工作。它适用于 python 和 octave,虽然我还没有对它进行太多测试

【讨论】:

    【解决方案2】:

    你可以简单地使用unix脚本命令,试试:

    script -a filename.txt
    python
    >> print("hi")
    hi
    >> exit()
    exit
    

    filename.txt 将记录您在该会话中所做的一切,它看起来像这样:

    Script started on Sat Dec 14 11:18:41 2013
    python
    >> print('hi')
    hi
    >> exit()
    exit
    
    Script done on Sat Dec 14 11:18:59 2013
    

    【讨论】:

      【解决方案3】:

      我只在 python2.7 中测试过这个。我手头没有 3 个。

      import code
      import sys
      
      class Tee(object):
      
        def __init__(self, log_fname, mode='a'):
          self.log = open(log_fname, mode)
      
        def __del__(self):
          # Restore sin, so, se
          sys.stdout = sys.__stdout__
          sys.stdir = sys.__stdin__
          sys.stderr = sys.__stderr__
          self.log.close()
      
        def write(self, data):
          self.log.write(data)
          sys.__stdout__.write(data)
      
        def readline(self):
          s = sys.__stdin__.readline()
          self.log.write(s)
          return s
      
      # Tie the ins and outs to Tee.
      sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')
      
      console = code.InteractiveConsole()
      console.interact()
      

      【讨论】:

      • 这很好用。你知道我怎样才能让它实时登录吗?即不等到会话关闭再写?我在某处读到,调用sys.stdout.flush() 等会做到这一点,但我有点不确定如何实现。感谢您迄今为止的帮助!
      • 想通了。您需要为日志文件和标准输出/输入对象调用flush()。感谢您将我推向正确的方向!
      • 很高兴它对您有所帮助。您应该只需要刷新日志。没有理由刷新标准输出/标准错误。请记住,日志是唯一实际写入文件的内容,因此刷新它就足够了。
      • 我也这么认为,但是(出于某种我不明白的原因)Py 3.2 中的提示无法正确打印,除非我刷新 std 对象。我无法在 2.7 上复制该问题。这就是我使用 3 得到的结果,我猜 :)。
      【解决方案4】:

      参见 Doug Hellmann 的 this Virtualenv article,展示如何记录 iPython 会话:

      如果您习惯以这种方式在交互式提示下工作,但想在关闭会话后记录您所做的事情以供将来参考,您可以使用 IPython 的日志记录功能将会话写入文件。要激活日志,请使用控制命令 %logstart,如清单 5 所示。输出文件是 Python 源文件,因此在您完成实验后很容易将其清理并变成“真正的”模块.

      In [6]: %logstart
      Activating auto-logging. Current session state plus future input saved.
      Filename       : ipython_log.py
      Mode           : rotate
      Output logging : False
      Raw input log  : False
      Timestamping   : False
      State          : active
      
      In [7]: a = 5
      
      In [8]: b = 6
      
      In [9]: c = a * b
      
      In [10]: c
      
      Out[10]: 30
      
      In [11]: d = [ a, b, c]
      
      In [12]: d
      
      Out[12]: [5, 6, 30]
      
      In [13]: %logstop
      

      【讨论】:

      • 感谢参考!不过,我想在标准解释器中完成这项工作。我的目标是为 Python 基础创建一些交互式教程(并在此过程中自学),并且我希望它可以移植,以供可能使用它的朋友使用。
      猜你喜欢
      • 1970-01-01
      • 2011-03-12
      • 1970-01-01
      • 2010-09-11
      • 2010-10-31
      • 1970-01-01
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      相关资源
      最近更新 更多