##// END OF EJS Templates
BUG Move setting of log_active flag down...
Luis Pedro Coelho -
Show More
@@ -1,215 +1,214
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 self.log_active = True
73
74 72 # The parameters can override constructor defaults
75 73 if logfname is not None: self.logfname = logfname
76 74 if loghead is not None: self.loghead = loghead
77 75 if logmode is not None: self.logmode = logmode
78 76
79 77 # Parameters not part of the constructor
80 78 self.timestamp = timestamp
81 79 self.log_output = log_output
82 80 self.log_raw_input = log_raw_input
83 81
84 82 # init depending on the log mode requested
85 83 isfile = os.path.isfile
86 84 logmode = self.logmode
87 85
88 86 if logmode == 'append':
89 87 self.logfile = open(self.logfname,'a')
90 88
91 89 elif logmode == 'backup':
92 90 if isfile(self.logfname):
93 91 backup_logname = self.logfname+'~'
94 92 # Manually remove any old backup, since os.rename may fail
95 93 # under Windows.
96 94 if isfile(backup_logname):
97 95 os.remove(backup_logname)
98 96 os.rename(self.logfname,backup_logname)
99 97 self.logfile = open(self.logfname,'w')
100 98
101 99 elif logmode == 'global':
102 100 self.logfname = os.path.join(self.home_dir,self.logfname)
103 101 self.logfile = open(self.logfname, 'a')
104 102
105 103 elif logmode == 'over':
106 104 if isfile(self.logfname):
107 105 os.remove(self.logfname)
108 106 self.logfile = open(self.logfname,'w')
109 107
110 108 elif logmode == 'rotate':
111 109 if isfile(self.logfname):
112 110 if isfile(self.logfname+'.001~'):
113 111 old = glob.glob(self.logfname+'.*~')
114 112 old.sort()
115 113 old.reverse()
116 114 for f in old:
117 115 root, ext = os.path.splitext(f)
118 116 num = int(ext[1:-1])+1
119 117 os.rename(f, root+'.'+`num`.zfill(3)+'~')
120 118 os.rename(self.logfname, self.logfname+'.001~')
121 119 self.logfile = open(self.logfname,'w')
122 120
123 121 if logmode != 'append':
124 122 self.logfile.write(self.loghead)
125 123
126 124 self.logfile.flush()
125 self.log_active = True
127 126
128 127 def switch_log(self,val):
129 128 """Switch logging on/off. val should be ONLY a boolean."""
130 129
131 130 if val not in [False,True,0,1]:
132 131 raise ValueError, \
133 132 'Call switch_log ONLY with a boolean argument, not with:',val
134 133
135 134 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
136 135
137 136 if self.logfile is None:
138 137 print """
139 138 Logging hasn't been started yet (use logstart for that).
140 139
141 140 %logon/%logoff are for temporarily starting and stopping logging for a logfile
142 141 which already exists. But you must first start the logging process with
143 142 %logstart (optionally giving a logfile name)."""
144 143
145 144 else:
146 145 if self.log_active == val:
147 146 print 'Logging is already',label[val]
148 147 else:
149 148 print 'Switching logging',label[val]
150 149 self.log_active = not self.log_active
151 150 self.log_active_out = self.log_active
152 151
153 152 def logstate(self):
154 153 """Print a status message about the logger."""
155 154 if self.logfile is None:
156 155 print 'Logging has not been activated.'
157 156 else:
158 157 state = self.log_active and 'active' or 'temporarily suspended'
159 158 print 'Filename :',self.logfname
160 159 print 'Mode :',self.logmode
161 160 print 'Output logging :',self.log_output
162 161 print 'Raw input log :',self.log_raw_input
163 162 print 'Timestamping :',self.timestamp
164 163 print 'State :',state
165 164
166 165 def log(self, line_mod, line_ori):
167 166 """Write the sources to a log.
168 167
169 168 Inputs:
170 169
171 170 - line_mod: possibly modified input, such as the transformations made
172 171 by input prefilters or input handlers of various kinds. This should
173 172 always be valid Python.
174 173
175 174 - line_ori: unmodified input line from the user. This is not
176 175 necessarily valid Python.
177 176 """
178 177
179 178 # Write the log line, but decide which one according to the
180 179 # log_raw_input flag, set when the log is started.
181 180 if self.log_raw_input:
182 181 self.log_write(line_ori)
183 182 else:
184 183 self.log_write(line_mod)
185 184
186 185 def log_write(self, data, kind='input'):
187 186 """Write data to the log file, if active"""
188 187
189 188 #print 'data: %r' % data # dbg
190 189 if self.log_active and data:
191 190 write = self.logfile.write
192 191 if kind=='input':
193 192 if self.timestamp:
194 193 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
195 194 time.localtime()))
196 195 write(data)
197 196 elif kind=='output' and self.log_output:
198 197 odata = '\n'.join(['#[Out]# %s' % s
199 198 for s in data.splitlines()])
200 199 write('%s\n' % odata)
201 200 self.logfile.flush()
202 201
203 202 def logstop(self):
204 203 """Fully stop logging and close log file.
205 204
206 205 In order to start logging again, a new logstart() call needs to be
207 206 made, possibly (though not necessarily) with a new filename, mode and
208 207 other options."""
209 208
210 209 self.logfile.close()
211 210 self.logfile = None
212 211 self.log_active = False
213 212
214 213 # For backwards compatibility, in case anyone was using this.
215 214 close_log = logstop
General Comments 0
You need to be logged in to leave comments. Login now