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 tracing back-end."
85 JUL
= "Java Util Logging tracing back-end."
86 Python
= "Python logging module tracing back-end."
89 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
93 class BufferSharingPolicy(enum
.Enum
):
94 """Buffer sharing policy."""
96 PerUID
= "Per-UID buffering"
97 PerPID
= "Per-PID buffering"
100 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
103 class EventRule(abc
.ABC
):
104 """Event rule base class, see LTTNG-EVENT-RULE(7)."""
110 def __eq__(self
, other
):
111 # type (LogLevelRule) -> bool
112 if type(self
) != type(other
):
115 return self
.level
== other
.level
119 class LogLevel(enum
.Enum
):
124 class UserLogLevel(LogLevel
):
143 class JULLogLevel(LogLevel
):
156 class Log4jLogLevel(LogLevel
):
168 class PythonLogLevel(LogLevel
):
177 class LogLevelRuleAsSevereAs(LogLevelRule
):
178 def __init__(self
, level
):
184 # type: () -> LogLevel
188 class LogLevelRuleExactly(LogLevelRule
):
189 def __init__(self
, level
):
195 # type: () -> LogLevel
199 class TracepointEventRule(EventRule
):
202 name_pattern
=None, # type: Optional[str]
203 filter_expression
=None, # type: Optional[str]
205 self
._name
_pattern
= name_pattern
# type: Optional[str]
206 self
._filter
_expression
= filter_expression
# type: Optional[str]
208 def _equals(self
, other
):
209 # type (TracepointEventRule) -> bool
210 # Overridden by derived classes that have supplementary attributes.
213 def __eq__(self
, other
):
214 # type (TracepointEventRule) -> bool
215 if type(self
) != type(other
):
218 if self
.name_pattern
!= other
.name_pattern
:
221 if self
.filter_expression
!= other
.filter_expression
:
224 return self
._equals
(other
)
227 def name_pattern(self
):
228 # type: () -> Optional[str]
229 return self
._name
_pattern
232 def filter_expression(self
):
233 # type: () -> Optional[str]
234 return self
._filter
_expression
237 class UserTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
254 def _equals(self
, other
):
255 # type (UserTracepointEventRule) -> bool
257 self
.log_level_rule
== other
.log_level_rule
258 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
262 def log_level_rule(self
):
263 # type: () -> Optional[LogLevelRule]
264 return self
._log
_level
_rule
267 def name_pattern_exclusions(self
):
268 # type: () -> Optional[List[str]]
269 return self
._name
_pattern
_exclusions
272 class Log4jTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
289 def _equals(self
, other
):
290 # type (Log4jTracepointEventRule) -> bool
292 self
.log_level_rule
== other
.log_level_rule
293 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
297 def log_level_rule(self
):
298 # type: () -> Optional[LogLevelRule]
299 return self
._log
_level
_rule
302 def name_pattern_exclusions(self
):
303 # type: () -> Optional[List[str]]
304 return self
._name
_pattern
_exclusions
307 class JULTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
324 def _equals(self
, other
):
325 # type (JULTracepointEventRule) -> bool
327 self
.log_level_rule
== other
.log_level_rule
328 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
332 def log_level_rule(self
):
333 # type: () -> Optional[LogLevelRule]
334 return self
._log
_level
_rule
337 def name_pattern_exclusions(self
):
338 # type: () -> Optional[List[str]]
339 return self
._name
_pattern
_exclusions
342 class PythonTracepointEventRule(TracepointEventRule
):
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]]
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]]
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")
359 def _equals(self
, other
):
360 # type (PythonTracepointEventRule) -> bool
362 self
.log_level_rule
== other
.log_level_rule
363 and self
.name_pattern_exclusions
== other
.name_pattern_exclusions
367 def log_level_rule(self
):
368 # type: () -> Optional[LogLevelRule]
369 return self
._log
_level
_rule
372 def name_pattern_exclusions(self
):
373 # type: () -> Optional[List[str]]
374 return self
._name
_pattern
_exclusions
377 class KernelTracepointEventRule(TracepointEventRule
):
380 name_pattern
=None, # type: Optional[str]
381 filter_expression
=None, # type: Optional[str]
383 TracepointEventRule
.__init
__(**locals())
386 class Channel(abc
.ABC
):
388 A channel is an object which is responsible for a set of ring buffers. It is
389 associated to a domain and
393 def _generate_name():
395 return "channel_{random_id}".format(random_id
=_generate_random_string(8))
398 def add_context(self
, context_type
):
399 # type: (ContextType) -> None
400 raise NotImplementedError
405 # type: () -> TracingDomain
406 raise NotImplementedError
412 raise NotImplementedError
415 def add_recording_rule(self
, rule
) -> None:
416 # type: (Type[EventRule]) -> None
417 raise NotImplementedError
420 class SessionOutputLocation(abc
.ABC
):
424 class LocalSessionOutputLocation(SessionOutputLocation
):
425 def __init__(self
, trace_path
):
426 # type: (pathlib.Path)
427 self
._path
= trace_path
431 # type: () -> pathlib.Path
435 class ProcessAttributeTracker(abc
.ABC
):
437 Process attribute tracker used to filter before the evaluation of event
440 Note that this interface is currently limited as it doesn't allow changing
441 the tracking policy. For instance, it is not possible to set the tracking
442 policy back to "all" once it has transitioned to "include set".
446 class TrackingPolicy(enum
.Enum
):
448 Track all possible process attribute value of a given type (i.e. no filtering).
449 This is the default state of a process attribute tracker.
451 EXCLUDE_ALL
= "Exclude all possible process attribute values of a given type."
452 INCLUDE_SET
= "Track a set of specific process attribute values."
455 return "<%s.%s>" % (self
.__class
__.__name
__, self
.name
)
457 def __init__(self
, policy
):
458 # type: (TrackingPolicy)
459 self
._policy
= policy
462 def tracking_policy(self
):
463 # type: () -> TrackingPolicy
467 class ProcessIDProcessAttributeTracker(ProcessAttributeTracker
):
469 def track(self
, pid
):
470 # type: (int) -> None
471 raise NotImplementedError
474 def untrack(self
, pid
):
475 # type: (int) -> None
476 raise NotImplementedError
479 class VirtualProcessIDProcessAttributeTracker(ProcessAttributeTracker
):
481 def track(self
, vpid
):
482 # type: (int) -> None
483 raise NotImplementedError
486 def untrack(self
, vpid
):
487 # type: (int) -> None
488 raise NotImplementedError
491 class UserIDProcessAttributeTracker(ProcessAttributeTracker
):
493 def track(self
, uid
):
494 # type: (Union[int, str]) -> None
495 raise NotImplementedError
498 def untrack(self
, uid
):
499 # type: (Union[int, str]) -> None
500 raise NotImplementedError
503 class VirtualUserIDProcessAttributeTracker(ProcessAttributeTracker
):
505 def track(self
, vuid
):
506 # type: (Union[int, str]) -> None
507 raise NotImplementedError
510 def untrack(self
, vuid
):
511 # type: (Union[int, str]) -> None
512 raise NotImplementedError
515 class GroupIDProcessAttributeTracker(ProcessAttributeTracker
):
517 def track(self
, gid
):
518 # type: (Union[int, str]) -> None
519 raise NotImplementedError
522 def untrack(self
, gid
):
523 # type: (Union[int, str]) -> None
524 raise NotImplementedError
527 class VirtualGroupIDProcessAttributeTracker(ProcessAttributeTracker
):
529 def track(self
, vgid
):
530 # type: (Union[int, str]) -> None
531 raise NotImplementedError
534 def untrack(self
, vgid
):
535 # type: (Union[int, str]) -> None
536 raise NotImplementedError
539 class Session(abc
.ABC
):
541 def _generate_name():
543 return "session_{random_id}".format(random_id
=_generate_random_string(8))
549 raise NotImplementedError
554 # type: () -> Optional[Type[SessionOutputLocation]]
555 raise NotImplementedError
562 buffer_sharing_policy
=BufferSharingPolicy
.PerUID
,
564 # type: (TracingDomain, Optional[str], BufferSharingPolicy) -> Channel
565 """Add a channel with default attributes to the session."""
566 raise NotImplementedError
571 raise NotImplementedError
576 raise NotImplementedError
581 raise NotImplementedError
586 raise NotImplementedError
591 raise NotImplementedError
593 @abc.abstractproperty
594 def kernel_pid_process_attribute_tracker(self
):
595 # type: () -> Type[ProcessIDProcessAttributeTracker]
596 raise NotImplementedError
598 @abc.abstractproperty
599 def kernel_vpid_process_attribute_tracker(self
):
600 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
601 raise NotImplementedError
603 @abc.abstractproperty
604 def user_vpid_process_attribute_tracker(
606 ) -> Type
[VirtualProcessIDProcessAttributeTracker
]:
607 # type: () -> Type[VirtualProcessIDProcessAttributeTracker]
608 raise NotImplementedError
610 @abc.abstractproperty
611 def kernel_gid_process_attribute_tracker(self
):
612 # type: () -> Type[GroupIDProcessAttributeTracker]
613 raise NotImplementedError
615 @abc.abstractproperty
616 def kernel_vgid_process_attribute_tracker(self
):
617 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
618 raise NotImplementedError
620 @abc.abstractproperty
621 def user_vgid_process_attribute_tracker(self
):
622 # type: () -> Type[VirtualGroupIDProcessAttributeTracker]
623 raise NotImplementedError
625 @abc.abstractproperty
626 def kernel_uid_process_attribute_tracker(self
):
627 # type: () -> Type[UserIDProcessAttributeTracker]
628 raise NotImplementedError
630 @abc.abstractproperty
631 def kernel_vuid_process_attribute_tracker(self
):
632 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
633 raise NotImplementedError
635 @abc.abstractproperty
636 def user_vuid_process_attribute_tracker(self
):
637 # type: () -> Type[VirtualUserIDProcessAttributeTracker]
638 raise NotImplementedError
641 class ControlException(RuntimeError):
642 """Base type for exceptions thrown by a controller."""
644 def __init__(self
, msg
):
646 super().__init
__(msg
)
649 class Controller(abc
.ABC
):
651 Interface of a top-level control interface. A control interface can be, for
652 example, the LTTng client or a wrapper around liblttng-ctl. It is used to
653 create and manage top-level objects of a session daemon instance.
657 def create_session(self
, name
=None, output
=None):
658 # type: (Optional[str], Optional[SessionOutputLocation]) -> Session
660 Create a session with an output. Don't specify an output
661 to create a session without an output.
663 raise NotImplementedError
666 def start_session_by_name(self
, name
):
667 # type: (str) -> None
669 Start a session by name.
671 raise NotImplementedError
674 def start_session_by_glob_pattern(self
, pattern
):
675 # type: (str) -> None
677 Start sessions whose name matches `pattern`, see GLOB(7).
679 raise NotImplementedError
682 def start_sessions_all(self
):
684 Start all sessions visible to the current user.
687 raise NotImplementedError
690 def stop_session_by_name(self
, name
):
691 # type: (str) -> None
693 Stop a session by name.
695 raise NotImplementedError
698 def stop_session_by_glob_pattern(self
, pattern
):
699 # type: (str) -> None
701 Stop sessions whose name matches `pattern`, see GLOB(7).
703 raise NotImplementedError
706 def stop_sessions_all(self
):
708 Stop all sessions visible to the current user.
711 raise NotImplementedError
714 def destroy_session_by_name(self
, name
):
715 # type: (str) -> None
717 Destroy a session by name.
719 raise NotImplementedError
722 def destroy_session_by_glob_pattern(self
, pattern
):
723 # type: (str) -> None
725 Destroy sessions whose name matches `pattern`, see GLOB(7).
727 raise NotImplementedError
730 def destroy_sessions_all(self
):
733 Destroy all sessions visible to the current user.
735 raise NotImplementedError
738 def list_sessions(self
):
739 # type: () -> List[Session]
741 List all sessions visible to the current user.
743 raise NotImplementedError
746 def rotate_session_by_name(self
, name
, wait
=True):
747 # type: (str, bool) -> None
751 raise NotImplementedError
754 def schedule_size_based_rotation(self
, name
, size_bytes
):
755 # type: (str, int) -> None
757 Schedule automatic size-based rotations.
759 raise NotImplementedError
762 def schedule_time_based_rotation(self
, name
, period_seconds
):
763 # type: (str, int) -> None
765 Schedule automatic time-based rotations.
767 raise NotImplementedError