Skip to content

Commit f67608d

Browse files
feat(back): Added structured logs when available in the list of logs for finished tasks
1 parent fdc0ad9 commit f67608d

2 files changed

Lines changed: 91 additions & 22 deletions

File tree

tests/etl/taskcluster_pulse/test_handler.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
11
import pytest
22

3-
from treeherder.etl.taskcluster_pulse.handler import handle_message, handle_task_defined
3+
from treeherder.etl.taskcluster_pulse.handler import (
4+
create_log_reference,
5+
handle_message,
6+
handle_task_defined,
7+
)
8+
9+
ROOT_URL = "https://firefox-ci-tc.services.mozilla.com"
10+
TASK_ID = "AJBb7wqZT6K9kz4niYAatg"
11+
12+
13+
def test_create_log_reference_emits_live_backing_log_by_default():
14+
logs = create_log_reference(ROOT_URL, TASK_ID, 0)
15+
assert len(logs) == 1
16+
assert logs[0]["name"] == "live_backing_log"
17+
assert logs[0]["url"].endswith(f"task/{TASK_ID}/runs/0/artifacts/public/logs/live_backing.log")
18+
19+
20+
def test_create_log_reference_only_live_backing_log_when_no_raw_log():
21+
artifacts = [
22+
{"name": "public/logs/live_backing.log"},
23+
{"name": "public/test_info/something.txt"},
24+
]
25+
logs = create_log_reference(ROOT_URL, TASK_ID, 0, artifacts=artifacts)
26+
assert len(logs) == 1
27+
assert logs[0]["url"].endswith("artifacts/public/logs/live_backing.log")
28+
29+
30+
def test_create_log_reference_appends_raw_log_when_present():
31+
artifacts = [
32+
{"name": "public/logs/live_backing.log"},
33+
{"name": "public/test_info/xpcshell_raw.log"},
34+
{"name": "public/test_info/mochitest_raw.log"},
35+
]
36+
logs = create_log_reference(ROOT_URL, TASK_ID, 0, artifacts=artifacts)
37+
assert [log["name"] for log in logs] == [
38+
"live_backing_log",
39+
"structured_log",
40+
"structured_log",
41+
]
42+
urls = [log["url"] for log in logs]
43+
assert urls[0].endswith("artifacts/public/logs/live_backing.log")
44+
assert urls[1].endswith("artifacts/public/test_info/xpcshell_raw.log")
45+
assert urls[2].endswith("artifacts/public/test_info/mochitest_raw.log")
446

547

648
@pytest.mark.asyncio

treeherder/etl/taskcluster_pulse/handler.py

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,31 @@ def result_from_run(job_run):
5656
return "unknown"
5757

5858

59-
# Creates a log entry for Treeherder to retrieve and parse. This log is
60-
# displayed on the Treeherder Log Viewer once parsed.
61-
def create_log_reference(root_url, task_id, run_id):
62-
log_url = taskcluster_urls.api(
63-
root_url, "queue", "v1", "task/{taskId}/runs/{runId}/artifacts/public/logs/live_backing.log"
64-
).format(taskId=task_id, runId=run_id)
65-
return {
66-
"name": "live_backing_log",
67-
"url": log_url,
68-
}
59+
# Creates the log entries for Treeherder to retrieve and parse. These logs
60+
# are displayed on the Treeherder Log Viewer once parsed.
61+
# `public/logs/live_backing.log` is always included. Any artifact whose name
62+
# ends with `_raw.log` is appended as an additional reference. All entries
63+
# share the `live_backing_log` JobLog name so the existing parser dispatch
64+
# (jobs.py:_schedule_log_parsing, log_parser/tasks.py:parser_tasks) handles
65+
# them; JobLog's `(job, name, url)` unique constraint allows the duplicates.
66+
def create_log_reference(root_url, task_id, run_id, artifacts=None):
67+
def _ref(name, artifact_path):
68+
return {
69+
"name": name,
70+
"url": taskcluster_urls.api(
71+
root_url,
72+
"queue",
73+
"v1",
74+
f"task/{{taskId}}/runs/{{runId}}/artifacts/{artifact_path}",
75+
).format(taskId=task_id, runId=run_id),
76+
}
77+
78+
logs = [_ref("live_backing_log", "public/logs/live_backing.log")]
79+
for artifact in artifacts or []:
80+
name = artifact.get("name", "")
81+
if name.endswith("_raw.log"):
82+
logs.append(_ref("structured_log", name))
83+
return logs
6984

7085

7186
# Filters the task routes for the treeherder specific route. Once found,
@@ -371,11 +386,23 @@ async def handle_task_completed(push_info, task, message, session):
371386

372387
job["timeStarted"] = job_run["started"]
373388
job["timeCompleted"] = job_run["resolved"]
374-
job["logs"] = [
375-
create_log_reference(message["root_url"], payload["status"]["taskId"], job_run["runId"]),
376-
]
389+
390+
task_id = payload["status"]["taskId"]
391+
run_id = job_run["runId"]
392+
try:
393+
artifacts = await fetch_artifacts(message["root_url"], task_id, run_id, session)
394+
except Exception:
395+
logger.debug("Artifacts could not be found for task: %s run: %s", task_id, run_id)
396+
artifacts = []
397+
398+
job["logs"] = create_log_reference(message["root_url"], task_id, run_id, artifacts=artifacts)
377399
job = await add_artifact_uploaded_links(
378-
message["root_url"], payload["status"]["taskId"], payload["runId"], job, session
400+
message["root_url"],
401+
task_id,
402+
payload["runId"],
403+
job,
404+
session,
405+
artifacts=artifacts,
379406
)
380407
return job
381408

@@ -434,13 +461,13 @@ async def fetch_artifacts(root_url, task_id, run_id, session):
434461
# fetch them in order to determine if there is an error_summary log;
435462
# TODO refactor this when there is a way to only retrieve the error_summary
436463
# artifact: https://bugzilla.mozilla.org/show_bug.cgi?id=1629716
437-
async def add_artifact_uploaded_links(root_url, task_id, run_id, job, session):
438-
artifacts = []
439-
try:
440-
artifacts = await fetch_artifacts(root_url, task_id, run_id, session)
441-
except Exception:
442-
logger.debug("Artifacts could not be found for task: %s run: %s", task_id, run_id)
443-
return job
464+
async def add_artifact_uploaded_links(root_url, task_id, run_id, job, session, artifacts=None):
465+
if artifacts is None:
466+
try:
467+
artifacts = await fetch_artifacts(root_url, task_id, run_id, session)
468+
except Exception:
469+
logger.debug("Artifacts could not be found for task: %s run: %s", task_id, run_id)
470+
return job
444471

445472
seen = {}
446473
links = []

0 commit comments

Comments
 (0)