fix: relayd: unaligned access in trace_chunk_registry_ht_key_hash
[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 def __eq__(self, other):
111 # type (LogLevelRule) -> bool
112 if type(self) != type(other):
113 return False
114
115 return self.level == other.level
116
117
118 @enum.unique
119 class LogLevel(enum.Enum):
120 pass
121
122
123 @enum.unique
124 class UserLogLevel(LogLevel):
125 EMERGENCY = 0
126 ALERT = 1
127 CRITICAL = 2
128 ERROR = 3
129 WARNING = 4
130 NOTICE = 5
131 INFO = 6
132 DEBUG_SYSTEM = 7
133 DEBUG_PROGRAM = 8
134 DEBUG_PROCESS = 9
135 DEBUG_MODULE = 10
136 DEBUG_UNIT = 11
137 DEBUG_FUNCTION = 12
138 DEBUG_LINE = 13
139 DEBUG = 14
140
141
142 @enum.unique
143 class JULLogLevel(LogLevel):
144 OFF = 2147483647
145 SEVERE = 1000
146 WARNING = 900
147 INFO = 800
148 CONFIG = 700
149 FINE = 500
150 FINER = 400
151 FINEST = 300
152 ALL = -2147483648
153
154
155 @enum.unique
156 class Log4jLogLevel(LogLevel):
157 OFF = 2147483647
158 FATAL = 50000
159 ERROR = 40000
160 WARN = 30000
161 INFO = 20000
162 DEBUG = 10000
163 TRACE = 5000
164 ALL = -2147483648
165
166
167 @enum.unique
168 class PythonLogLevel(LogLevel):
169 CRITICAL = 50
170 ERROR = 40
171 WARNING = 30
172 INFO = 20
173 DEBUG = 10
174 NOTSET = 0
175
176
177 class LogLevelRuleAsSevereAs(LogLevelRule):
178 def __init__(self, level):
179 # type: (LogLevel)
180 self._level = level
181
182 @property
183 def level(self):
184 # type: () -> LogLevel
185 return self._level
186
187
188 class LogLevelRuleExactly(LogLevelRule):
189 def __init__(self, level):
190 # type: (LogLevel)
191 self._level = level
192
193 @property
194 def level(self):
195 # type: () -> LogLevel
196 return self._level
197
198
199 class TracepointEventRule(EventRule):
200 def __init__(
201 self,
202 name_pattern=None, # type: Optional[str]
203 filter_expression=None, # type: Optional[str]
204 ):
205 self._name_pattern = name_pattern # type: Optional[str]
206 self._filter_expression = filter_expression # type: Optional[str]
207
208 def _equals(self, other):
209 # type (TracepointEventRule) -> bool
210 # Overridden by derived classes that have supplementary attributes.
211 return True
212
213 def __eq__(self, other):
214 # type (TracepointEventRule) -> bool
215 if type(self) != type(other):
216 return False
217
218 if self.name_pattern != other.name_pattern:
219 return False
220
221 if self.filter_expression != other.filter_expression:
222 return False
223
224 return self._equals(other)
225
226 @property
227 def name_pattern(self):
228 # type: () -> Optional[str]
229 return self._name_pattern
230
231 @property
232 def filter_expression(self):
233 # type: () -> Optional[str]
234 return self._filter_expression
235
236
237 class UserTracepointEventRule(TracepointEventRule):
238 def __init__(
239 self,
240 name_pattern=None, # type: Optional[str]
241 filter_expression=None, # type: Optional[str]
242 log_level_rule=None, # type: Optional[LogLevelRule]
243 name_pattern_exclusions=None, # type: Optional[List[str]]
244 ):
245 TracepointEventRule.__init__(self, name_pattern, filter_expression)
246 self._log_level_rule = log_level_rule # type: Optional[LogLevelRule]
247 self._name_pattern_exclusions = (
248 name_pattern_exclusions
249 ) # type: Optional[List[str]]
250
251 if log_level_rule and not isinstance(log_level_rule.level, UserLogLevel):
252 raise ValueError("Log level rule must use a UserLogLevel as its value")
253
254 def _equals(self, other):
255 # type (UserTracepointEventRule) -> bool
256 return (
257 self.log_level_rule == other.log_level_rule
258 and self.name_pattern_exclusions == other.name_pattern_exclusions
259 )
260
261 @property
262 def log_level_rule(self):
263 # type: () -> Optional[LogLevelRule]
264 return self._log_level_rule
265
266 @property
267 def name_pattern_exclusions(self):
268 # type: () -> Optional[List[str]]
269 return self._name_pattern_exclusions
270
271
272 class Log4jTracepointEventRule(TracepointEventRule):
273 def __init__(
274 self,
275 name_pattern=None, # type: Optional[str]
276 filter_expression=None, # type: Optional[str]
277 log_level_rule=None, # type: Optional[LogLevelRule]
278 name_pattern_exclusions=None, # type: Optional[List[str]]
279 ):
280 TracepointEventRule.__init__(self, name_pattern, filter_expression)
281 self._log_level_rule = log_level_rule # type: Optional[LogLevelRule]
282 self._name_pattern_exclusions = (
283 name_pattern_exclusions
284 ) # type: Optional[List[str]]
285
286 if log_level_rule and not isinstance(log_level_rule.level, Log4jLogLevel):
287 raise ValueError("Log level rule must use a Log4jLogLevel as its value")
288
289 def _equals(self, other):
290 # type (Log4jTracepointEventRule) -> bool
291 return (
292 self.log_level_rule == other.log_level_rule
293 and self.name_pattern_exclusions == other.name_pattern_exclusions
294 )
295
296 @property
297 def log_level_rule(self):
298 # type: () -> Optional[LogLevelRule]
299 return self._log_level_rule
300
301 @property
302 def name_pattern_exclusions(self):
303 # type: () -> Optional[List[str]]
304 return self._name_pattern_exclusions
305
306
307 class JULTracepointEventRule(TracepointEventRule):
308 def __init__(
309 self,
310 name_pattern=None, # type: Optional[str]
311 filter_expression=None, # type: Optional[str]
312 log_level_rule=None, # type: Optional[LogLevelRule]
313 name_pattern_exclusions=None, # type: Optional[List[str]]
314 ):
315 TracepointEventRule.__init__(self, name_pattern, filter_expression)
316 self._log_level_rule = log_level_rule # type: Optional[LogLevelRule]
317 self._name_pattern_exclusions = (
318 name_pattern_exclusions
319 ) # type: Optional[List[str]]
320
321 if log_level_rule and not isinstance(log_level_rule.level, JULLogLevel):
322 raise ValueError("Log level rule must use a JULLogLevel as its value")
323
324 def _equals(self, other):
325 # type (JULTracepointEventRule) -> bool
326 return (
327 self.log_level_rule == other.log_level_rule
328 and self.name_pattern_exclusions == other.name_pattern_exclusions
329 )
330
331 @property
332 def log_level_rule(self):
333 # type: () -> Optional[LogLevelRule]
334 return self._log_level_rule
335
336 @property
337 def name_pattern_exclusions(self):
338 # type: () -> Optional[List[str]]
339 return self._name_pattern_exclusions
340
341
342 class PythonTracepointEventRule(TracepointEventRule):
343 def __init__(
344 self,
345 name_pattern=None, # type: Optional[str]
346 filter_expression=None, # type: Optional[str]
347 log_level_rule=None, # type: Optional[LogLevelRule]
348 name_pattern_exclusions=None, # type: Optional[List[str]]
349 ):
350 TracepointEventRule.__init__(self, name_pattern, filter_expression)
351 self._log_level_rule = log_level_rule # type: Optional[LogLevelRule]
352 self._name_pattern_exclusions = (
353 name_pattern_exclusions
354 ) # type: Optional[List[str]]
355
356 if log_level_rule and not isinstance(log_level_rule.level, PythonLogLevel):
357 raise ValueError("Log level rule must use a PythonLogLevel as its value")
358
359 def _equals(self, other):
360 # type (PythonTracepointEventRule) -> bool
361 return (
362 self.log_level_rule == other.log_level_rule
363 and self.name_pattern_exclusions == other.name_pattern_exclusions
364 )
365
366 @property
367 def log_level_rule(self):
368 # type: () -> Optional[LogLevelRule]
369 return self._log_level_rule
370
371 @property
372 def name_pattern_exclusions(self):
373 # type: () -> Optional[List[str]]
374 return self._name_pattern_exclusions
375
376
377 class KernelTracepointEventRule(TracepointEventRule):
378 def __init__(
379 self,
380 name_pattern=None, # type: Optional[str]
381 filter_expression=None, # type: Optional[str]
382 ):
383 TracepointEventRule.__init__(**locals())
384
385
386 class Channel(abc.ABC):
387 """
388 A channel is an object which is responsible for a set of ring buffers. It is
389 associated to a domain and
390 """
391
392 @staticmethod
393 def _generate_name():
394 # type: () -> str
395 return "channel_{random_id}".format(random_id=_generate_random_string(8))
396
397 @abc.abstractmethod
398 def add_context(self, context_type):
399 # type: (ContextType) -> None
400 raise NotImplementedError
401
402 @property
403 @abc.abstractmethod
404 def domain(self):
405 # type: () -> TracingDomain
406 raise NotImplementedError
407
408 @property
409 @abc.abstractmethod
410 def name(self):
411 # type: () -> str
412 raise NotImplementedError
413
414 @abc.abstractmethod
415 def add_recording_rule(self, rule) -> None:
416 # type: (Type[EventRule]) -> None
417 raise NotImplementedError
418
419
420 class SessionOutputLocation(abc.ABC):
421 pass
422
423
424 class LocalSessionOutputLocation(SessionOutputLocation):
425 def __init__(self, trace_path):
426 # type: (pathlib.Path)
427 self._path = trace_path
428
429 @property
430 def path(self):
431 # type: () -> pathlib.Path
432 return self._path
433
434
435 class NetworkSessionOutputLocation(SessionOutputLocation):
436 def __init__(self, set_url):
437 # type (str)
438 self._set_url = set_url
439
440 @property
441 def url(self):
442 # type: () -> str
443 return self._set_url
444
445
446 class ProcessAttributeTracker(abc.ABC):
447 """
448 Process attribute tracker used to filter before the evaluation of event
449 rules.
450
451 Note that this interface is currently limited as it doesn't allow changing
452 the tracking policy. For instance, it is not possible to set the tracking
453 policy back to "all" once it has transitioned to "include set".
454 """
455
456 @enum.unique
457 class TrackingPolicy(enum.Enum):
458 INCLUDE_ALL = """
459 Track all possible process attribute value of a given type (i.e. no filtering).
460 This is the default state of a process attribute tracker.
461 """
462 EXCLUDE_ALL = "Exclude all possible process attribute values of a given type."
463 INCLUDE_SET = "Track a set of specific process attribute values."
464
465 def __repr__(self):
466 return "<%s.%s>" % (self.__class__.__name__, self.name)
467
468 def __init__(self, policy):
469 # type: (TrackingPolicy)
470 self._policy = policy
471
472 @property
473 def tracking_policy(self):
474 # type: () -> TrackingPolicy
475 return self._policy
476
477
478 class ProcessIDProcessAttributeTracker(ProcessAttributeTracker):
479 @abc.abstractmethod
480 def track(self, pid):
481 # type: (int) -> None
482 raise NotImplementedError
483
484 @abc.abstractmethod
485 def untrack(self, pid):
486 # type: (int) -> None
487 raise NotImplementedError
488
489
490 class VirtualProcessIDProcessAttributeTracker(ProcessAttributeTracker):
491 @abc.abstractmethod
492 def track(self, vpid):
493 # type: (int) -> None
494 raise NotImplementedError
495
496 @abc.abstractmethod
497 def untrack(self, vpid):
498 # type: (int) -> None
499 raise NotImplementedError
500
501
502 class UserIDProcessAttributeTracker(ProcessAttributeTracker):
503 @abc.abstractmethod
504 def track(self, uid):
505 # type: (Union[int, str]) -> None
506 raise NotImplementedError
507
508 @abc.abstractmethod
509 def untrack(self, uid):
510 # type: (Union[int, str]) -> None
511 raise NotImplementedError
512
513
514 class VirtualUserIDProcessAttributeTracker(ProcessAttributeTracker):
515 @abc.abstractmethod
516 def track(self, vuid):
517 # type: (Union[int, str]) -> None
518 raise NotImplementedError
519
520 @abc.abstractmethod
521 def untrack(self, vuid):
522 # type: (Union[int, str]) -> None
523 raise NotImplementedError
524
525
526 class GroupIDProcessAttributeTracker(ProcessAttributeTracker):
527 @abc.abstractmethod
528 def track(self, gid):
529 # type: (Union[int, str]) -> None
530 raise NotImplementedError
531
532 @abc.abstractmethod
533 def untrack(self, gid):
534 # type: (Union[int, str]) -> None
535 raise NotImplementedError
536
537
538 class VirtualGroupIDProcessAttributeTracker(ProcessAttributeTracker):
539 @abc.abstractmethod
540 def track(self, vgid):
541 # type: (Union[int, str]) -> None
542 raise NotImplementedError
543
544 @abc.abstractmethod
545 def untrack(self, vgid):
546 # type: (Union[int, str]) -> None
547 raise NotImplementedError
548
549
550 class Session(abc.ABC):
551 @staticmethod
552 def _generate_name():
553 # type: () -> str
554 return "session_{random_id}".format(random_id=_generate_random_string(8))
555
556 @property
557 @abc.abstractmethod
558 def name(self):
559 # type: () -> str
560 raise NotImplementedError
561
562 @property
563 @abc.abstractmethod
564 def output(self):
565 # type: () -> Optional[Type[SessionOutputLocation]]
566 raise NotImplementedError
567
568 @abc.abstractmethod
569 def add_channel(
570 self,
571 domain,
572 channel_name=None,
573 buffer_sharing_policy=BufferSharingPolicy.PerUID,
574 ):
575 # type: (TracingDomain, Optional[str], BufferSharingPolicy) -> Channel
576 """Add a channel with default attributes to the session."""
577 raise NotImplementedError
578
579 @abc.abstractmethod
580 def start(self):
581 # type: () -> None
582 raise NotImplementedError
583
584 @abc.abstractmethod
585 def stop(self):
586 # type: () -> None
587 raise NotImplementedError
588
589 @abc.abstractmethod
590 def destroy(self):
591 # type: () -> None
592 raise NotImplementedError
593
594 @abc.abstractmethod
595 def is_active(self):
596 # type: () -> bool
597 raise NotImplementedError
598
599 @abc.abstractmethod
600 def rotate(self):
601 # type: () -> None
602 raise NotImplementedError
603
604 @abc.abstractproperty
605 def kernel_pid_process_attribute_tracker(self):
606 # type: () -> Type[ProcessIDProcessAttributeTracker]
607 raise NotImplementedError
608
609 @abc.abstractproperty
610 def kernel_vpid_process_attribute_tracker(self):
611 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
612 raise NotImplementedError
613
614 @abc.abstractproperty
615 def user_vpid_process_attribute_tracker(
616 self,
617 ) -> Type[VirtualProcessIDProcessAttributeTracker]:
618 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
619 raise NotImplementedError
620
621 @abc.abstractproperty
622 def kernel_gid_process_attribute_tracker(self):
623 # type: () -> Type[GroupIDProcessAttributeTracker]
624 raise NotImplementedError
625
626 @abc.abstractproperty
627 def kernel_vgid_process_attribute_tracker(self):
628 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
629 raise NotImplementedError
630
631 @abc.abstractproperty
632 def user_vgid_process_attribute_tracker(self):
633 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
634 raise NotImplementedError
635
636 @abc.abstractproperty
637 def kernel_uid_process_attribute_tracker(self):
638 # type: () -> Type[UserIDProcessAttributeTracker]
639 raise NotImplementedError
640
641 @abc.abstractproperty
642 def kernel_vuid_process_attribute_tracker(self):
643 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
644 raise NotImplementedError
645
646 @abc.abstractproperty
647 def user_vuid_process_attribute_tracker(self):
648 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
649 raise NotImplementedError
650
651
652 class ControlException(RuntimeError):
653 """Base type for exceptions thrown by a controller."""
654
655 def __init__(self, msg):
656 # type: (str)
657 super().__init__(msg)
658
659
660 class Controller(abc.ABC):
661 """
662 Interface of a top-level control interface. A control interface can be, for
663 example, the LTTng client or a wrapper around liblttng-ctl. It is used to
664 create and manage top-level objects of a session daemon instance.
665 """
666
667 @abc.abstractmethod
668 def create_session(self, name=None, output=None):
669 # type: (Optional[str], Optional[SessionOutputLocation]) -> Session
670 """
671 Create a session with an output. Don't specify an output
672 to create a session without an output.
673 """
674 raise NotImplementedError
675
676 @abc.abstractmethod
677 def start_session_by_name(self, name):
678 # type: (str) -> None
679 """
680 Start a session by name.
681 """
682 raise NotImplementedError
683
684 @abc.abstractmethod
685 def start_session_by_glob_pattern(self, pattern):
686 # type: (str) -> None
687 """
688 Start sessions whose name matches `pattern`, see GLOB(7).
689 """
690 raise NotImplementedError
691
692 @abc.abstractmethod
693 def start_sessions_all(self):
694 """
695 Start all sessions visible to the current user.
696 """
697 # type: () -> None
698 raise NotImplementedError
699
700 @abc.abstractmethod
701 def stop_session_by_name(self, name):
702 # type: (str) -> None
703 """
704 Stop a session by name.
705 """
706 raise NotImplementedError
707
708 @abc.abstractmethod
709 def stop_session_by_glob_pattern(self, pattern):
710 # type: (str) -> None
711 """
712 Stop sessions whose name matches `pattern`, see GLOB(7).
713 """
714 raise NotImplementedError
715
716 @abc.abstractmethod
717 def stop_sessions_all(self):
718 """
719 Stop all sessions visible to the current user.
720 """
721 # type: () -> None
722 raise NotImplementedError
723
724 @abc.abstractmethod
725 def destroy_session_by_name(self, name):
726 # type: (str) -> None
727 """
728 Destroy a session by name.
729 """
730 raise NotImplementedError
731
732 @abc.abstractmethod
733 def destroy_session_by_glob_pattern(self, pattern):
734 # type: (str) -> None
735 """
736 Destroy sessions whose name matches `pattern`, see GLOB(7).
737 """
738 raise NotImplementedError
739
740 @abc.abstractmethod
741 def destroy_sessions_all(self):
742 # type: () -> None
743 """
744 Destroy all sessions visible to the current user.
745 """
746 raise NotImplementedError
747
748 @abc.abstractmethod
749 def list_sessions(self):
750 # type: () -> List[Session]
751 """
752 List all sessions visible to the current user.
753 """
754 raise NotImplementedError
755
756 @abc.abstractmethod
757 def rotate_session_by_name(self, name, wait=True):
758 # type: (str, bool) -> None
759 """
760 Rotate a session
761 """
762 raise NotImplementedError
763
764 @abc.abstractmethod
765 def schedule_size_based_rotation(self, name, size_bytes):
766 # type: (str, int) -> None
767 """
768 Schedule automatic size-based rotations.
769 """
770 raise NotImplementedError
771
772 @abc.abstractmethod
773 def schedule_time_based_rotation(self, name, period_seconds):
774 # type: (str, int) -> None
775 """
776 Schedule automatic time-based rotations.
777 """
778 raise NotImplementedError
This page took 0.051444 seconds and 4 git commands to generate.