Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve tracing configuration error reporting #85

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ def test_action_frontend_yaml(self) -> None:
def test_action_context_per_domain(self) -> None:
tmpdir = tempfile.mkdtemp(prefix='TestTraceAction__test_action_context_per_domain')

# Invalid context domain
action = Trace(
session_name='my-session-name',
base_path=tmpdir,
events_kernel=[],
events_ust=[
'ros2:*',
'*',
],
context_fields={
'some_unknown_domain_type': [],
'userspace': ['vpid', 'vtid'],
},
subbuffer_size_ust=524288,
subbuffer_size_kernel=1048576,
)
self._assert_launch_errors([action])

action = Trace(
session_name='my-session-name',
base_path=tmpdir,
Expand Down
3 changes: 2 additions & 1 deletion tracetools_launch/tracetools_launch/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ def __init__(
:param context_fields: the names of context fields to enable
if it's a list or a set, the context fields are enabled for both kernel and userspace;
if it's a dictionary: { domain type string -> context fields list }
with the domain type string being either 'kernel' or 'userspace'
with the domain type string being either `names.DOMAIN_TYPE_KERNEL` or
`names.DOMAIN_TYPE_USERSPACE`
:param subbuffer_size_ust: the size of the subbuffers (defaults to 8 times the usual page
size)
:param subbuffer_size_kernel: the size of the subbuffers (defaults to 32 times the usual
Expand Down
72 changes: 54 additions & 18 deletions tracetools_trace/tracetools_trace/tools/lttng_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,19 @@ def is_session_daemon_not_alive() -> bool:
return not lttngpy.is_lttng_session_daemon_alive()


def spawn_session_daemon() -> None:
"""
Try to spawn a session daemon.
Raises RuntimeError if lttng-sessiond is not found.
"""
try:
subprocess.run(['lttng-sessiond', '--daemonize'])
except FileNotFoundError:
raise RuntimeError(
'cannot find lttng-sessiond: on Ubuntu, install lttng-tools and liblttng-ust-dev')


def setup(
*,
session_name: str,
Expand Down Expand Up @@ -165,7 +178,8 @@ def setup(
:param context_fields: the names of context fields to enable
if it's a list or a set, the context fields are enabled for both kernel and userspace;
if it's a dictionary: { domain type string -> context fields list }
with the domain type string being either 'kernel' or 'userspace'
with the domain type string being either `names.DOMAIN_TYPE_KERNEL` or
`names.DOMAIN_TYPE_USERSPACE`
:param channel_name_ust: the UST channel name
:param channel_name_kernel: the kernel channel name
:param subbuffer_size_ust: the size of the subbuffers for userspace events (defaults to 8 times
Expand All @@ -185,9 +199,7 @@ def setup(

# If there is no session daemon running, try to spawn one
if is_session_daemon_not_alive():
subprocess.run(
['lttng-sessiond', '--daemonize'],
)
spawn_session_daemon()
# Error out if it looks like there is a session daemon that we can't actually reach
if is_session_daemon_unreachable():
raise RuntimeError(
Expand Down Expand Up @@ -321,7 +333,8 @@ def start(
"""
result = lttngpy.lttng_start_tracing(session_name=session_name)
if result < 0:
raise RuntimeError(f'failed to start tracing: {lttngpy.lttng_strerror(result)}')
error = lttngpy.lttng_strerror(result)
raise RuntimeError(f"failed to start tracing session '{session_name}': {error}")


def stop(
Expand All @@ -341,7 +354,8 @@ def stop(
"""
result = lttngpy.lttng_stop_tracing(session_name=session_name)
if result < 0 and not ignore_error:
raise RuntimeError(f'failed to stop tracing: {lttngpy.lttng_strerror(result)}')
error = lttngpy.lttng_strerror(result)
raise RuntimeError(f"failed to stop tracing session '{session_name}': {error}")


def destroy(
Expand All @@ -361,7 +375,8 @@ def destroy(
"""
result = lttngpy.lttng_destroy_session(session_name=session_name)
if result < 0 and not ignore_error:
raise RuntimeError(f'failed to destroy tracing session: {lttngpy.lttng_strerror(result)}')
error = lttngpy.lttng_strerror(result)
raise RuntimeError(f"failed to destroy tracing session '{session_name}': {error}")


def _create_session(
Expand Down Expand Up @@ -391,7 +406,8 @@ def _create_session(
url=full_path,
)
if result < 0:
raise RuntimeError(f'session creation failed: {lttngpy.lttng_strerror(result)}')
error = lttngpy.lttng_strerror(result)
raise RuntimeError(f"failed to create tracing session '{session_name}': {error}")


def _enable_channel(**kwargs) -> None:
Expand All @@ -405,7 +421,13 @@ def _enable_channel(**kwargs) -> None:
"""
result = lttngpy.enable_channel(**kwargs)
if result < 0:
raise RuntimeError(f'channel enabling failed: {lttngpy.lttng_strerror(result)}')
session_name = kwargs['session_name']
channel_name = kwargs['channel_name']
error = lttngpy.lttng_strerror(result)
raise RuntimeError(
f"failed to enable channel '{channel_name}' "
f"in tracing session '{session_name}': {error}"
)


def _enable_events(**kwargs) -> None:
Expand All @@ -419,7 +441,13 @@ def _enable_events(**kwargs) -> None:
"""
result = lttngpy.enable_events(**kwargs)
if result < 0:
raise RuntimeError(f'event enabling failed: {lttngpy.lttng_strerror(result)}')
session_name = kwargs['session_name']
channel_name = kwargs['channel_name']
error = lttngpy.lttng_strerror(result)
raise RuntimeError(
f"failed to enable event for channel '{channel_name}' "
f"in tracing session '{session_name}': {error}"
)


def _normalize_contexts_dict(
Expand All @@ -431,21 +459,23 @@ def _normalize_contexts_dict(
:param context_fields: the names of context fields to enable
if it's a set, the context fields are enabled for both kernel and userspace;
if it's a dictionary: { domain type string -> context fields list }
with the domain type string being either 'kernel' or 'userspace'
:return: a dictionary of domain type name to list of context field name
with the domain type string being either `names.DOMAIN_TYPE_KERNEL` or
`names.DOMAIN_TYPE_USERSPACE`
:return: a dictionary of domain type name to list of context field names
"""
DOMAIN_TYPES = {DOMAIN_TYPE_USERSPACE, DOMAIN_TYPE_KERNEL}
if isinstance(context_fields, dict):
unknown_domain_types = context_fields.keys() - DOMAIN_TYPES
if unknown_domain_types:
raise RuntimeError(f'unknown context domain type(s): {unknown_domain_types}')
return {domain: set(field_names) for domain, field_names in context_fields.items()}
assert isinstance(context_fields, set)
return {
'userspace': context_fields,
'kernel': context_fields,
}
return {domain_type: context_fields for domain_type in DOMAIN_TYPES}


def _add_contexts(**kwargs) -> None:
"""
Add context lists to given handles, and check for errors.
Add context lists to given channel, and check for errors.
This must not be called if `lttngpy.is_available()` is `False`.
Raises RuntimeError on failure.
Expand All @@ -454,5 +484,11 @@ def _add_contexts(**kwargs) -> None:
"""
result = lttngpy.add_contexts(**kwargs)
if result < 0:
session_name = kwargs['session_name']
channel_name = kwargs['channel_name']
domain_type = kwargs['domain_type']
error = lttngpy.lttng_strerror(result)
raise RuntimeError(
f'failed to add context field: {lttngpy.lttng_strerror(result)}')
f"failed to add context fields for channel '{channel_name}' "
f"and domain '{domain_type}' in tracing session '{session_name}': {error}"
)
Loading