##// END OF EJS Templates
Add ChangeLog symlink, sync up SVN with my local tree (minimal changes), to...
Add ChangeLog symlink, sync up SVN with my local tree (minimal changes), to start new work off SVN.

File last commit:

r0:6f629fcc
r1:b100d442
Show More
Logger.py
185 lines | 6.9 KiB | text/x-python | PythonLexer
# -*- coding: utf-8 -*-
"""
Logger class for IPython's logging facilities.
$Id: Logger.py 430 2004-11-30 08:52:05Z fperez $
"""
#*****************************************************************************
# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#*****************************************************************************
#****************************************************************************
# Modules and globals
from IPython import Release
__author__ = '%s <%s>\n%s <%s>' % \
( Release.authors['Janko'] + Release.authors['Fernando'] )
__license__ = Release.license
# Python standard modules
import os,sys,glob
# Homebrewed
from IPython.genutils import *
#****************************************************************************
# FIXME: The logger class shouldn't be a mixin, it throws too many things into
# the InteractiveShell namespace. Rather make it a standalone tool, and create
# a Logger instance in InteractiveShell that uses it. Doing this will require
# tracking down a *lot* of nasty uses of the Logger attributes in
# InteractiveShell, but will clean up things quite a bit.
class Logger:
"""A Logfile Mixin class with different policies for file creation"""
# FIXME: once this isn't a mixin, log_ns should just be 'namespace', since the
# names won't collide anymore.
def __init__(self,log_ns):
self._i00,self._i,self._ii,self._iii = '','','',''
self.do_full_cache = 0 # FIXME. There's also a do_full.. in OutputCache
self.log_ns = log_ns
# defaults
self.LOGMODE = 'backup'
self.defname = 'logfile'
def create_log(self,header='',fname='',defname='.Logger.log'):
"""Generate a new log-file with a default header"""
if fname:
self.LOG = fname
if self.LOG:
self.logfname = self.LOG
else:
self.logfname = defname
if self.LOGMODE == 'over':
if os.path.isfile(self.logfname):
os.remove(self.logfname)
self.logfile = open(self.logfname,'w')
if self.LOGMODE == 'backup':
if os.path.isfile(self.logfname):
backup_logname = self.logfname+'~'
# Manually remove any old backup, since os.rename may fail
# under Windows.
if os.path.isfile(backup_logname):
os.remove(backup_logname)
os.rename(self.logfname,backup_logname)
self.logfile = open(self.logfname,'w')
elif self.LOGMODE == 'global':
self.logfname = os.path.join(self.home_dir, self.defname)
self.logfile = open(self.logfname, 'a')
self.LOG = self.logfname
elif self.LOGMODE == 'rotate':
if os.path.isfile(self.logfname):
if os.path.isfile(self.logfname+'.001~'):
old = glob.glob(self.logfname+'.*~')
old.sort()
old.reverse()
for f in old:
root, ext = os.path.splitext(f)
num = int(ext[1:-1])+1
os.rename(f, root+'.'+`num`.zfill(3)+'~')
os.rename(self.logfname, self.logfname+'.001~')
self.logfile = open(self.logfname,'w')
elif self.LOGMODE == 'append':
self.logfile = open(self.logfname,'a')
if self.LOGMODE != 'append':
self.logfile.write(header)
self.logfile.flush()
def logstart(self, header='',parameter_s = ''):
if not hasattr(self, 'LOG'):
logfname = self.LOG or parameter_s or './'+self.defname
self.create_log(header,logfname)
elif parameter_s and hasattr(self,'logfname') and \
parameter_s != self.logfname:
self.close_log()
self.create_log(header,parameter_s)
self._dolog = 1
def switch_log(self,val):
"""Switch logging on/off. val should be ONLY 0 or 1."""
if not val in [0,1]:
raise ValueError, \
'Call switch_log ONLY with 0 or 1 as argument, not with:',val
label = {0:'OFF',1:'ON'}
try:
_ = self.logfile
except AttributeError:
print """
Logging hasn't been started yet (use %logstart for that).
%logon/%logoff are for temporarily starting and stopping logging for a logfile
which already exists. But you must first start the logging process with
%logstart (optionally giving a logfile name)."""
else:
if self._dolog == val:
print 'Logging is already',label[val]
else:
print 'Switching logging',label[val]
self._dolog = 1 - self._dolog
def logstate(self):
"""Print a status message about the logger."""
try:
logfile = self.logfname
except:
print 'Logging has not been activated.'
else:
state = self._dolog and 'active' or 'temporarily suspended'
print """
File:\t%s
Mode:\t%s
State:\t%s """ % (logfile,self.LOGMODE,state)
def log(self, line,continuation=None):
"""Write the line to a log and create input cache variables _i*."""
# update the auto _i tables
#print '***logging line',line # dbg
#print '***cache_count', self.outputcache.prompt_count # dbg
input_hist = self.log_ns['_ih']
if not continuation and line:
self._iii = self._ii
self._ii = self._i
self._i = self._i00
# put back the final \n of every input line
self._i00 = line+'\n'
#print 'Logging input:<%s>' % line # dbg
input_hist.append(self._i00)
# hackish access to top-level namespace to create _i1,_i2... dynamically
to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
if self.do_full_cache:
in_num = self.outputcache.prompt_count
# add blank lines if the input cache fell out of sync. This can happen
# for embedded instances which get killed via C-D and then get resumed.
while in_num >= len(input_hist):
input_hist.append('\n')
new_i = '_i%s' % in_num
if continuation:
self._i00 = '%s%s\n' % (self.log_ns[new_i],line)
input_hist[in_num] = self._i00
to_main[new_i] = self._i00
self.log_ns.update(to_main)
if self._dolog and line:
self.logfile.write(line+'\n')
self.logfile.flush()
def close_log(self):
if hasattr(self, 'logfile'):
self.logfile.close()
self.logfname = ''