diff --git a/logfire/_internal/json_encoder.py b/logfire/_internal/json_encoder.py index df72e846..f0d13e72 100644 --- a/logfire/_internal/json_encoder.py +++ b/logfire/_internal/json_encoder.py @@ -241,12 +241,12 @@ def to_json_value(o: Any, seen: set[int]) -> JsonValue: return { key if isinstance(key, str) else safe_repr(key): to_json_value(value, seen) for key, value in o.items() } # type: ignore + elif is_sqlalchemy(o): + return _get_sqlalchemy_data(o, seen) elif dataclasses.is_dataclass(o): return {f.name: to_json_value(getattr(o, f.name), seen) for f in dataclasses.fields(o)} elif is_attrs(o): return _get_attrs_data(o, seen) - elif is_sqlalchemy(o): - return _get_sqlalchemy_data(o, seen) # Check the class type and its superclasses for a matching encoder for base in o.__class__.__mro__[:-1]: diff --git a/logfire/_internal/json_schema.py b/logfire/_internal/json_schema.py index 75cebc8a..df7020fd 100644 --- a/logfire/_internal/json_schema.py +++ b/logfire/_internal/json_schema.py @@ -116,12 +116,12 @@ def create_json_schema(obj: Any, seen: set[int]) -> JsonDict: return _array_schema(obj, seen) elif isinstance(obj, Mapping): return _mapping_schema(obj, seen) + elif is_sqlalchemy(obj): + return _sqlalchemy_schema(obj, seen) elif dataclasses.is_dataclass(obj): return _dataclass_schema(obj, seen) elif is_attrs(obj): return _attrs_schema(obj, seen) - elif is_sqlalchemy(obj): - return _sqlalchemy_schema(obj, seen) global _type_to_schema _type_to_schema = _type_to_schema or type_to_schema() diff --git a/tests/test_json_args.py b/tests/test_json_args.py index daf0871f..54e3f14c 100644 --- a/tests/test_json_args.py +++ b/tests/test_json_args.py @@ -18,12 +18,13 @@ import pandas import pytest from attrs import define -from dirty_equals import IsJson, IsStr +from dirty_equals import IsJson from inline_snapshot import snapshot from pydantic import AnyUrl, BaseModel, ConfigDict, FilePath, NameEmail, SecretBytes, SecretStr from pydantic.dataclasses import dataclass as pydantic_dataclass from sqlalchemy import String, create_engine from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column +from sqlalchemy.orm.decl_api import MappedAsDataclass import logfire from logfire.testing import TestExporter @@ -829,7 +830,7 @@ def test_log_non_scalar_args( def test_log_sqlalchemy_class(exporter: TestExporter) -> None: - class Base(DeclarativeBase): + class Base(MappedAsDataclass, DeclarativeBase): pass class Model(Base): @@ -903,9 +904,7 @@ def __init__(self, id: int, name: str): 'logfire.span_type': 'log', 'logfire.level_num': 9, 'logfire.msg_template': 'test message {var=}', - 'logfire.msg': IsStr( - regex='test message var=.Model object at .*' - ), + 'logfire.msg': "test message var=test_log_sqlalchemy_class..Model(id=1, name='test name')", 'code.filepath': 'test_json_args.py', 'code.function': 'test_log_sqlalchemy_class', 'code.lineno': 123,