diff --git a/logfire/_internal/json_encoder.py b/logfire/_internal/json_encoder.py index 8a48518d..ae7f8a11 100644 --- a/logfire/_internal/json_encoder.py +++ b/logfire/_internal/json_encoder.py @@ -299,17 +299,17 @@ def logfire_json_dumps(obj: Any) -> str: def is_sqlalchemy(obj: Any) -> bool: - if not hasattr(obj, '__mapper__'): - # A SQLModel without `table=True` will pass `isinstance(obj.__class__, DeclarativeMeta)` (I don't know how) - # but will fail when retrieving data, specifically when calling `sqlalchemy.inspect` - # or when getting the `__mapper__` attribute. - return False - try: + if not hasattr(obj, '__mapper__'): + # A SQLModel without `table=True` will pass `isinstance(obj.__class__, DeclarativeMeta)` (I don't know how) + # but will fail when retrieving data, specifically when calling `sqlalchemy.inspect` + # or when getting the `__mapper__` attribute. + return False + from sqlalchemy.orm import DeclarativeBase, DeclarativeMeta return isinstance(obj, DeclarativeBase) or isinstance(obj.__class__, DeclarativeMeta) - except ImportError: # pragma: no cover + except Exception: return False diff --git a/tests/test_json_args.py b/tests/test_json_args.py index ad6a17ba..32ec4987 100644 --- a/tests/test_json_args.py +++ b/tests/test_json_args.py @@ -1315,3 +1315,38 @@ def test_numpy_array_truncation(exporter: TestExporter): } ] ) + + +def test_bad_getattr(exporter: TestExporter, caplog: pytest.LogCaptureFixture): + class A: + def __getattr__(self, item: str): + raise RuntimeError + + def __repr__(self): + return 'A()' + + logfire.info('hello', a=A()) + + assert not caplog.messages + assert exporter.exported_spans_as_dict() == snapshot( + [ + { + 'name': 'hello', + 'context': {'trace_id': 1, 'span_id': 1, 'is_remote': False}, + 'parent': None, + 'start_time': 1000000000, + 'end_time': 1000000000, + 'attributes': { + 'logfire.span_type': 'log', + 'logfire.level_num': 9, + 'logfire.msg_template': 'hello', + 'logfire.msg': 'hello', + 'code.filepath': 'test_json_args.py', + 'code.function': 'test_bad_getattr', + 'code.lineno': 123, + 'a': '"A()"', + 'logfire.json_schema': '{"type":"object","properties":{"a":{"type":"object","x-python-datatype":"unknown"}}}', + }, + } + ] + )