henry3260 opened a new pull request, #76369:
URL: https://github.com/apache/airflow/pull/76369

   ## Why
   
   `PodLogsConsumer._save_incomplete_log_item` guarded on a freshly built list:
   
   ```python
   return [sub_chunk] if [sub_chunk] else []
   ```
   
   `[sub_chunk]` is a one-element list, so the condition is always true and the 
empty remainder left when a stream chunk ends on `\n` is kept. That item is 
yielded once the stream ends, and it carries no timestamp, so 
`PodManager.fetch_container_logs` takes it as a continuation of the buffered 
message.
   
   Two things reach the task log as a result:
   
   - Every stream that ends on a newline gains a trailing newline on its last 
message, so the log picks up a blank line at each read boundary.
   - When nothing is buffered yet, the continuation branch formatted the empty 
buffer into the message, so a read window whose only content is empty container 
writes logged a literal `[base] None`.
   
   A line that genuinely has no parsable timestamp hit the same branch, so its 
text was logged behind a `None` prefix — and because the prefix came first, 
`_parse_log_level` and the group-marker check looked at `None` rather than at 
the real text.
   
   | Stream | Before | After |
   | --- | --- | --- |
   | `<ts> a\n`, `<ts> b\n` | `'a'`, `'b\n'` | `'a'`, `'b'` |
   | `<ts> \n` (only an empty container write) | `'None\n'` | nothing |
   | `ERROR: boom\n` (no timestamp) | `'None\nERROR: boom\n'`, at INFO | 
`'ERROR: boom'`, at ERROR |
   
   ## What
   
   
`providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/pod_manager.py`
   
   - `_save_incomplete_log_item` now tests `sub_chunk`, so the empty remainder 
is dropped and no empty item is yielded once the stream ends.
   - The continuation branch in `fetch_container_logs` is split in two. A 
buffered message is still appended to; a line with no parsable timestamp that 
arrives before any message is buffered now opens a message of its own instead 
of being formatted onto the empty buffer. It is stripped of the trailing 
newline that `parse_log_line` leaves on an unparsable line, and a bare newline 
is dropped rather than emitted as an orphan `[base] ` row.
   - `AsyncPodManager._emit_container_logs` already guards its own continuation 
branch, and drops such a line; the deferrable path is left as it is.
   
   
`providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_pod_manager.py`
   
   - Two `test_chunks` cases for a stream that ends on a newline, with and 
without an earlier complete line.
   - `test_leading_line_without_timestamp_keeps_its_text`, parametrized over 
the line with and without its newline, and 
`test_leading_blank_line_without_timestamp_is_dropped`. Both assert on the 
`progress_callback` kwargs rather than on log text.
   - Every new case fails on `main` and passes with the fix.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Opus 5)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to