Process a log entry for burst suppression. Args: key: Unique key for the log (source + message) formatted_line: The fully formatted log line Returns: Tuple of (line_to_print_now, deferred_line_if_any) - If same as last: retur
(
self, key: str, formatted_line: str
)
| 187 | self._count: int = 0 |
| 188 | |
| 189 | def process( |
| 190 | self, key: str, formatted_line: str |
| 191 | ) -> Tuple[Optional[str], Optional[str]]: |
| 192 | """ |
| 193 | Process a log entry for burst suppression. |
| 194 | |
| 195 | Args: |
| 196 | key: Unique key for the log (source + message) |
| 197 | formatted_line: The fully formatted log line |
| 198 | |
| 199 | Returns: |
| 200 | Tuple of (line_to_print_now, deferred_line_if_any) |
| 201 | - If same as last: returns (None, None) - suppressed |
| 202 | - If different: returns (last_with_count_if_needed, current_line) |
| 203 | """ |
| 204 | with self._lock: |
| 205 | if self._last_key is None: |
| 206 | # First message |
| 207 | self._last_key = key |
| 208 | self._last_formatted = formatted_line |
| 209 | self._count = 1 |
| 210 | return (formatted_line, None) |
| 211 | |
| 212 | if key == self._last_key: |
| 213 | # Duplicate - suppress and increment counter |
| 214 | self._count += 1 |
| 215 | return (None, None) |
| 216 | else: |
| 217 | # Different message - flush previous with count |
| 218 | prev_line = self._last_formatted |
| 219 | prev_count = self._count |
| 220 | |
| 221 | # Update to new message |
| 222 | self._last_key = key |
| 223 | self._last_formatted = formatted_line |
| 224 | self._count = 1 |
| 225 | |
| 226 | if prev_count > 1 and prev_line: |
| 227 | # Create a dim footnote line instead of appending count |
| 228 | # Extract timestamp/level/source/id columns from prev_line to align properly |
| 229 | # Format: " └─ (Repeated N times)" |
| 230 | indent = ( |
| 231 | " " * 31 |
| 232 | ) # Align with message column (timestamp + level + source + id + spaces) |
| 233 | count_line = f"{indent}{Colors.TREE}\u2514\u2500 {Colors.BURST_COUNT}(Repeated {prev_count} times){Colors.RESET}" |
| 234 | # Return previous line (without count), count line, and current line |
| 235 | return (f"{prev_line}\n{count_line}", formatted_line) |
| 236 | else: |
| 237 | # Previous was single, just print current |
| 238 | return (formatted_line, None) |
| 239 | |
| 240 | def flush(self) -> Optional[str]: |
| 241 | """Flush any remaining buffered message.""" |
no outgoing calls