Tests: lttngctl.py: allow the creation of per-pid buffers
[lttng-tools.git] / tests / utils / lttngtest / lttngctl.py
1 #!/usr/bin/env python3
2 #
3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 #
5 # SPDX-License-Identifier: GPL-2.0-only
6
7 import abc
8 import random
9 import string
10 import pathlib
11 import enum
12 from typing import Optional, Type, Union, List
13
14 """
15 Defines an abstract interface to control LTTng tracing.
16
17 The various control concepts are defined by this module. You can use them with a
18 Controller to interact with a session daemon.
19
20 This interface is not comprehensive; it currently provides a subset of the
21 control functionality that is used by tests.
22 """
23
24
25 def _generate_random_string(length):
26 # type: (int) -> str
27 return "".join(
28 random.choice(string.ascii_lowercase + string.digits) for _ in range(length)
29 )
30
31
32 class ContextType(abc.ABC):
33 """Base class representing a tracing context field."""
34
35 pass
36
37
38 class VpidContextType(ContextType):
39 """Application's virtual process id."""
40
41 pass
42
43
44 class VuidContextType(ContextType):
45 """Application's virtual user id."""
46
47 pass
48
49
50 class VgidContextType(ContextType):
51 """Application's virtual group id."""
52
53 pass
54
55
56 class JavaApplicationContextType(ContextType):
57 """A java application-specific context field is a piece of state which the application provides."""
58
59 def __init__(
60 self,
61 retriever_name, # type: str
62 field_name, # type: str
63 ):
64 self._retriever_name = retriever_name # type: str
65 self._field_name = field_name # type: str
66
67 @property
68 def retriever_name(self):
69 # type: () -> str
70 return self._retriever_name
71
72 @property
73 def field_name(self):
74 # type: () -> str
75 return self._field_name
76
77
78 @enum.unique
79 class TracingDomain(enum.Enum):
80 """Tracing domain."""
81
82 User = "User space tracing domain"
83 Kernel = "Linux kernel tracing domain."
84 Log4j = "Log4j tracing back-end."
85 JUL = "Java Util Logging tracing back-end."
86 Python = "Python logging module tracing back-end."
87
88 def __repr__(self):
89 return "<%s.%s>" % (self.__class__.__name__, self.name)
90
91
92 @enum.unique
93 class BufferSharingPolicy(enum.Enum):
94 """Buffer sharing policy."""
95
96 PerUID = "Per-UID buffering"
97 PerPID = "Per-PID buffering"
98
99 def __repr__(self):
100 return "<%s.%s>" % (self.__class__.__name__, self.name)
101
102
103 class EventRule(abc.ABC):
104 """Event rule base class, see LTTNG-EVENT-RULE(7)."""
105
106 pass
107
108
109 class LogLevelRule:
110 pass
111
112
113 class LogLevelRuleAsSevereAs(LogLevelRule):
114 def __init__(self, level):
115 # type: (int)
116 self._level = level
117
118 @property
119 def level(self):
120 # type: () -> int
121 return self._level
122
123
124 class LogLevelRuleExactly(LogLevelRule):
125 def __init__(self, level):
126 # type: (int)
127 self._level = level
128
129 @property
130 def level(self):
131 # type: () -> int
132 return self._level
133
134
135 class TracepointEventRule(EventRule):
136 def __init__(
137 self,
138 name_pattern=None, # type: Optional[str]
139 filter_expression=None, # type: Optional[str]
140 log_level_rule=None, # type: Optional[LogLevelRule]
141 name_pattern_exclusions=None, # type: Optional[List[str]]
142 ):
143 self._name_pattern = name_pattern # type: Optional[str]
144 self._filter_expression = filter_expression # type: Optional[str]
145 self._log_level_rule = log_level_rule # type: Optional[LogLevelRule]
146 self._name_pattern_exclusions = (
147 name_pattern_exclusions
148 ) # type: Optional[List[str]]
149
150 @property
151 def name_pattern(self):
152 # type: () -> Optional[str]
153 return self._name_pattern
154
155 @property
156 def filter_expression(self):
157 # type: () -> Optional[str]
158 return self._filter_expression
159
160 @property
161 def log_level_rule(self):
162 # type: () -> Optional[LogLevelRule]
163 return self._log_level_rule
164
165 @property
166 def name_pattern_exclusions(self):
167 # type: () -> Optional[List[str]]
168 return self._name_pattern_exclusions
169
170
171 class UserTracepointEventRule(TracepointEventRule):
172 def __init__(
173 self,
174 name_pattern=None, # type: Optional[str]
175 filter_expression=None, # type: Optional[str]
176 log_level_rule=None, # type: Optional[LogLevelRule]
177 name_pattern_exclusions=None, # type: Optional[List[str]]
178 ):
179 TracepointEventRule.__init__(**locals())
180
181
182 class KernelTracepointEventRule(TracepointEventRule):
183 def __init__(
184 self,
185 name_pattern=None, # type: Optional[str]
186 filter_expression=None, # type: Optional[str]
187 log_level_rule=None, # type: Optional[LogLevelRule]
188 name_pattern_exclusions=None, # type: Optional[List[str]]
189 ):
190 TracepointEventRule.__init__(**locals())
191
192
193 class Channel(abc.ABC):
194 """
195 A channel is an object which is responsible for a set of ring buffers. It is
196 associated to a domain and
197 """
198
199 @staticmethod
200 def _generate_name():
201 # type: () -> str
202 return "channel_{random_id}".format(random_id=_generate_random_string(8))
203
204 @abc.abstractmethod
205 def add_context(self, context_type):
206 # type: (ContextType) -> None
207 pass
208
209 @property
210 @abc.abstractmethod
211 def domain(self):
212 # type: () -> TracingDomain
213 pass
214
215 @property
216 @abc.abstractmethod
217 def name(self):
218 # type: () -> str
219 pass
220
221 @abc.abstractmethod
222 def add_recording_rule(self, rule) -> None:
223 # type: (Type[EventRule]) -> None
224 pass
225
226
227 class SessionOutputLocation(abc.ABC):
228 pass
229
230
231 class LocalSessionOutputLocation(SessionOutputLocation):
232 def __init__(self, trace_path):
233 # type: (pathlib.Path)
234 self._path = trace_path
235
236 @property
237 def path(self):
238 # type: () -> pathlib.Path
239 return self._path
240
241
242 class ProcessAttributeTracker(abc.ABC):
243 """
244 Process attribute tracker used to filter before the evaluation of event
245 rules.
246
247 Note that this interface is currently limited as it doesn't allow changing
248 the tracking policy. For instance, it is not possible to set the tracking
249 policy back to "all" once it has transitioned to "include set".
250 """
251
252 @enum.unique
253 class TrackingPolicy(enum.Enum):
254 INCLUDE_ALL = """
255 Track all possible process attribute value of a given type (i.e. no filtering).
256 This is the default state of a process attribute tracker.
257 """
258 EXCLUDE_ALL = "Exclude all possible process attribute values of a given type."
259 INCLUDE_SET = "Track a set of specific process attribute values."
260
261 def __repr__(self):
262 return "<%s.%s>" % (self.__class__.__name__, self.name)
263
264 def __init__(self, policy):
265 # type: (TrackingPolicy)
266 self._policy = policy
267
268 @property
269 def tracking_policy(self):
270 # type: () -> TrackingPolicy
271 return self._policy
272
273
274 class ProcessIDProcessAttributeTracker(ProcessAttributeTracker):
275 @abc.abstractmethod
276 def track(self, pid):
277 # type: (int) -> None
278 pass
279
280 @abc.abstractmethod
281 def untrack(self, pid):
282 # type: (int) -> None
283 pass
284
285
286 class VirtualProcessIDProcessAttributeTracker(ProcessAttributeTracker):
287 @abc.abstractmethod
288 def track(self, vpid):
289 # type: (int) -> None
290 pass
291
292 @abc.abstractmethod
293 def untrack(self, vpid):
294 # type: (int) -> None
295 pass
296
297
298 class UserIDProcessAttributeTracker(ProcessAttributeTracker):
299 @abc.abstractmethod
300 def track(self, uid):
301 # type: (Union[int, str]) -> None
302 pass
303
304 @abc.abstractmethod
305 def untrack(self, uid):
306 # type: (Union[int, str]) -> None
307 pass
308
309
310 class VirtualUserIDProcessAttributeTracker(ProcessAttributeTracker):
311 @abc.abstractmethod
312 def track(self, vuid):
313 # type: (Union[int, str]) -> None
314 pass
315
316 @abc.abstractmethod
317 def untrack(self, vuid):
318 # type: (Union[int, str]) -> None
319 pass
320
321
322 class GroupIDProcessAttributeTracker(ProcessAttributeTracker):
323 @abc.abstractmethod
324 def track(self, gid):
325 # type: (Union[int, str]) -> None
326 pass
327
328 @abc.abstractmethod
329 def untrack(self, gid):
330 # type: (Union[int, str]) -> None
331 pass
332
333
334 class VirtualGroupIDProcessAttributeTracker(ProcessAttributeTracker):
335 @abc.abstractmethod
336 def track(self, vgid):
337 # type: (Union[int, str]) -> None
338 pass
339
340 @abc.abstractmethod
341 def untrack(self, vgid):
342 # type: (Union[int, str]) -> None
343 pass
344
345
346 class Session(abc.ABC):
347 @staticmethod
348 def _generate_name():
349 # type: () -> str
350 return "session_{random_id}".format(random_id=_generate_random_string(8))
351
352 @property
353 @abc.abstractmethod
354 def name(self):
355 # type: () -> str
356 pass
357
358 @property
359 @abc.abstractmethod
360 def output(self):
361 # type: () -> Optional[Type[SessionOutputLocation]]
362 pass
363
364 @abc.abstractmethod
365 def add_channel(
366 self,
367 domain,
368 channel_name=None,
369 buffer_sharing_policy=BufferSharingPolicy.PerUID,
370 ):
371 # type: (TracingDomain, Optional[str], BufferSharingPolicy) -> Channel
372 """Add a channel with default attributes to the session."""
373 pass
374
375 @abc.abstractmethod
376 def start(self):
377 # type: () -> None
378 pass
379
380 @abc.abstractmethod
381 def stop(self):
382 # type: () -> None
383 pass
384
385 @abc.abstractmethod
386 def destroy(self):
387 # type: () -> None
388 pass
389
390 @abc.abstractmethod
391 def is_active(self):
392 # type: () -> bool
393 pass
394
395 @abc.abstractproperty
396 def kernel_pid_process_attribute_tracker(self):
397 # type: () -> Type[ProcessIDProcessAttributeTracker]
398 raise NotImplementedError
399
400 @abc.abstractproperty
401 def kernel_vpid_process_attribute_tracker(self):
402 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
403 raise NotImplementedError
404
405 @abc.abstractproperty
406 def user_vpid_process_attribute_tracker(
407 self,
408 ) -> Type[VirtualProcessIDProcessAttributeTracker]:
409 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
410 raise NotImplementedError
411
412 @abc.abstractproperty
413 def kernel_gid_process_attribute_tracker(self):
414 # type: () -> Type[GroupIDProcessAttributeTracker]
415 raise NotImplementedError
416
417 @abc.abstractproperty
418 def kernel_vgid_process_attribute_tracker(self):
419 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
420 raise NotImplementedError
421
422 @abc.abstractproperty
423 def user_vgid_process_attribute_tracker(self):
424 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
425 raise NotImplementedError
426
427 @abc.abstractproperty
428 def kernel_uid_process_attribute_tracker(self):
429 # type: () -> Type[UserIDProcessAttributeTracker]
430 raise NotImplementedError
431
432 @abc.abstractproperty
433 def kernel_vuid_process_attribute_tracker(self):
434 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
435 raise NotImplementedError
436
437 @abc.abstractproperty
438 def user_vuid_process_attribute_tracker(self):
439 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
440 raise NotImplementedError
441
442
443 class ControlException(RuntimeError):
444 """Base type for exceptions thrown by a controller."""
445
446 def __init__(self, msg):
447 # type: (str)
448 super().__init__(msg)
449
450
451 class Controller(abc.ABC):
452 """
453 Interface of a top-level control interface. A control interface can be, for
454 example, the LTTng client or a wrapper around liblttng-ctl. It is used to
455 create and manage top-level objects of a session daemon instance.
456 """
457
458 @abc.abstractmethod
459 def create_session(self, name=None, output=None):
460 # type: (Optional[str], Optional[SessionOutputLocation]) -> Session
461 """
462 Create a session with an output. Don't specify an output
463 to create a session without an output.
464 """
465 pass
466
467 @abc.abstractmethod
468 def start_session_by_name(self, name):
469 # type: (str) -> None
470 """
471 Start a session by name.
472 """
473 pass
474
475 @abc.abstractmethod
476 def start_session_by_glob_pattern(self, pattern):
477 # type: (str) -> None
478 """
479 Start sessions whose name matches `pattern`, see GLOB(7).
480 """
481 pass
482
483 @abc.abstractmethod
484 def start_sessions_all(self):
485 """
486 Start all sessions visible to the current user.
487 """
488 # type: () -> None
489 pass
490
491 @abc.abstractmethod
492 def stop_session_by_name(self, name):
493 # type: (str) -> None
494 """
495 Stop a session by name.
496 """
497 pass
498
499 @abc.abstractmethod
500 def stop_session_by_glob_pattern(self, pattern):
501 # type: (str) -> None
502 """
503 Stop sessions whose name matches `pattern`, see GLOB(7).
504 """
505 pass
506
507 @abc.abstractmethod
508 def stop_sessions_all(self):
509 """
510 Stop all sessions visible to the current user.
511 """
512 # type: () -> None
513 pass
514
515 @abc.abstractmethod
516 def destroy_session_by_name(self, name):
517 # type: (str) -> None
518 """
519 Destroy a session by name.
520 """
521 pass
522
523 @abc.abstractmethod
524 def destroy_session_by_glob_pattern(self, pattern):
525 # type: (str) -> None
526 """
527 Destroy sessions whose name matches `pattern`, see GLOB(7).
528 """
529 pass
530
531 @abc.abstractmethod
532 def destroy_sessions_all(self):
533 # type: () -> None
534 """
535 Destroy all sessions visible to the current user.
536 """
537 pass
538
539 @abc.abstractmethod
540 def list_sessions(self):
541 # type: () -> List[Session]
542 """
543 List all sessions visible to the current user.
544 """
545 pass
This page took 0.039622 seconds and 4 git commands to generate.