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