2 # Copyright 2020 The Pigweed Authors
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 # use this file except in compliance with the License. You may obtain a copy of
8 # https://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations under
17 Trace module which creates trace files from a list of trace events.
19 This is a work in progress, future work will look to add:
20 - Config options to customize output.
21 - A method of providing custom data formatters.
28 from typing import Iterable, NamedTuple
30 _LOG = logging.getLogger('pw_trace')
33 class TraceType(Enum):
36 InstantaneousGroup = 2
42 DurationGroupStart = 8
46 class TraceEvent(NamedTuple):
54 has_data: bool = False
59 def event_has_trace_id(event_type):
60 return event_type in {
61 "PW_TRACE_EVENT_TYPE_ASYNC_START",
62 "PW_TRACE_EVENT_TYPE_ASYNC_STEP",
63 "PW_TRACE_EVENT_TYPE_ASYNC_END",
67 def generate_trace_json(events: Iterable[TraceEvent]):
68 """Generates a list of JSON lines from provided trace events."""
71 if event.module is None or event.timestamp_us is None or \
72 event.event_type is None or event.label is None:
73 _LOG.error("Invalid sample")
78 "name": (event.label),
79 "ts": event.timestamp_us
81 if event.event_type == TraceType.DurationStart:
83 line["tid"] = event.label
84 elif event.event_type == TraceType.DurationEnd:
86 line["tid"] = event.label
87 elif event.event_type == TraceType.DurationGroupStart:
89 line["tid"] = event.group
90 elif event.event_type == TraceType.DurationGroupEnd:
92 line["tid"] = event.group
93 elif event.event_type == TraceType.Instantaneous:
96 elif event.event_type == TraceType.InstantaneousGroup:
99 line["tid"] = event.group
100 elif event.event_type == TraceType.AsyncStart:
102 line["scope"] = event.group
103 line["tid"] = event.group
104 line["cat"] = event.module
105 line["id"] = event.trace_id
106 line["args"] = {"id": line["id"]}
107 elif event.event_type == TraceType.AsyncStep:
109 line["scope"] = event.group
110 line["tid"] = event.group
111 line["cat"] = event.module
112 line["id"] = event.trace_id
113 line["args"] = {"id": line["id"]}
114 elif event.event_type == TraceType.AsyncEnd:
116 line["scope"] = event.group
117 line["tid"] = event.group
118 line["cat"] = event.module
119 line["id"] = event.trace_id
120 line["args"] = {"id": line["id"]}
122 _LOG.error("Unknown event type, skipping")
127 if event.data_fmt == "@pw_arg_label":
128 line["name"] = event.data.decode("utf-8")
129 elif event.data_fmt == "@pw_arg_group":
130 line["tid"] = event.data.decode("utf-8")
131 elif event.data_fmt == "@pw_arg_counter":
134 line["name"]: int.from_bytes(event.data, "little")
136 elif event.data_fmt.startswith("@pw_py_struct_fmt:"):
137 items = struct.unpack_from(
138 event.data_fmt[len("@pw_py_struct_fmt:"):], event.data)
140 for i, item in enumerate(items):
141 args["data_" + str(i)] = item
144 line["args"] = {"data": event.data.hex()}
147 json_lines.append(json.dumps(line))