fix(instigation logger): stringify non-json objects#32867
Conversation
f2e3cd6 to
e46b3da
Compare
cmpadden
left a comment
There was a problem hiding this comment.
I verified that this preserves the prior seven.json behavior.
One small caveat is that this won’t make serialization completely bulletproof for every possible pathological LogRecord shape, e.g. unusual nested dict keys or circular structures, but it’s an appropriate minimal fix for the issue reported in #32845.
Greptile SummaryThis PR fixes a crash in
Confidence Score: 4/5Safe to merge; the core fix is correct and the new test exercises the repaired path end-to-end. The No files require special attention; both changed files are straightforward and the test covers the fixed scenario well.
|
| Filename | Overview |
|---|---|
| python_modules/dagster/dagster/_core/definitions/instigation_logger.py | Core fix: replaces seven.json with stdlib json + default=str to handle non-serializable log record attributes; adds strict=False to the read path (unnecessary but harmless). |
| python_modules/dagster/dagster_tests/storage_tests/test_instigation_logger.py | New end-to-end test covers the happy path with a non-serializable extra; uses >= 2 for record count which is slightly imprecise but functionally adequate. |
Sequence Diagram
sequenceDiagram
participant User as User Code
participant IL as InstigationLogger
participant CLH as CapturedLogHandler
participant WS as Write Stream (IO)
participant GILR as get_instigation_log_records
User->>IL: "logger.info("msg", extra={"key": NonJsonSerializable()})"
IL->>IL: makeRecord() → _annotate_record()
IL->>CLH: emit(record)
CLH->>CLH: "record_dict = record.__dict__"
CLH->>CLH: handle exc_info (format traceback string)
alt "default=str path (NEW)"
CLH->>CLH: "json.dumps(record_dict, default=str, sort_keys=True)"
CLH->>WS: write(json_line + newline)
else Exception still raised (circular ref, etc.)
CLH->>CLH: except: write to stderr with origin location
end
Note over GILR,WS: Later, on read-back
GILR->>WS: get_log_data() → raw bytes
GILR->>GILR: for line in raw_logs.split(newline)
GILR->>GILR: "json.loads(line, strict=False)"
GILR-->>User: Sequence[Mapping[str, Any]]
Reviews (1): Last reviewed commit: "Remove unnecessary pyright ignore" | Re-trigger Greptile
|
|
||
| try: | ||
| records.append(seven.json.loads(line)) | ||
| records.append(json.loads(line, strict=False)) |
There was a problem hiding this comment.
strict=False is redundant on this read path. json.dumps always escapes control characters in strings (e.g., a newline in a str value becomes in the JSON output), so the data written by CapturedLogHandler.emit is already strictly conformant JSON and will parse without strict=False. The parameter adds no protection here and makes the code misleadingly imply that the stored JSON might contain raw control characters.
| records.append(json.loads(line, strict=False)) | |
| records.append(json.loads(line)) |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| assert len(records) >= 2 | ||
| assert "test-repo - test-instigator - log with extras" in { | ||
| record.get("msg") for record in records if record.get("msg") | ||
| } |
There was a problem hiding this comment.
The test logs exactly two messages and then asserts
len(records) >= 2. If a future change accidentally swallowed one record (returning only 1), this assertion would still pass. An == 2 assertion (or checking that both messages appear) would catch that regression.
| assert len(records) >= 2 | |
| assert "test-repo - test-instigator - log with extras" in { | |
| record.get("msg") for record in records if record.get("msg") | |
| } | |
| assert len(records) == 2 | |
| record_msgs = {record.get("msg") for record in records if record.get("msg")} | |
| assert "test-repo - test-instigator - log without extras" in record_msgs | |
| assert "test-repo - test-instigator - log with extras" in record_msgs |
Summary & Motivation
Fixes #32845. Although, here is probably some underlying issue that is not fixed by this PR. But I think that can go in another issue.
How I Tested These Changes
Implemented a test with a "weird" log record to show that logging does not error in this case any more.
Changelog