3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 # SPDX-License-Identifier: GPL-2.0-only
12 from typing
import Optional
, Type
, Union
, List
15 Defines an abstract interface to control LTTng tracing.
17 The various control concepts are defined by this module. You can use them with a
18 Controller to interact with a session daemon.
20 This interface is not comprehensive; it currently provides a subset of the
21 control functionality that is used by tests.
25 def _generate_random_string(length
):
28 random
.choice(string
.ascii_lowercase
+ string
.digits
) for _
in range(length
)
32 class ContextType(abc
.ABC
):
33 """Base class representing a tracing context field."""
38 class VpidContextType(ContextType
):
39 """Application's virtual process id."""
44 class VuidContextType(ContextType
):
45 """Application's virtual user id."""
50 class VgidContextType(ContextType
):
51 """Application's virtual group id."""
56 class JavaApplicationContextType(ContextType
):
57 """A java application-specific context field is a piece of state which the application provides."""
61 retriever_name
, # type: str
62 field_name
, # type: str
64 self
._retriever
_name
= retriever_name
# type: str
65 self
._field
_name
= field_name
# type: str
68 def retriever_name(self
):
70 return self
._retriever
_name
75 return self
._field
_name
79 class TracingDomain(enum
.Enum
):
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."
90 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
94 class BufferSharingPolicy(enum
.Enum
):
95 """Buffer sharing policy."""
97 PerUID
= "Per-UID buffering"
98 PerPID
= "Per-PID buffering"
101 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
104 class EventRule(abc
.ABC
):
105 """Event rule base class, see LTTNG-EVENT-RULE(7)."""
111 def __eq__(self
, other
):
112 # type (LogLevelRule) -> bool
113 if type(self
) != type(other
):
116 return self
.level
== other
.level
120 class LogLevel(enum
.Enum
):
125 class UserLogLevel(LogLevel
):
144 class JULLogLevel(LogLevel
):
157 class Log4jLogLevel(LogLevel
):
169 class Log4j2LogLevel(LogLevel
):
181 class PythonLogLevel(LogLevel
):
190 class LogLevelRuleAsSevereAs(LogLevelRule
):
191 def __init__(self
, level
):
197 # type: () -> LogLevel
201 class LogLevelRuleExactly(LogLevelRule
):
202 def __init__(self
, level
):
208 # type: () -> LogLevel
212 class TracepointEventRule(EventRule
):
215 name_pattern
=None, # type: Optional[str]
216 filter_expression
=None, # type: Optional[str]
218 self
._name
_pattern
= name_pattern
# type: Optional[str]
219 self
._filter
_expression
= filter_expression
# type: Optional[str]
221 def _equals(self
, other
):
222 # type (TracepointEventRule) -> bool
223 # Overridden by derived classes that have supplementary attributes.
226 def __eq__(self
, other
):
227 # type (TracepointEventRule) -> bool
228 if type(self
) != type(other
):
231 if self
.name_pattern
!= other
.name_pattern
:
234 if self
.filter_expression
!= other
.filter_expression
:
237 return self
._equals
(other
)
240 def name_pattern(self
):
241 # type: () -> Optional[str]
242 return self
._name
_pattern
245 def filter_expression(self
):
246 # type: () -> Optional[str]
247 return self
._filter
_expression
250 class UserTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
267 def _equals(self
, other
):
268 # type (UserTracepointEventRule) -> bool
270 self
.log_level_rule
== other
.log_level_rule
271 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
275 def log_level_rule(self
):
276 # type: () -> Optional[LogLevelRule]
277 return self
._log
_level
_rule
280 def name_pattern_exclusions(self
):
281 # type: () -> Optional[List[str]]
282 return self
._name
_pattern
_exclusions
285 class Log4jTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
302 def _equals(self
, other
):
303 # type (Log4jTracepointEventRule) -> bool
305 self
.log_level_rule
== other
.log_level_rule
306 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
310 def log_level_rule(self
):
311 # type: () -> Optional[LogLevelRule]
312 return self
._log
_level
_rule
315 def name_pattern_exclusions(self
):
316 # type: () -> Optional[List[str]]
317 return self
._name
_pattern
_exclusions
320 class Log4j2TracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
337 def _equals(self
, other
):
338 # type (Log4jTracepointEventRule) -> bool
340 self
.log_level_rule
== other
.log_level_rule
341 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
345 def log_level_rule(self
):
346 # type: () -> Optional[LogLevelRule]
347 return self
._log
_level
_rule
350 def name_pattern_exclusions(self
):
351 # type: () -> Optional[List[str]]
352 return self
._name
_pattern
_exclusions
355 class JULTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
372 def _equals(self
, other
):
373 # type (JULTracepointEventRule) -> bool
375 self
.log_level_rule
== other
.log_level_rule
376 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
380 def log_level_rule(self
):
381 # type: () -> Optional[LogLevelRule]
382 return self
._log
_level
_rule
385 def name_pattern_exclusions(self
):
386 # type: () -> Optional[List[str]]
387 return self
._name
_pattern
_exclusions
390 class PythonTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
407 def _equals(self
, other
):
408 # type (PythonTracepointEventRule) -> bool
410 self
.log_level_rule
== other
.log_level_rule
411 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
415 def log_level_rule(self
):
416 # type: () -> Optional[LogLevelRule]
417 return self
._log
_level
_rule
420 def name_pattern_exclusions(self
):
421 # type: () -> Optional[List[str]]
422 return self
._name
_pattern
_exclusions
425 class KernelTracepointEventRule(TracepointEventRule
):
428 name_pattern
=None, # type: Optional[str]
429 filter_expression
=None, # type: Optional[str]
431 TracepointEventRule
.__init
__(**locals())
434 class Channel(abc
.ABC
):
436 A channel is an object which is responsible for a set of ring buffers. It is
437 associated to a domain and
441 def _generate_name():
443 return "channel_{random_id}".format(random_id
=_generate_random_string(8))
446 def add_context(self
, context_type
):
447 # type: (ContextType) -> None
448 raise NotImplementedError
453 # type: () -> TracingDomain
454 raise NotImplementedError
460 raise NotImplementedError
463 def add_recording_rule(self
, rule
) -> None:
464 # type: (Type[EventRule]) -> None
465 raise NotImplementedError
468 class SessionOutputLocation(abc
.ABC
):
472 class LocalSessionOutputLocation(SessionOutputLocation
):
473 def __init__(self
, trace_path
):
474 # type: (pathlib.Path)
475 self
._path
= trace_path
479 # type: () -> pathlib.Path
483 class NetworkSessionOutputLocation(SessionOutputLocation
):
484 def __init__(self
, set_url
):
486 self
._set
_url
= set_url
494 class ProcessAttributeTracker(abc
.ABC
):
496 Process attribute tracker used to filter before the evaluation of event
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".
505 class TrackingPolicy(enum
.Enum
):
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.
510 EXCLUDE_ALL
= "Exclude all possible process attribute values of a given type."
511 INCLUDE_SET
= "Track a set of specific process attribute values."
514 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
516 def __init__(self
, policy
):
517 # type: (TrackingPolicy)
518 self
._policy
= policy
521 def tracking_policy(self
):
522 # type: () -> TrackingPolicy
526 class ProcessIDProcessAttributeTracker(ProcessAttributeTracker
):
528 def track(self
, pid
):
529 # type: (int) -> None
530 raise NotImplementedError
533 def untrack(self
, pid
):
534 # type: (int) -> None
535 raise NotImplementedError
538 class VirtualProcessIDProcessAttributeTracker(ProcessAttributeTracker
):
540 def track(self
, vpid
):
541 # type: (int) -> None
542 raise NotImplementedError
545 def untrack(self
, vpid
):
546 # type: (int) -> None
547 raise NotImplementedError
550 class UserIDProcessAttributeTracker(ProcessAttributeTracker
):
552 def track(self
, uid
):
553 # type: (Union[int, str]) -> None
554 raise NotImplementedError
557 def untrack(self
, uid
):
558 # type: (Union[int, str]) -> None
559 raise NotImplementedError
562 class VirtualUserIDProcessAttributeTracker(ProcessAttributeTracker
):
564 def track(self
, vuid
):
565 # type: (Union[int, str]) -> None
566 raise NotImplementedError
569 def untrack(self
, vuid
):
570 # type: (Union[int, str]) -> None
571 raise NotImplementedError
574 class GroupIDProcessAttributeTracker(ProcessAttributeTracker
):
576 def track(self
, gid
):
577 # type: (Union[int, str]) -> None
578 raise NotImplementedError
581 def untrack(self
, gid
):
582 # type: (Union[int, str]) -> None
583 raise NotImplementedError
586 class VirtualGroupIDProcessAttributeTracker(ProcessAttributeTracker
):
588 def track(self
, vgid
):
589 # type: (Union[int, str]) -> None
590 raise NotImplementedError
593 def untrack(self
, vgid
):
594 # type: (Union[int, str]) -> None
595 raise NotImplementedError
598 class Session(abc
.ABC
):
600 def _generate_name():
602 return "session_{random_id}".format(random_id
=_generate_random_string(8))
608 raise NotImplementedError
613 # type: () -> Optional[Type[SessionOutputLocation]]
614 raise NotImplementedError
621 buffer_sharing_policy
=BufferSharingPolicy
.PerUID
,
623 # type: (TracingDomain, Optional[str], BufferSharingPolicy) -> Channel
624 """Add a channel with default attributes to the session."""
625 raise NotImplementedError
630 raise NotImplementedError
635 raise NotImplementedError
640 raise NotImplementedError
645 raise NotImplementedError
650 raise NotImplementedError
652 @abc.abstractproperty
653 def kernel_pid_process_attribute_tracker(self
):
654 # type: () -> Type[ProcessIDProcessAttributeTracker]
655 raise NotImplementedError
657 @abc.abstractproperty
658 def kernel_vpid_process_attribute_tracker(self
):
659 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
660 raise NotImplementedError
662 @abc.abstractproperty
663 def user_vpid_process_attribute_tracker(
665 ) -> Type
[VirtualProcessIDProcessAttributeTracker
]:
666 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
667 raise NotImplementedError
669 @abc.abstractproperty
670 def kernel_gid_process_attribute_tracker(self
):
671 # type: () -> Type[GroupIDProcessAttributeTracker]
672 raise NotImplementedError
674 @abc.abstractproperty
675 def kernel_vgid_process_attribute_tracker(self
):
676 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
677 raise NotImplementedError
679 @abc.abstractproperty
680 def user_vgid_process_attribute_tracker(self
):
681 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
682 raise NotImplementedError
684 @abc.abstractproperty
685 def kernel_uid_process_attribute_tracker(self
):
686 # type: () -> Type[UserIDProcessAttributeTracker]
687 raise NotImplementedError
689 @abc.abstractproperty
690 def kernel_vuid_process_attribute_tracker(self
):
691 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
692 raise NotImplementedError
694 @abc.abstractproperty
695 def user_vuid_process_attribute_tracker(self
):
696 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
697 raise NotImplementedError
700 class ControlException(RuntimeError):
701 """Base type for exceptions thrown by a controller."""
703 def __init__(self
, msg
):
705 super().__init
__(msg
)
708 class Controller(abc
.ABC
):
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.
716 def create_session(self
, name
=None, output
=None):
717 # type: (Optional[str], Optional[SessionOutputLocation]) -> Session
719 Create a session with an output. Don't specify an output
720 to create a session without an output.
722 raise NotImplementedError
725 def start_session_by_name(self
, name
):
726 # type: (str) -> None
728 Start a session by name.
730 raise NotImplementedError
733 def start_session_by_glob_pattern(self
, pattern
):
734 # type: (str) -> None
736 Start sessions whose name matches `pattern`, see GLOB(7).
738 raise NotImplementedError
741 def start_sessions_all(self
):
743 Start all sessions visible to the current user.
746 raise NotImplementedError
749 def stop_session_by_name(self
, name
):
750 # type: (str) -> None
752 Stop a session by name.
754 raise NotImplementedError
757 def stop_session_by_glob_pattern(self
, pattern
):
758 # type: (str) -> None
760 Stop sessions whose name matches `pattern`, see GLOB(7).
762 raise NotImplementedError
765 def stop_sessions_all(self
):
767 Stop all sessions visible to the current user.
770 raise NotImplementedError
773 def destroy_session_by_name(self
, name
):
774 # type: (str) -> None
776 Destroy a session by name.
778 raise NotImplementedError
781 def destroy_session_by_glob_pattern(self
, pattern
):
782 # type: (str) -> None
784 Destroy sessions whose name matches `pattern`, see GLOB(7).
786 raise NotImplementedError
789 def destroy_sessions_all(self
):
792 Destroy all sessions visible to the current user.
794 raise NotImplementedError
797 def list_sessions(self
):
798 # type: () -> List[Session]
800 List all sessions visible to the current user.
802 raise NotImplementedError
805 def rotate_session_by_name(self
, name
, wait
=True):
806 # type: (str, bool) -> None
810 raise NotImplementedError
813 def schedule_size_based_rotation(self
, name
, size_bytes
):
814 # type: (str, int) -> None
816 Schedule automatic size-based rotations.
818 raise NotImplementedError
821 def schedule_time_based_rotation(self
, name
, period_seconds
):
822 # type: (str, int) -> None
824 Schedule automatic time-based rotations.
826 raise NotImplementedError