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