Skip to content

Commit f6c842e

Browse files
Replace python3-lttng with lttngpy
Signed-off-by: Christophe Bedard <[email protected]>
1 parent 9d3e053 commit f6c842e

File tree

8 files changed

+238
-368
lines changed

8 files changed

+238
-368
lines changed

Diff for: test_ros2trace/package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<test_depend>ament_xmllint</test_depend>
1919
<test_depend>launch</test_depend>
2020
<test_depend>launch_ros</test_depend>
21+
<test_depend>lttngpy</test_depend>
2122
<test_depend>python3-pytest</test_depend>
2223
<test_depend>ros2run</test_depend>
2324
<test_depend>ros2trace</test_depend>

Diff for: test_ros2trace/test/test_ros2trace/test_trace.py

+27-38
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from launch import LaunchDescription
2626
from launch import LaunchService
2727
from launch_ros.actions import Node
28+
from lttngpy import impl as lttngpy
2829
from tracetools_trace.tools import tracepoints
2930
from tracetools_trace.tools.lttng import is_lttng_installed
3031

@@ -63,30 +64,26 @@ def tearDown(self) -> None:
6364
# Even if running 'ros2 trace' fails, we do not want any lingering tracing session
6465
self.assertNoTracingSession()
6566

66-
def get_tracing_sessions(self) -> Tuple[bool, str]:
67-
output = self.run_lttng_list()
68-
# If there is no session daemon, then there are no tracing sessions
69-
no_session_daemon_available = 'No session daemon is available' in output
70-
if no_session_daemon_available:
71-
return False, output
72-
# Starting from LTTng 2.13, 'tracing session' was replaced with 'recording session'
73-
# (see lttng-tools e971184)
74-
has_tracing_sessions = not any(
75-
f'Currently no available {name} session' in output for name in ('tracing', 'recording')
76-
)
77-
return has_tracing_sessions, output
78-
7967
def assertTracingSession(self) -> None:
80-
has_tracing_sessions, output = self.get_tracing_sessions()
81-
self.assertTrue(has_tracing_sessions, 'no tracing sessions exist:\n' + output)
68+
self.assertTrue(
69+
lttngpy.is_lttng_session_daemon_alive(),
70+
'no tracing sessions exist because there is no daemon',
71+
)
72+
session_names = lttngpy.get_session_names()
73+
has_tracing_sessions = session_names is not None and 0 < len(session_names)
74+
self.assertTrue(has_tracing_sessions, 'no tracing sessions exist')
8275

8376
def assertNoTracingSession(self) -> None:
84-
has_tracing_sessions, output = self.get_tracing_sessions()
85-
if has_tracing_sessions:
77+
# If there is no session daemon, then there are no tracing sessions
78+
if not lttngpy.is_lttng_session_daemon_alive():
79+
return
80+
session_names = lttngpy.get_session_names()
81+
no_tracing_sessions = 0 == len(session_names)
82+
if not no_tracing_sessions:
8683
# Destroy tracing sessions if there are any, this way we can continue running tests and
8784
# avoid possible interference between them
88-
self.run_lttng_destroy_all()
89-
self.assertFalse(has_tracing_sessions, 'tracing session(s) exist:\n' + output)
85+
self.assertEqual(0, lttngpy.destroy_all_sessions())
86+
self.assertTrue(no_tracing_sessions, f'tracing session(s) exist: {session_names}')
9087

9188
def assertTraceExist(self, trace_dir: str) -> None:
9289
self.assertTrue(os.path.isdir(trace_dir), f'trace directory does not exist: {trace_dir}')
@@ -116,25 +113,6 @@ def create_test_tmpdir(self, test_name: str) -> str:
116113
def get_subdirectories(self, directory: str) -> List[str]:
117114
return [f.name for f in os.scandir(directory) if f.is_dir()]
118115

119-
def run_lttng_list(self) -> str:
120-
process = subprocess.run(
121-
['lttng', 'list'],
122-
stdout=subprocess.PIPE,
123-
stderr=subprocess.PIPE,
124-
encoding='utf-8',
125-
)
126-
return process.stdout + process.stderr
127-
128-
def run_lttng_destroy_all(self):
129-
process = subprocess.run(
130-
['lttng', 'destroy', '--all'],
131-
stdout=subprocess.PIPE,
132-
stderr=subprocess.PIPE,
133-
encoding='utf-8',
134-
)
135-
output = process.stdout + process.stderr
136-
self.assertEqual(0, process.returncode, f"'lttng destroy' command failed: {output}")
137-
138116
def run_command(
139117
self,
140118
args: List[str],
@@ -370,6 +348,17 @@ def test_base_path_not_exist(self) -> None:
370348

371349
shutil.rmtree(tmpdir)
372350

351+
def test_no_events(self) -> None:
352+
tmpdir = self.create_test_tmpdir('test_no_events')
353+
354+
# Enabling no events should result in an error
355+
ret = self.run_trace_command(
356+
['--path', tmpdir, '--ust', '--kernel'],
357+
)
358+
self.assertEqual(1, ret)
359+
360+
shutil.rmtree(tmpdir)
361+
373362
def test_unknown_context_field(self) -> None:
374363
tmpdir = self.create_test_tmpdir('test_unknown_context_field')
375364

Diff for: tracetools_trace/package.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
<url type="bugtracker">https://github.com/ros2/ros2_tracing/issues</url>
1313
<author email="[email protected]">Christophe Bedard</author>
1414

15-
<exec_depend>lttng-tools</exec_depend>
16-
<exec_depend>python3-lttng</exec_depend>
15+
<exec_depend>lttngpy</exec_depend>
1716

1817
<test_depend>ament_copyright</test_depend>
1918
<test_depend>ament_flake8</test_depend>

Diff for: tracetools_trace/test/tracetools_trace/test_lttng_tracing.py

+19-32
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
import os
16-
import subprocess
1716
import tempfile
1817
import unittest
1918
from unittest import mock
@@ -35,32 +34,7 @@ def test_is_lttng_installed(self):
3534
with mock.patch('platform.system', return_value='Windows'):
3635
self.assertFalse(is_lttng_installed())
3736

38-
# LTTng command not found
39-
class PopenFileNotFound:
40-
41-
def __init__(self, *args, **kwargs):
42-
raise FileNotFoundError('file not found')
43-
44-
with mock.patch.object(subprocess, 'Popen', PopenFileNotFound):
45-
self.assertFalse(is_lttng_installed())
46-
47-
# Other error when running LTTng command
48-
class PopenReturnCodeError:
49-
50-
def __init__(self, *args, **kwargs):
51-
pass
52-
53-
def communicate(self):
54-
return 'stdout'.encode(), 'stderr'.encode()
55-
56-
@property
57-
def returncode(self):
58-
return 1
59-
60-
with mock.patch.object(subprocess, 'Popen', PopenReturnCodeError):
61-
self.assertFalse(is_lttng_installed())
62-
63-
# lttng Python package or version not found
37+
# lttng-ctl or version not found
6438
with mock.patch('tracetools_trace.tools.lttng.get_lttng_version', return_value=None):
6539
self.assertFalse(is_lttng_installed())
6640

@@ -81,11 +55,18 @@ def test_lttng_not_installed(self):
8155
def test_no_kernel_tracer(self):
8256
from tracetools_trace.tools.lttng_impl import setup
8357
with (
58+
mock.patch(
59+
'tracetools_trace.tools.lttng_impl.is_session_daemon_not_alive',
60+
return_value=False,
61+
),
62+
mock.patch(
63+
'tracetools_trace.tools.lttng_impl.is_session_daemon_unreachable',
64+
return_value=False,
65+
),
8466
mock.patch(
8567
'tracetools_trace.tools.lttng_impl.is_kernel_tracer_available',
86-
return_value=(False, 'some error message'),
68+
return_value=False,
8769
),
88-
mock.patch('lttng.session_daemon_alive', return_value=1),
8970
):
9071
with self.assertRaises(RuntimeError):
9172
setup(
@@ -166,9 +147,15 @@ def test_is_session_daemon_unreachable(self):
166147

167148
def test_unreachable_session_daemon(self):
168149
from tracetools_trace.tools.lttng_impl import setup
169-
with mock.patch(
170-
'tracetools_trace.tools.lttng_impl.is_session_daemon_unreachable',
171-
return_value=True,
150+
with (
151+
mock.patch(
152+
'tracetools_trace.tools.lttng_impl.is_session_daemon_not_alive',
153+
return_value=False,
154+
),
155+
mock.patch(
156+
'tracetools_trace.tools.lttng_impl.is_session_daemon_unreachable',
157+
return_value=True,
158+
),
172159
):
173160
with self.assertRaises(RuntimeError):
174161
setup(session_name='test-session', base_path='/tmp')

Diff for: tracetools_trace/tracetools_trace/tools/lttng.py

+14-40
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,30 @@
1616
"""Interface for tracing with LTTng."""
1717

1818
import platform
19-
import subprocess
2019
import sys
2120
from typing import Optional
2221

2322
from packaging.version import Version
2423

2524
try:
26-
from . import lttng_impl
27-
_lttng = lttng_impl # type: ignore
25+
from . import lttng_impl as _lttng
2826
except ImportError:
2927
# Fall back on stub functions so that this still passes linter checks
30-
from . import lttng_stub
31-
_lttng = lttng_stub # type: ignore
28+
# This will happen if lttngpy isn't found, in which case importing lttng_impl will fail
29+
from . import lttng_stub as _lttng # type: ignore
3230

3331

3432
def get_lttng_version() -> Optional[Version]:
3533
"""
36-
Get version of lttng Python package.
34+
Get version of lttng-ctl.
3735
38-
:return: the version of the lttng Python package, or `None` if it is not available
36+
:return: the version of lttng-ctl, or `None` if it is not available
3937
"""
4038
if not hasattr(_lttng, 'get_version') or not callable(_lttng.get_version):
4139
return None
4240
return _lttng.get_version()
4341

4442

45-
# Check lttng module version
46-
current_version = get_lttng_version()
47-
LTTNG_MIN_VERSION = '2.10.7'
48-
if current_version is None or current_version < Version(LTTNG_MIN_VERSION):
49-
print(
50-
f'lttng module version >={LTTNG_MIN_VERSION} required, found {str(current_version)}',
51-
file=sys.stderr,
52-
)
53-
54-
5543
def lttng_init(**kwargs) -> Optional[str]:
5644
"""
5745
Set up and start LTTng session.
@@ -114,14 +102,13 @@ def is_lttng_installed(
114102
Check if LTTng is installed.
115103
116104
It first checks if the OS can support LTTng.
117-
If so, it then simply checks if LTTng is installed using the 'lttng' command, and checks if the
118-
lttng Python package is installed (python3-lttng).
105+
If so, it then checks if lttng-ctl is installed.
119106
120-
Optionally, a minimum version can also be specified for the lttng Python package.
107+
Optionally, a minimum version can also be specified for lttng-ctl.
121108
122-
:param minimum_version: the minimum required lttng Python package version
123-
:return: True if LTTng and the lttng Python package are installed, and optionally if the
124-
version of lttng Python package is sufficient, False otherwise
109+
:param minimum_version: the minimum required lttng-ctl version
110+
:return: True if lttng-ctl is installed, and optionally if the version of lttng-ctl is
111+
sufficient, False otherwise
125112
"""
126113
# Check system
127114
message_doc = (
@@ -132,32 +119,19 @@ def is_lttng_installed(
132119
if 'Linux' != system:
133120
print(f"System '{system}' does not support LTTng.\n{message_doc}", file=sys.stderr)
134121
return False
135-
# Check if LTTng (CLI) is installed
136-
try:
137-
process = subprocess.Popen(
138-
['lttng', '--version'],
139-
stdout=subprocess.PIPE,
140-
stderr=subprocess.PIPE,
141-
)
142-
_, stderr = process.communicate()
143-
if 0 != process.returncode:
144-
raise RuntimeError(stderr.decode())
145-
except (RuntimeError, FileNotFoundError) as e:
146-
print(f'LTTng not found: {e}\n{message_doc}', file=sys.stderr)
147-
return False
148-
# Check if lttng Python package is installed
122+
# Check if lttng-ctl is installed
149123
lttng_version = get_lttng_version()
150124
if not lttng_version:
151125
print(
152-
f'lttng Python package (python3-lttng) not installed\n{message_doc}',
126+
f'lttng-ctl (liblttng-ctl-dev) not installed\n{message_doc}',
153127
file=sys.stderr,
154128
)
155129
return False
156-
# Check if lttng Python package version is sufficient
130+
# Check if lttng-ctl version is sufficient
157131
if minimum_version and lttng_version < Version(minimum_version):
158132
print(
159133
(
160-
f'lttng Python package (python3-lttng) version >={minimum_version} required, '
134+
f'lttng-ctl (liblttng-ctl-dev) version >={minimum_version} required, '
161135
f'found {str(lttng_version)}'
162136
),
163137
file=sys.stderr,

0 commit comments

Comments
 (0)