Добавил просмотр trace логов полностью
This commit is contained in:
+223
-32
@@ -54,6 +54,7 @@ def test_trace_endpoint_returns_html_by_default() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="root-trace",
|
||||
alias="mailbox_sync",
|
||||
child_ids=("child-1", "child-2"),
|
||||
records=(
|
||||
_trace_record(row_id=1, level="ERROR", message="first error"),
|
||||
@@ -69,7 +70,7 @@ def test_trace_endpoint_returns_html_by_default() -> None:
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.headers["content-type"].startswith("text/html")
|
||||
assert "trace_id:" in response.text
|
||||
assert "trace context: mailbox_sync, " in response.text
|
||||
assert "first error" in response.text
|
||||
assert "second warning" in response.text
|
||||
assert captured == [
|
||||
@@ -79,7 +80,8 @@ def test_trace_endpoint_returns_html_by_default() -> None:
|
||||
levels=("ERROR", "WARNING", "INFO"),
|
||||
include_attrs_json=False,
|
||||
response_format="html",
|
||||
ancestor_depth=0,
|
||||
ancestor_depth=None,
|
||||
view="tree",
|
||||
),
|
||||
)
|
||||
]
|
||||
@@ -90,6 +92,7 @@ def test_trace_endpoint_returns_text_when_requested() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="root-trace",
|
||||
alias="mailbox_sync",
|
||||
child_ids=("child-1", "child-2"),
|
||||
records=(
|
||||
_trace_record(row_id=1, level="ERROR", message="first error"),
|
||||
@@ -112,7 +115,7 @@ def test_trace_endpoint_returns_text_when_requested() -> None:
|
||||
" - child-2\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: trace-1\n"
|
||||
"trace context: mailbox_sync, trace-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
"first error\n"
|
||||
@@ -125,6 +128,7 @@ def test_trace_endpoint_appends_attrs_json_in_text_mode() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id=None,
|
||||
alias="mailbox_sync",
|
||||
child_ids=(),
|
||||
records=(
|
||||
_trace_record(row_id=1, level="ERROR", message="failure", attrs_json={"attempt": 2, "source": "crm"}),
|
||||
@@ -144,7 +148,7 @@ def test_trace_endpoint_appends_attrs_json_in_text_mode() -> None:
|
||||
"child_ids:\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: trace-1\n"
|
||||
"trace context: mailbox_sync, trace-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
'failure, {"attempt":2,"source":"crm"}'
|
||||
@@ -156,6 +160,7 @@ def test_trace_endpoint_separates_messages_by_step_in_text_mode() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id=None,
|
||||
alias="mailbox_sync",
|
||||
child_ids=(),
|
||||
records=(
|
||||
_trace_record(row_id=1, level="INFO", message="load first", step="load_stocks"),
|
||||
@@ -177,7 +182,7 @@ def test_trace_endpoint_separates_messages_by_step_in_text_mode() -> None:
|
||||
"child_ids:\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: trace-1\n"
|
||||
"trace context: mailbox_sync, trace-1\n"
|
||||
"\n"
|
||||
"step: load_stocks\n"
|
||||
"load first\n"
|
||||
@@ -201,7 +206,7 @@ def test_trace_endpoint_returns_json_payload() -> None:
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/trace-1?format=json&attrs_json=true&levels=info")
|
||||
response = client.get("/traces/trace-1?format=json&attrs_json=true&levels=info&view=single")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
@@ -257,7 +262,7 @@ def test_trace_endpoint_returns_json_payload_with_ancestors() -> None:
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/trace-1?format=json&ancestor_depth=1")
|
||||
response = client.get("/traces/trace-1?format=json&ancestor_depth=1&view=single")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
@@ -303,6 +308,7 @@ def test_trace_endpoint_returns_html_page_with_related_links() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="parent-1",
|
||||
alias="order_confirmation",
|
||||
child_ids=("child-1", "child-2"),
|
||||
records=(
|
||||
_trace_record(row_id=1, level="INFO", message="loaded prices", step="load_stocks", status="ok"),
|
||||
@@ -327,14 +333,14 @@ def test_trace_endpoint_returns_html_page_with_related_links() -> None:
|
||||
assert "--error: #ff817d;" in response.text
|
||||
assert "--other: #ececec;" in response.text
|
||||
assert 'font: 13px/1.1 "SFMono-Regular", monospace;' in response.text
|
||||
assert '<div class="line">trace_id: <a href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true">trace-1</a></div>' in response.text
|
||||
assert '<div class="line">parent_id: <a href="/traces/parent-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true">parent-1</a></div>' in response.text
|
||||
assert '<div class="line">trace_id: <a href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=tree&ancestor_depth=all">trace-1</a></div>' in response.text
|
||||
assert '<div class="line">parent_id: <a href="/traces/parent-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=tree&ancestor_depth=all">parent-1</a></div>' in response.text
|
||||
assert '<div class="line">child_ids:</div>' in response.text
|
||||
assert '<div class="line"> - <a href="/traces/child-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true">child-1</a></div>' in response.text
|
||||
assert '<div class="line"> - <a href="/traces/child-2?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true">child-2</a></div>' in response.text
|
||||
assert '<div class="line"> - <a href="/traces/child-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=tree&ancestor_depth=all">child-1</a></div>' in response.text
|
||||
assert '<div class="line"> - <a href="/traces/child-2?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=tree&ancestor_depth=all">child-2</a></div>' in response.text
|
||||
assert '<div class="line">==============================</div>' in response.text
|
||||
assert '<div class="line">trace context: order_confirmation, <a href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=tree&ancestor_depth=all">trace-1</a></div>' in response.text
|
||||
assert '<div class="line" style="color: var(--step);">load_stocks</div>' in response.text
|
||||
assert '<div class="line">trace_id: <a href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true">trace-1</a></div>' in response.text
|
||||
assert '<div class="line" style="color: var(--step);">filter_stocks</div>' in response.text
|
||||
assert "loaded prices" in response.text
|
||||
assert "filtered suspicious ticker" in response.text
|
||||
@@ -348,18 +354,21 @@ def test_trace_endpoint_renders_ancestors_in_text_mode() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="parent-1",
|
||||
alias="child",
|
||||
child_ids=(),
|
||||
records=(_trace_record(row_id=1, level="INFO", message="child message"),),
|
||||
ancestors=(
|
||||
TraceLogView(
|
||||
trace_id="root-1",
|
||||
parent_id=None,
|
||||
alias="root",
|
||||
child_ids=("parent-1",),
|
||||
records=(_trace_record(row_id=2, level="INFO", message="root message"),),
|
||||
),
|
||||
TraceLogView(
|
||||
trace_id="parent-1",
|
||||
parent_id="root-1",
|
||||
alias="parent",
|
||||
child_ids=("trace-1",),
|
||||
records=(_trace_record(row_id=3, level="WARNING", message="parent message"),),
|
||||
),
|
||||
@@ -368,7 +377,7 @@ def test_trace_endpoint_renders_ancestors_in_text_mode() -> None:
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/trace-1?format=text&ancestor_depth=1")
|
||||
response = client.get("/traces/trace-1?format=text&ancestor_depth=1&view=single")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
@@ -379,21 +388,21 @@ def test_trace_endpoint_renders_ancestors_in_text_mode() -> None:
|
||||
"child_ids:\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: root-1\n"
|
||||
"trace context: root, root-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
"root message\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: parent-1\n"
|
||||
"trace context: parent, parent-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
"parent message\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace_id: trace-1\n"
|
||||
"trace context: child, trace-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
"child message"
|
||||
@@ -405,18 +414,21 @@ def test_trace_endpoint_preserves_ancestor_depth_in_html_links() -> None:
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="parent-1",
|
||||
alias="child",
|
||||
child_ids=("child-1",),
|
||||
records=(_trace_record(row_id=1, level="INFO", message="loaded prices"),),
|
||||
ancestors=(
|
||||
TraceLogView(
|
||||
trace_id="root-1",
|
||||
parent_id=None,
|
||||
alias="root",
|
||||
child_ids=("parent-1",),
|
||||
records=(_trace_record(row_id=2, level="INFO", message="root info"),),
|
||||
),
|
||||
TraceLogView(
|
||||
trace_id="parent-1",
|
||||
parent_id="root-1",
|
||||
alias="parent",
|
||||
child_ids=("trace-1",),
|
||||
records=(_trace_record(row_id=3, level="WARNING", message="parent warning"),),
|
||||
),
|
||||
@@ -425,19 +437,102 @@ def test_trace_endpoint_preserves_ancestor_depth_in_html_links() -> None:
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/trace-1?format=html&attrs_json=true&ancestor_depth=all")
|
||||
response = client.get("/traces/trace-1?format=html&attrs_json=true&ancestor_depth=all&view=single")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert 'href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&ancestor_depth=all"' in response.text
|
||||
assert 'href="/traces/root-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&ancestor_depth=all"' in response.text
|
||||
assert 'href="/traces/parent-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&ancestor_depth=all"' in response.text
|
||||
assert 'href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=single&ancestor_depth=all"' in response.text
|
||||
assert 'href="/traces/root-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=single&ancestor_depth=all"' in response.text
|
||||
assert 'href="/traces/parent-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true&view=single&ancestor_depth=all"' in response.text
|
||||
assert response.text.index("root info") < response.text.index("parent warning") < response.text.index("loaded prices")
|
||||
assert "root info" in response.text
|
||||
assert "parent warning" in response.text
|
||||
|
||||
|
||||
def test_trace_endpoint_returns_full_tree_by_default() -> None:
|
||||
async def trace_provider(trace_id: str, request: TraceQueryRequest) -> TraceLogView:
|
||||
assert trace_id == "child-1"
|
||||
assert request.view == "tree"
|
||||
assert request.ancestor_depth is None
|
||||
return TraceLogView(
|
||||
trace_id="root-1",
|
||||
parent_id=None,
|
||||
alias="root",
|
||||
child_ids=("parent-1",),
|
||||
records=(_trace_record(row_id=1, level="INFO", message="root message"),),
|
||||
descendants=(
|
||||
TraceLogView(
|
||||
trace_id="parent-1",
|
||||
parent_id="root-1",
|
||||
alias="parent",
|
||||
child_ids=("child-1", "sibling-1"),
|
||||
records=(_trace_record(row_id=2, level="WARNING", message="parent message"),),
|
||||
descendants=(
|
||||
TraceLogView(
|
||||
trace_id="child-1",
|
||||
parent_id="parent-1",
|
||||
alias="child",
|
||||
child_ids=(),
|
||||
records=(_trace_record(row_id=3, level="ERROR", message="child message"),),
|
||||
),
|
||||
TraceLogView(
|
||||
trace_id="sibling-1",
|
||||
parent_id="parent-1",
|
||||
alias="sibling",
|
||||
child_ids=(),
|
||||
records=(_trace_record(row_id=4, level="INFO", message="sibling message"),),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
requested_trace_id="child-1",
|
||||
)
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/child-1?format=text")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "requested_trace_id: child-1" in response.text
|
||||
assert response.text.index("root message") < response.text.index("parent message") < response.text.index("child message") < response.text.index("sibling message")
|
||||
|
||||
|
||||
def test_trace_endpoint_supports_single_view_opt_in() -> None:
|
||||
async def trace_provider(_trace_id: str, request: TraceQueryRequest) -> TraceLogView:
|
||||
assert request.view == "single"
|
||||
assert request.ancestor_depth == 0
|
||||
return TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="root-trace",
|
||||
alias="single_trace",
|
||||
child_ids=("child-1",),
|
||||
records=(_trace_record(row_id=1, level="ERROR", message="only current trace"),),
|
||||
)
|
||||
|
||||
client = _build_client(trace_provider)
|
||||
try:
|
||||
response = client.get("/traces/trace-1?format=text&view=single")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.text == (
|
||||
"trace_id: trace-1\n"
|
||||
"parent_id: root-trace\n"
|
||||
"child_ids:\n"
|
||||
" - child-1\n"
|
||||
"\n"
|
||||
"==============================\n"
|
||||
"trace context: single_trace, trace-1\n"
|
||||
"\n"
|
||||
"step: process\n"
|
||||
"only current trace"
|
||||
)
|
||||
|
||||
|
||||
def test_trace_endpoint_validates_query_params() -> None:
|
||||
client = _build_client(lambda _trace_id, _request: None)
|
||||
try:
|
||||
@@ -445,6 +540,7 @@ def test_trace_endpoint_validates_query_params() -> None:
|
||||
invalid_format = client.get("/traces/trace-1?format=xml")
|
||||
invalid_ancestor_depth = client.get("/traces/trace-1?ancestor_depth=-1")
|
||||
invalid_ancestor_type = client.get("/traces/trace-1?ancestor_depth=up")
|
||||
invalid_view = client.get("/traces/trace-1?view=graph")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
@@ -462,12 +558,18 @@ def test_trace_endpoint_validates_query_params() -> None:
|
||||
"status": "error",
|
||||
"detail": "invalid ancestor depth query parameter: ancestor_depth=up",
|
||||
}
|
||||
assert invalid_view.status_code == 400
|
||||
assert invalid_view.json() == {
|
||||
"status": "error",
|
||||
"detail": "unsupported trace view: graph",
|
||||
}
|
||||
|
||||
|
||||
def test_runtime_trace_logs_uses_configured_reader(monkeypatch) -> None:
|
||||
expected = TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="root",
|
||||
alias="runtime",
|
||||
child_ids=("child-1",),
|
||||
records=(_trace_record(row_id=1, level="ERROR", message="boom"),),
|
||||
)
|
||||
@@ -478,16 +580,19 @@ def test_runtime_trace_logs_uses_configured_reader(monkeypatch) -> None:
|
||||
trace_id: str,
|
||||
levels: tuple[str, ...],
|
||||
ancestor_depth: int | None = 0,
|
||||
*,
|
||||
view: str = "tree",
|
||||
) -> TraceLogView | None:
|
||||
assert trace_id == "trace-1"
|
||||
assert levels == ("ERROR",)
|
||||
assert ancestor_depth is None
|
||||
assert view == "tree"
|
||||
return expected
|
||||
|
||||
monkeypatch.setattr(runtime_module, "build_trace_log_reader", lambda _transport: StubReader())
|
||||
runtime = RuntimeManager()
|
||||
|
||||
result = asyncio.run(runtime.trace_logs("trace-1", TraceQueryRequest(levels=("ERROR",), ancestor_depth=None)))
|
||||
result = asyncio.run(runtime.trace_logs("trace-1", TraceQueryRequest(levels=("ERROR",), ancestor_depth=None, view="tree")))
|
||||
|
||||
assert result == expected
|
||||
|
||||
@@ -504,9 +609,9 @@ def test_mysql_trace_log_reader_maps_db_rows() -> None:
|
||||
|
||||
def fetchone(self) -> dict[str, object] | None:
|
||||
if self.executed[-1][1] == ("trace-1",):
|
||||
return {"parent_id": "root-77"}
|
||||
return {"parent_id": "root-77", "alias": "single"}
|
||||
if self.executed[-1][1] == ("root-77",):
|
||||
return {"parent_id": None}
|
||||
return {"parent_id": None, "alias": "root"}
|
||||
return None
|
||||
|
||||
def fetchall(self) -> list[dict[str, object]]:
|
||||
@@ -554,11 +659,12 @@ def test_mysql_trace_log_reader_maps_db_rows() -> None:
|
||||
factory = FakeConnectionFactory()
|
||||
reader = MySqlTraceLogReader(factory) # type: ignore[arg-type]
|
||||
|
||||
view = reader.read_trace("trace-1", ("ERROR", "WARNING"))
|
||||
view = reader.read_trace("trace-1", ("ERROR", "WARNING"), view="single")
|
||||
|
||||
assert view == TraceLogView(
|
||||
trace_id="trace-1",
|
||||
parent_id="root-77",
|
||||
alias="single",
|
||||
child_ids=("child-1", "child-2"),
|
||||
records=(
|
||||
TraceLogRecord(
|
||||
@@ -591,11 +697,11 @@ def test_mysql_trace_log_reader_loads_requested_ancestors() -> None:
|
||||
|
||||
def fetchone(self) -> dict[str, object] | None:
|
||||
if self.executed[-1][1] == ("trace-1",):
|
||||
return {"parent_id": "parent-1"}
|
||||
return {"parent_id": "parent-1", "alias": "child"}
|
||||
if self.executed[-1][1] == ("parent-1",):
|
||||
return {"parent_id": "root-1"}
|
||||
return {"parent_id": "root-1", "alias": "parent"}
|
||||
if self.executed[-1][1] == ("root-1",):
|
||||
return {"parent_id": None}
|
||||
return {"parent_id": None, "alias": "root"}
|
||||
return None
|
||||
|
||||
def fetchall(self) -> list[dict[str, object]]:
|
||||
@@ -651,17 +757,101 @@ def test_mysql_trace_log_reader_loads_requested_ancestors() -> None:
|
||||
factory = FakeConnectionFactory()
|
||||
reader = MySqlTraceLogReader(factory) # type: ignore[arg-type]
|
||||
|
||||
view = reader.read_trace("trace-1", ("ERROR",), 1)
|
||||
view = reader.read_trace("trace-1", ("ERROR",), 1, view="single")
|
||||
|
||||
assert view is not None
|
||||
assert view.trace_id == "trace-1"
|
||||
assert view.parent_id == "parent-1"
|
||||
assert view.alias == "child"
|
||||
assert len(view.ancestors) == 1
|
||||
assert view.ancestors[0].trace_id == "parent-1"
|
||||
assert view.ancestors[0].parent_id == "root-1"
|
||||
assert view.ancestors[0].alias == "parent"
|
||||
assert view.ancestors[0].child_ids == ("trace-1",)
|
||||
|
||||
|
||||
def test_mysql_trace_log_reader_tree_view_returns_root_subtree() -> None:
|
||||
class FakeCursor:
|
||||
def __init__(self) -> None:
|
||||
self.executed: list[tuple[str, tuple[object, ...]]] = []
|
||||
self._current_query = ""
|
||||
|
||||
def execute(self, query: str, params: tuple[object, ...]) -> None:
|
||||
self.executed.append((query, params))
|
||||
self._current_query = query
|
||||
|
||||
def fetchone(self) -> dict[str, object] | None:
|
||||
trace_id = self.executed[-1][1][0]
|
||||
mapping = {
|
||||
"child-1": {"parent_id": "parent-1", "alias": "child"},
|
||||
"parent-1": {"parent_id": "root-1", "alias": "parent"},
|
||||
"root-1": {"parent_id": None, "alias": "root"},
|
||||
"sibling-1": {"parent_id": "parent-1", "alias": "sibling"},
|
||||
}
|
||||
return mapping.get(trace_id)
|
||||
|
||||
def fetchall(self) -> list[dict[str, object]]:
|
||||
if "WHERE parent_id = %s" in self._current_query:
|
||||
parent_id = self.executed[-1][1][0]
|
||||
if parent_id == "root-1":
|
||||
return [{"trace_id": "parent-1"}]
|
||||
if parent_id == "parent-1":
|
||||
return [{"trace_id": "child-1"}, {"trace_id": "sibling-1"}]
|
||||
return []
|
||||
trace_id = self.executed[-1][1][0]
|
||||
return [
|
||||
{
|
||||
"id": 8,
|
||||
"trace_id": trace_id,
|
||||
"event_time": datetime(2026, 4, 28, 10, 11, 12, tzinfo=timezone.utc),
|
||||
"step": "parse",
|
||||
"status": "failed",
|
||||
"level": "ERROR",
|
||||
"message": f"broken:{trace_id}",
|
||||
"attrs_json": '{"attempt":1}',
|
||||
}
|
||||
]
|
||||
|
||||
def __enter__(self) -> FakeCursor:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb) -> None:
|
||||
return None
|
||||
|
||||
class FakeConnection:
|
||||
def __init__(self, cursor: FakeCursor) -> None:
|
||||
self._cursor = cursor
|
||||
|
||||
def cursor(self) -> FakeCursor:
|
||||
return self._cursor
|
||||
|
||||
def __enter__(self) -> FakeConnection:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb) -> None:
|
||||
return None
|
||||
|
||||
class FakeConnectionFactory:
|
||||
def __init__(self) -> None:
|
||||
self.cursor = FakeCursor()
|
||||
|
||||
def connect(self) -> FakeConnection:
|
||||
return FakeConnection(self.cursor)
|
||||
|
||||
factory = FakeConnectionFactory()
|
||||
reader = MySqlTraceLogReader(factory) # type: ignore[arg-type]
|
||||
|
||||
view = reader.read_trace("child-1", ("ERROR",), None, view="tree")
|
||||
|
||||
assert view is not None
|
||||
assert view.trace_id == "root-1"
|
||||
assert view.alias == "root"
|
||||
assert view.requested_trace_id == "child-1"
|
||||
assert tuple(child.trace_id for child in view.descendants) == ("parent-1",)
|
||||
assert view.descendants[0].alias == "parent"
|
||||
assert tuple(child.trace_id for child in view.descendants[0].descendants) == ("child-1", "sibling-1")
|
||||
|
||||
|
||||
def test_mysql_trace_log_reader_orders_ancestors_root_first() -> None:
|
||||
class FakeCursor:
|
||||
def __init__(self) -> None:
|
||||
@@ -674,11 +864,11 @@ def test_mysql_trace_log_reader_orders_ancestors_root_first() -> None:
|
||||
|
||||
def fetchone(self) -> dict[str, object] | None:
|
||||
if self.executed[-1][1] == ("trace-1",):
|
||||
return {"parent_id": "parent-1"}
|
||||
return {"parent_id": "parent-1", "alias": "child"}
|
||||
if self.executed[-1][1] == ("parent-1",):
|
||||
return {"parent_id": "root-1"}
|
||||
return {"parent_id": "root-1", "alias": "parent"}
|
||||
if self.executed[-1][1] == ("root-1",):
|
||||
return {"parent_id": None}
|
||||
return {"parent_id": None, "alias": "root"}
|
||||
return None
|
||||
|
||||
def fetchall(self) -> list[dict[str, object]]:
|
||||
@@ -732,7 +922,8 @@ def test_mysql_trace_log_reader_orders_ancestors_root_first() -> None:
|
||||
factory = FakeConnectionFactory()
|
||||
reader = MySqlTraceLogReader(factory) # type: ignore[arg-type]
|
||||
|
||||
view = reader.read_trace("trace-1", ("ERROR",), 2)
|
||||
view = reader.read_trace("trace-1", ("ERROR",), 2, view="single")
|
||||
|
||||
assert view is not None
|
||||
assert tuple(ancestor.trace_id for ancestor in view.ancestors) == ("root-1", "parent-1")
|
||||
assert tuple(ancestor.alias for ancestor in view.ancestors) == ("root", "parent")
|
||||
|
||||
Reference in New Issue
Block a user