Changeset 345:a62373a28d90 for src/mlx/logger.py
- Timestamp:
- 12/08/12 15:02:57 (11 years ago)
- Branch:
- default
- hg-Phase:
- (<MercurialRepository 1 'hg:/home/ivaradi/mlx/hg' '/'>, 'public')
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/mlx/logger.py
r315 r345 6 6 import sys 7 7 import time 8 import bisect 8 9 9 10 #-------------------------------------------------------------------------------------- … … 28 29 29 30 class Logger(object): 30 """The class with the interface to log the various events.""" 31 """The class with the interface to log the various events. 32 33 It contains a list of entries ordered by their timestamps and their ever 34 increasing IDs.""" 35 36 class Entry(object): 37 """An entry in the log.""" 38 39 # The ID of the next entry to be created 40 _nextID = 1 41 42 def __init__(self, timestamp, text, showTimestamp = True, 43 faultID = None, faultScore = 0, id = None): 44 """Construct the entry.""" 45 if id is None: 46 self._id = self._nextID 47 Logger.Entry._nextID += 1 48 else: 49 self._id = id 50 51 self._timestamp = timestamp 52 self._text = text 53 self._showTimestamp = showTimestamp 54 55 self._faultID = faultID 56 self._faultScore = faultScore 57 58 @property 59 def id(self): 60 """Get the ID of the entry.""" 61 return self._id 62 63 @property 64 def timestamp(self): 65 """Get the timestamp of this entry.""" 66 return self._timestamp 67 68 @property 69 def timestampString(self): 70 """Get the timestamp string of this entry. 71 72 It returns None, if the timestamp of the entry is not visible.""" 73 return util.getTimestampString(self._timestamp) \ 74 if self._showTimestamp else None 75 76 @property 77 def text(self): 78 """Get the text of this entry.""" 79 return self._text 80 81 @property 82 def isFault(self): 83 """Determine if this is a log entry about a fault.""" 84 return self._faultID is not None 85 86 @property 87 def faultID(self): 88 """Get the fault ID of the entry. 89 90 It may be None, if the entry is not a fault entry.""" 91 return self._faultID 92 93 @property 94 def faultScore(self): 95 """Get the fault score of the entry, if it is a fault.""" 96 return self._faultScore 97 98 def copy(self, text = None): 99 """Create a copy of this entry with the given values changed.""" 100 return Logger.Entry(self._timestamp, 101 self._text if text is None else text, 102 showTimestamp = self._showTimestamp, 103 faultID = self._faultID, 104 faultScore = self._faultScore, 105 id = self._id) 106 107 def __cmp__(self, other): 108 """Compare two entries 109 110 First their timestamps are compared, and if those are equal, then 111 their IDs.""" 112 result = cmp(self._timestamp, other.timestamp) 113 if result==0: 114 result = cmp(self._id, other._id) 115 return result 116 117 class Fault(object): 118 """Information about a fault. 119 120 It contains the list of log entries that belong to this fault. The list 121 is ordered so that the first element contains the entry with the 122 highest score, so that it should be easy to find the actual score.""" 123 def __init__(self, entry): 124 """Construct the fault info with the given log entry as its only 125 one.""" 126 self._entries = [entry] 127 128 @property 129 def score(self): 130 """Get the score of this fault, i.e. the score of the entry with 131 the highest score.""" 132 return self._entries[0].faultScore if self._entries else 0 133 134 def addEntry(self, entry): 135 """Add an entry to this fault. 136 137 The entries will be sorted.""" 138 entries = self._entries 139 entries.append(entry) 140 entries.sort(key = Logger.Entry.faultScore, reverse = True) 141 142 def removeEntry(self, entry): 143 """Remove the given entry. 144 145 Returns True if at least one entry remains, False otherwise.""" 146 entries = self._entries 147 for index in range(0, len(entries)): 148 if entry is entries[index]: 149 del entries[index] 150 break 151 152 return len(entries)>0 153 31 154 # FIXME: shall we use const.stage2string() instead? 32 155 _stages = { const.STAGE_BOARDING : "Boarding", … … 42 165 const.STAGE_GOAROUND : "Go-Around", 43 166 const.STAGE_END : "End" } 44 167 45 168 NO_GO_SCORE = 10000 46 169 47 170 def __init__(self, output): 48 171 """Construct the logger.""" 172 self._entries = {} 49 173 self._lines = [] 174 50 175 self._faults = {} 51 self._faultLineIndexes = [] 176 52 177 self._output = output 53 178 … … 55 180 def lines(self): 56 181 """Get the lines of the log.""" 57 return self._lines182 return [(entry.timestampString, entry.text) for entry in self._lines] 58 183 59 184 @property 60 185 def faultLineIndexes(self): 61 """Get the array of the indexes of the log line that contains a 62 fault.""" 63 return self._faultLineIndexes 186 """Get the sorted array of the indexes of those log lines that contain 187 a fault.""" 188 faultLineIndexes = [] 189 lines = self._lines 190 for index in range(0, len(lines)): 191 if lines[index].isFault: 192 faultLineIndexes.append(index) 193 return faultLineIndexes 64 194 65 195 def reset(self): … … 67 197 68 198 The faults logged so far will be cleared.""" 199 self._entries = {} 69 200 self._lines = [] 70 self._faults .clear()71 self._faultLineIndexes = [] 72 73 def message(self, timestamp, msg, isFault = False):74 """Put a simple textual message into the log with the given timestamp.""" 75 timeStr = util.getTimestampString(timestamp)76 return self._ logLine(msg, timeStr, isFault = isFault)77 78 def untimedMessage(self, msg , isFault = False):201 self._faults = {} 202 203 def message(self, timestamp, msg): 204 """Put a simple textual message into the log with the given timestamp. 205 206 Returns an ID of the message so that it could be referred to later.""" 207 return self._addEntry(Logger.Entry(timestamp, msg)) 208 209 def untimedMessage(self, msg): 79 210 """Put an untimed message into the log.""" 80 return self._logLine(msg, isFault = isFault) 211 timestamp = self._lines[-1].timestamp if self._lines else 0 212 return self._addEntry(Logger.Entry(timestamp, msg, 213 showTimestamp = False)) 81 214 82 215 def debug(self, msg): … … 97 230 else const.MESSAGETYPE_INFORMATION 98 231 sendMessage(messageType, "Flight stage: " + s, 3) 99 232 100 233 def fault(self, faultID, timestamp, what, score): 101 234 """Report a fault. … … 104 237 this ID has been reported earlier, it will be reported again only if 105 238 the score is greater than last time. This ID can be, e.g. the checker 106 the report comes from.""" 239 the report comes from. 240 241 Returns an ID of the fault, or -1 if it was not logged.""" 107 242 if faultID in self._faults: 108 if score<=self._faults[faultID] :109 return 110 self._faults[faultID] = score 243 if score<=self._faults[faultID].score: 244 return -1 245 111 246 text = "%s (NO GO)" % (what) if score==Logger.NO_GO_SCORE \ 112 247 else "%s (%.1f)" % (what, score) 113 lineIndex = self.message(timestamp, text, isFault = True) 114 self._faultLineIndexes.append(lineIndex) 248 249 id = self._addEntry(Logger.Entry(timestamp, text, faultID = faultID, 250 faultScore = score)) 251 115 252 (messageType, duration) = (const.MESSAGETYPE_NOGO, 10) \ 116 253 if score==Logger.NO_GO_SCORE \ 117 254 else (const.MESSAGETYPE_FAULT, 5) 118 sendMessage(messageType, text, duration) 255 sendMessage(messageType, text, duration) 256 257 return id 119 258 120 259 def noGo(self, faultID, timestamp, what): 121 260 """Report a No-Go fault.""" 122 self.fault(faultID, timestamp, what, Logger.NO_GO_SCORE)261 return self.fault(faultID, timestamp, what, Logger.NO_GO_SCORE) 123 262 124 263 def getRating(self): 125 264 """Get the rating of the flight so far.""" 126 265 totalScore = 100 127 for (id, score) in self._faults.iteritems(): 266 for fault in self._faults.itervalues(): 267 score = fault.score 128 268 if score==Logger.NO_GO_SCORE: 129 269 return -score … … 132 272 return totalScore 133 273 134 def updateLine(self, index, line): 135 """Update the line at the given index with the given string.""" 136 (timeStr, _line) = self._lines[index] 137 self._lines[index] = (timeStr, line) 138 self._output.updateFlightLogLine(index, timeStr, line) 139 140 def _logLine(self, line, timeStr = None, isFault = False): 141 """Log the given line.""" 142 index = len(self._lines) 143 self._lines.append((timeStr, line)) 144 self._output.addFlightLogLine(timeStr, line, isFault) 145 return index 146 274 def updateLine(self, id, line): 275 """Update the line with the given ID with the given string. 276 277 Note, that it does not change the status of the line as a fault!""" 278 self._updateEntry(id, self._entries[id].copy(text = line)) 279 280 def _addEntry(self, entry): 281 """Add the given entry to the log. 282 283 @return the ID of the new entry.""" 284 assert entry.id not in self._entries 285 286 self._entries[entry.id] = entry 287 288 if not self._lines or entry>self._lines[-1]: 289 index = len(self._lines) 290 self._lines.append(entry) 291 else: 292 index = bisect.bisect_left(self._lines, entry) 293 self._lines.insert(index, entry) 294 295 if entry.isFault: 296 self._addFault(entry) 297 298 self._output.insertFlightLogLine(index, entry.timestampString, 299 entry.text, entry.isFault) 300 301 return entry.id 302 303 def _updateEntry(self, id, newEntry): 304 """Update the entry with the given ID from the given new entry.""" 305 self._removeEntry(id) 306 self._addEntry(newEntry) 307 308 def _removeEntry(self, id): 309 """Remove the entry with the given ID.""" 310 assert id in self._entries 311 312 entry = self._entries[id] 313 del self._entries[id] 314 315 for index in range(len(self._lines)-1, -1, -1): 316 if self._lines[index] is entry: 317 break 318 del self._lines[index] 319 320 if entry.isFault: 321 faultID = entry.faultID 322 fault = self._faults[faultID] 323 if not fault.removeEntry(entry): 324 del self._faults[faultID] 325 326 self._output.removeFlightLogLine(index) 327 328 def _addFault(self, entry): 329 """Add the given fault entry to the fault with the given ID.""" 330 faultID = entry.faultID 331 if faultID in self._faults: 332 self._faults[faultID].addEntry(entry) 333 else: 334 self._faults[faultID] = Logger.Fault(entry) 335 147 336 #--------------------------------------------------------------------------------------
Note:
See TracChangeset
for help on using the changeset viewer.