##// END OF EJS Templates
Bernard Paulus -
Show More
@@ -1,214 +1,217 b''
1 1 """Logger class for IPython's logging facilities.
2 2 """
3 3
4 4 #*****************************************************************************
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
6 6 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #*****************************************************************************
11 11
12 12 #****************************************************************************
13 13 # Modules and globals
14 14
15 15 # Python standard modules
16 16 import glob
17 17 import os
18 18 import time
19 19
20 20 #****************************************************************************
21 21 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
22 22 # ipython and does input cache management. Finish cleanup later...
23 23
24 24 class Logger(object):
25 25 """A Logfile class with different policies for file creation"""
26 26
27 27 def __init__(self, home_dir, logfname='Logger.log', loghead='',
28 28 logmode='over'):
29 29
30 30 # this is the full ipython instance, we need some attributes from it
31 31 # which won't exist until later. What a mess, clean up later...
32 32 self.home_dir = home_dir
33 33
34 34 self.logfname = logfname
35 35 self.loghead = loghead
36 36 self.logmode = logmode
37 37 self.logfile = None
38 38
39 39 # Whether to log raw or processed input
40 40 self.log_raw_input = False
41 41
42 42 # whether to also log output
43 43 self.log_output = False
44 44
45 45 # whether to put timestamps before each log entry
46 46 self.timestamp = False
47 47
48 48 # activity control flags
49 49 self.log_active = False
50 50
51 51 # logmode is a validated property
52 52 def _set_mode(self,mode):
53 53 if mode not in ['append','backup','global','over','rotate']:
54 54 raise ValueError,'invalid log mode %s given' % mode
55 55 self._logmode = mode
56 56
57 57 def _get_mode(self):
58 58 return self._logmode
59 59
60 60 logmode = property(_get_mode,_set_mode)
61 61
62 62 def logstart(self,logfname=None,loghead=None,logmode=None,
63 63 log_output=False,timestamp=False,log_raw_input=False):
64 64 """Generate a new log-file with a default header.
65 65
66 66 Raises RuntimeError if the log has already been started"""
67 67
68 68 if self.logfile is not None:
69 69 raise RuntimeError('Log file is already active: %s' %
70 70 self.logfname)
71 71
72 72 # The parameters can override constructor defaults
73 73 if logfname is not None: self.logfname = logfname
74 74 if loghead is not None: self.loghead = loghead
75 75 if logmode is not None: self.logmode = logmode
76 76
77 77 # Parameters not part of the constructor
78 78 self.timestamp = timestamp
79 79 self.log_output = log_output
80 80 self.log_raw_input = log_raw_input
81 81
82 82 # init depending on the log mode requested
83 83 isfile = os.path.isfile
84 84 logmode = self.logmode
85 85
86 86 if logmode == 'append':
87 87 self.logfile = open(self.logfname,'a')
88 88
89 89 elif logmode == 'backup':
90 90 if isfile(self.logfname):
91 91 backup_logname = self.logfname+'~'
92 92 # Manually remove any old backup, since os.rename may fail
93 93 # under Windows.
94 94 if isfile(backup_logname):
95 95 os.remove(backup_logname)
96 96 os.rename(self.logfname,backup_logname)
97 97 self.logfile = open(self.logfname,'w')
98 98
99 99 elif logmode == 'global':
100 100 self.logfname = os.path.join(self.home_dir,self.logfname)
101 101 self.logfile = open(self.logfname, 'a')
102 102
103 103 elif logmode == 'over':
104 104 if isfile(self.logfname):
105 105 os.remove(self.logfname)
106 106 self.logfile = open(self.logfname,'w')
107 107
108 108 elif logmode == 'rotate':
109 109 if isfile(self.logfname):
110 110 if isfile(self.logfname+'.001~'):
111 111 old = glob.glob(self.logfname+'.*~')
112 112 old.sort()
113 113 old.reverse()
114 114 for f in old:
115 115 root, ext = os.path.splitext(f)
116 116 num = int(ext[1:-1])+1
117 117 os.rename(f, root+'.'+`num`.zfill(3)+'~')
118 118 os.rename(self.logfname, self.logfname+'.001~')
119 119 self.logfile = open(self.logfname,'w')
120 120
121 121 if logmode != 'append':
122 122 self.logfile.write(self.loghead)
123 123
124 124 self.logfile.flush()
125 125 self.log_active = True
126 126
127 127 def switch_log(self,val):
128 128 """Switch logging on/off. val should be ONLY a boolean."""
129 129
130 130 if val not in [False,True,0,1]:
131 131 raise ValueError, \
132 132 'Call switch_log ONLY with a boolean argument, not with:',val
133 133
134 134 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
135 135
136 136 if self.logfile is None:
137 137 print """
138 138 Logging hasn't been started yet (use logstart for that).
139 139
140 140 %logon/%logoff are for temporarily starting and stopping logging for a logfile
141 141 which already exists. But you must first start the logging process with
142 142 %logstart (optionally giving a logfile name)."""
143 143
144 144 else:
145 145 if self.log_active == val:
146 146 print 'Logging is already',label[val]
147 147 else:
148 148 print 'Switching logging',label[val]
149 149 self.log_active = not self.log_active
150 150 self.log_active_out = self.log_active
151 151
152 152 def logstate(self):
153 153 """Print a status message about the logger."""
154 154 if self.logfile is None:
155 155 print 'Logging has not been activated.'
156 156 else:
157 157 state = self.log_active and 'active' or 'temporarily suspended'
158 158 print 'Filename :',self.logfname
159 159 print 'Mode :',self.logmode
160 160 print 'Output logging :',self.log_output
161 161 print 'Raw input log :',self.log_raw_input
162 162 print 'Timestamping :',self.timestamp
163 163 print 'State :',state
164 164
165 165 def log(self, line_mod, line_ori):
166 166 """Write the sources to a log.
167 167
168 168 Inputs:
169 169
170 170 - line_mod: possibly modified input, such as the transformations made
171 171 by input prefilters or input handlers of various kinds. This should
172 172 always be valid Python.
173 173
174 174 - line_ori: unmodified input line from the user. This is not
175 175 necessarily valid Python.
176 176 """
177 177
178 178 # Write the log line, but decide which one according to the
179 179 # log_raw_input flag, set when the log is started.
180 180 if self.log_raw_input:
181 181 self.log_write(line_ori)
182 182 else:
183 183 self.log_write(line_mod)
184 184
185 185 def log_write(self, data, kind='input'):
186 186 """Write data to the log file, if active"""
187 187
188 188 #print 'data: %r' % data # dbg
189 189 if self.log_active and data:
190 190 write = self.logfile.write
191 191 if kind=='input':
192 192 if self.timestamp:
193 193 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
194 194 time.localtime()))
195 195 write(data)
196 196 elif kind=='output' and self.log_output:
197 197 odata = '\n'.join(['#[Out]# %s' % s
198 198 for s in data.splitlines()])
199 199 write('%s\n' % odata)
200 200 self.logfile.flush()
201 201
202 202 def logstop(self):
203 203 """Fully stop logging and close log file.
204 204
205 205 In order to start logging again, a new logstart() call needs to be
206 206 made, possibly (though not necessarily) with a new filename, mode and
207 207 other options."""
208 208
209 self.logfile.close()
210 self.logfile = None
209 if self.logfile is not None:
210 self.logfile.close()
211 self.logfile = None
212 else:
213 print "Logging hadn't been started."
211 214 self.log_active = False
212 215
213 216 # For backwards compatibility, in case anyone was using this.
214 217 close_log = logstop
General Comments 0
You need to be logged in to leave comments. Login now