python: reimplement the babeltrace package as a bt2 wrapper
[babeltrace.git] / bindings / python / babeltrace / babeltrace / reader_event.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2013-2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22
23 import bt2
24 import babeltrace.common as common
25 import babeltrace.reader_field_definition as field_definition
26 import datetime
27 import collections
28
29 def _create_event(event_notification, trace_handle=None, trace_collection=None):
30 event = Event.__new__(Event)
31 event._event_notification = event_notification
32 event._trace_handle = trace_handle
33 event._trace_collection = trace_collection
34 return event
35
36 class Event(collections.Mapping):
37 """
38 An :class:`Event` object represents a trace event. :class:`Event`
39 objects are returned by :attr:`TraceCollection.events` and are
40 not meant to be instantiated by the user.
41
42 :class:`Event` has a :class:`dict`-like interface for accessing
43 an event's field value by field name:
44
45 .. code-block:: python
46
47 event['my_field']
48
49 If a field name exists in multiple scopes, the value of the first
50 field found is returned. The scopes are searched in the following
51 order:
52
53 1. Event fields (:attr:`babeltrace.common.CTFScope.EVENT_FIELDS`)
54 2. Event context (:attr:`babeltrace.common.CTFScope.EVENT_CONTEXT`)
55 3. Stream event context (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_CONTEXT`)
56 4. Event header (:attr:`babeltrace.common.CTFScope.STREAM_EVENT_HEADER`)
57 5. Packet context (:attr:`babeltrace.common.CTFScope.STREAM_PACKET_CONTEXT`)
58 6. Packet header (:attr:`babeltrace.common.CTFScope.TRACE_PACKET_HEADER`)
59
60 It is still possible to obtain a field's value from a specific
61 scope using :meth:`field_with_scope`.
62
63 Field values are returned as native Python types, that is:
64
65 +-----------------------+----------------------------------+
66 | Field type | Python type |
67 +=======================+==================================+
68 | Integer | :class:`int` |
69 +-----------------------+----------------------------------+
70 | Floating point number | :class:`float` |
71 +-----------------------+----------------------------------+
72 | Enumeration | :class:`str` (enumeration label) |
73 +-----------------------+----------------------------------+
74 | String | :class:`str` |
75 +-----------------------+----------------------------------+
76 | Array | :class:`list` of native Python |
77 | | objects |
78 +-----------------------+----------------------------------+
79 | Sequence | :class:`list` of native Python |
80 | | objects |
81 +-----------------------+----------------------------------+
82 | Structure | :class:`dict` mapping field |
83 | | names to native Python objects |
84 +-----------------------+----------------------------------+
85
86 For example, printing the third element of a sequence named ``seq``
87 in a structure named ``my_struct`` of the ``event``'s field named
88 ``my_field`` is done this way:
89
90 .. code-block:: python
91
92 print(event['my_field']['my_struct']['seq'][2])
93 """
94
95 def __init__(self):
96 raise NotImplementedError("Event cannot be instantiated")
97
98 @property
99 def name(self):
100 """
101 Event name or ``None`` on error.
102 """
103
104 try:
105 return self._event_notification.event.name
106 except bt2.Error:
107 pass
108
109 def _clock_value(self):
110 cc_prio_map = self._event_notification.clock_class_priority_map
111 clock_class = cc_prio_map.highest_priority_clock_class
112 if not clock_class:
113 return
114
115 return self._event_notification.event.clock_value(clock_class)
116
117 @property
118 def cycles(self):
119 """
120 Event timestamp in cycles or -1 on error.
121 """
122
123 try:
124 clock_value = self._clock_value()
125 except bt2.Error:
126 return -1
127
128 if clock_value is not None:
129 return clock_value.cycles
130 else:
131 return -1
132
133 @property
134 def timestamp(self):
135 """
136 Event timestamp (nanoseconds since Epoch).
137 """
138
139 try:
140 clock_value = self._clock_value()
141 except bt2.Error:
142 raise RuntimeError("Failed to get event timestamp")
143
144 if clock_value is not None:
145 return clock_value.ns_from_epoch
146 else:
147 raise RuntimeError("Failed to get event timestamp")
148
149 @property
150 def datetime(self):
151 """
152 Event timestamp as a standard :class:`datetime.datetime`
153 object.
154
155 Note that the :class:`datetime.datetime` class' precision
156 is limited to microseconds, whereas :attr:`timestamp` provides
157 the event's timestamp with a nanosecond resolution.
158 """
159
160 return datetime.date.fromtimestamp(self.timestamp / 1E9)
161
162 def field_with_scope(self, field_name, scope):
163 """
164 Returns the value of a field named *field_name* within the
165 scope *scope*, or ``None`` if the field cannot be found.
166
167 *scope* must be one of :class:`babeltrace.common.CTFScope`
168 constants.
169 """
170
171 if scope not in _SCOPES:
172 raise ValueError("Invalid scope provided")
173
174 field = self._field_with_scope(field_name, scope)
175
176 if field is not None:
177 return field.value
178
179 def field_list_with_scope(self, scope):
180 """
181 Returns a list of field names in the scope *scope*.
182 """
183
184 if scope not in _SCOPES:
185 raise ValueError("Invalid scope provided")
186
187 field_names = []
188
189 for field in self._field_list_with_scope(scope):
190 field_names.append(field.name)
191
192 return field_names
193
194 @property
195 def handle(self):
196 """
197 :class:`TraceHandle` object containing this event, or ``None``
198 on error.
199 """
200
201 try:
202 return self._trace_handle
203 except AttributeError:
204 return None
205
206 @property
207 def trace_collection(self):
208 """
209 :class:`TraceCollection` object containing this event, or
210 ``None`` on error.
211 """
212
213 try:
214 return self._trace_collection
215 except AttributeError:
216 return
217
218 def __getitem__(self, field_name):
219 field = self._field(field_name)
220 if field is None:
221 raise KeyError(field_name)
222 return field.value
223
224 def __iter__(self):
225 for key in self.keys():
226 yield key
227
228 def __len__(self):
229 count = 0
230 for scope in _SCOPES:
231 scope_field = self._get_scope_field(scope)
232 if scope_field is not None and isinstance(scope_field,
233 bt2._StructureField):
234 count += len(scope_field)
235 return count
236
237 def __contains__(self, field_name):
238 return self._field(field_name) is not None
239
240 def keys(self):
241 """
242 Returns the list of field names.
243
244 Note: field names are unique within the returned list, although
245 a field name could exist in multiple scopes. Use
246 :meth:`field_list_with_scope` to obtain the list of field names
247 of a given scope.
248 """
249
250 field_names = set()
251
252 for scope in _SCOPES:
253 for name in self.field_list_with_scope(scope):
254 field_names.add(name)
255
256 return list(field_names)
257
258 def get(self, field_name, default=None):
259 """
260 Returns the value of the field named *field_name*, or *default*
261 when not found.
262
263 See :class:`Event` note about how fields are retrieved by
264 name when multiple fields share the same name in different
265 scopes.
266 """
267
268 field = self._field(field_name)
269
270 if field is None:
271 return default
272
273 return field.value
274
275 def items(self):
276 """
277 Generates pairs of (field name, field value).
278
279 This method iterates :meth:`keys` to find field names, which
280 means some fields could be unavailable if other fields share
281 their names in scopes with higher priorities.
282 """
283
284 for field in self.keys():
285 yield (field, self[field])
286
287 def _get_scope_field(self, scope):
288 try:
289 event = self._event_notification.event
290 if scope is common.CTFScope.EVENT_FIELDS:
291 return event.payload_field
292
293 if scope is common.CTFScope.EVENT_CONTEXT:
294 return event.context_field
295
296 if scope is common.CTFScope.STREAM_EVENT_CONTEXT:
297 return event.stream_event_context_field
298
299 if scope is common.CTFScope.STREAM_EVENT_HEADER:
300 return event.header_field
301
302 if scope is common.CTFScope.STREAM_PACKET_CONTEXT:
303 return event.packet.context_field
304
305 if scope is common.CTFScope.TRACE_PACKET_HEADER:
306 return event.packet.header_field
307 except bt2.Error:
308 return
309
310 raise ValueError("Invalid scope provided")
311
312 def _field_with_scope(self, field_name, scope):
313 scope_field = self._get_scope_field(scope)
314 if scope_field is not None:
315 try:
316 bt2_field = scope_field[field_name]
317 if bt2_field is not None:
318 return field_definition._Definition(scope, bt2_field,
319 field_name)
320 except (KeyError, bt2.Error):
321 return None
322
323 def _field(self, field_name):
324 for scope in _SCOPES:
325 field = self._field_with_scope(field_name, scope)
326 if field is not None:
327 return field
328
329 def _field_list_with_scope(self, scope):
330 fields = []
331 scope_field = self._get_scope_field(scope)
332
333 if scope_field is None or not isinstance(scope_field,
334 bt2._StructureField):
335 return fields
336
337 for name, field in scope_field.items():
338 fields.append(field_definition._Definition(scope, field, name))
339
340 return fields
341
342
343 # Priority of the scopes when searching for event fields
344 _SCOPES = [
345 common.CTFScope.EVENT_FIELDS,
346 common.CTFScope.EVENT_CONTEXT,
347 common.CTFScope.STREAM_EVENT_CONTEXT,
348 common.CTFScope.STREAM_EVENT_HEADER,
349 common.CTFScope.STREAM_PACKET_CONTEXT,
350 common.CTFScope.TRACE_PACKET_HEADER
351 ]
This page took 0.037019 seconds and 4 git commands to generate.