Skip to content

Support for logging via rcutils#102

Merged
dhood merged 65 commits intomasterfrom
rclpy_logging
Sep 8, 2017
Merged

Support for logging via rcutils#102
dhood merged 65 commits intomasterfrom
rclpy_logging

Conversation

@dhood
Copy link
Copy Markdown
Member

@dhood dhood commented Aug 19, 2017

connects to #103

Could I get some feedback on the direction this is going in? I add logging as an additional module of the rclpy package but it might belong in its own package or in the rclpy module itself.

@dhood dhood added the in progress Actively being worked on (Kanban column) label Aug 19, 2017
@dhood dhood self-assigned this Aug 19, 2017
@wjwwood
Copy link
Copy Markdown
Member

wjwwood commented Aug 19, 2017

Looks reasonable to me so far. It could either be its own module or part of the existing one. I don't think it needs to be in a separate package. Is there any downside to initializing it automatically?

Copy link
Copy Markdown
Member

@dirk-thomas dirk-thomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate library within the same package looks good to me. We can always change it later if we see a reason to do so.

target_include_directories(${library_name}
PUBLIC
${PythonExtra_INCLUDE_DIRS}
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of duplicating the logic to update the target with various information this should be moved into a function for reuse.

static struct PyModuleDef _rclpy_logging_module = {
PyModuleDef_HEAD_INIT,
"_rclpy_logging",
"_rclpy_logging_doc",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a dummy this should be NULL or a actual docstring.

def setUpClass(cls):
rclpy.logging.initialize()

def test_set_get_severity_threshold(self):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick about the name: Use *_get_set_* (since that is the order used in the test) or just test_severity_threshold.

dhood added 24 commits September 1, 2017 10:33
Just set and get severity level at the moment
This should be consistent with the C implementation of features in rcutils
In the C implementation in rcutils, all features are static.
@dirk-thomas mentioned someone might want to import the module, use a custom logging configuration, and then initialise. If we always initialise then the custom initialisation won't have an effect.
Also, the object as the context key wasn't unique so go back to using pickle
In anticipation of the global threshold being replaced by ones specific to each logger.
It was originally templated to reduce the coupling between the python enum and the rcutils C enum, but the names were still coupled anyway.
Add an option to return the result of the log condition
@dhood
Copy link
Copy Markdown
Member Author

dhood commented Sep 7, 2017

To fix _find_caller on windows, I had to introduce pathlib.Path().resolve() wrappers to each of the filenames returned by inspect.getabsfile(). This is because inspect.getabsfile() appears to return paths as lowercase on windows (only). Using pathlib.Path().resolve() corrects the case somehow (not sure how it would deal with ambiguity?).

Another issue on Windows was that, surprisingly to me, the __file__ attribute of the module had a mix of forward and backwards slashes.. So I applied the same approach to the internal filenames.

Most of this was done in 6c6917f; if there's a cleaner way that avoids lower casing everything I'm interested.

Example usage on windows is:

[INFO] []: message (test_log_arguments() at C:\J\workspace\ci_windows\ws\src\ros2\rclpy\rclpy\test\test_logging.py:128)

and on linux:

[INFO] []: message (test_log_arguments() at /home/dhood/ros2_ws/src/ros2/rclpy/rclpy/test/test_logging.py:128)

@dhood
Copy link
Copy Markdown
Member Author

dhood commented Sep 7, 2017

there are still a few outstanding comments that I will respond to tomorrow

Copy link
Copy Markdown
Member

@dirk-thomas dirk-thomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding inspect.getabsfile(): since this function is not publically documented I was wondering if another approach to get the same information has the same case problem on Windows. Have you tried os.path.abspath(inspect.getframeinfo(frame).filename) instead?

return frame


class CallerId:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the class could use __slots__ if it is never intended to be extended with additional attributes.

That would also make the implementation of __hash__ and __eq__ easier by just iterating the slots and avoiding the repetition of the member names.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made use of __slots__ as you suggested in d34a86c but then figured what we really want is a named tuple so switched to that in b4a8787

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even nicer! 🥇

if not frame:
frame = _find_caller(inspect.currentframe())
self.function_name = frame.f_code.co_name
self.file_name = _normalize_path(inspect.getabsfile(frame))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For file_name I would only expect the name of the file but not its full path. Maybe rename to file_path?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, fair call: renamed in 5507e4e

# This has to be done from within a function to avoid cyclic module imports.
import rclpy.logging
# Extend the list to preserve any filenames that may have been added by third parties.
# Note: the call to `abspath` will also resolve mixed slashes that can result on Windows.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using realpath will also resolve symlinks and therefore ensure that they compare equal even if one is a symlink of the other.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! I changed it in c4ae7a7 but only for the _find_caller function. the file path that will displayed in the logging call is still using abspath because I thought that would be more what users are expecting (but maybe not)

@dhood
Copy link
Copy Markdown
Member Author

dhood commented Sep 7, 2017

Indeed using os.path.abspath to get the absolute path instead of inspect.getabsfile prevents the case change, thanks @dirk-thomas. I switched to that in b028243 and 06367b0
I noted in the code comments that the abspath on the internal filenames is needed because otherwise __file__ can include a mix of slash directions on Windows e.g. (output as debug print from this job):

Internal callers: ['C:/J/workspace/ci_windows/ws/src/ros2/rclpy/rclpy\\rclpy\\impl\\rcutils_logger.py', 'C:/J/workspace/ci_windows/ws/src/ros2/rclpy/rclpy\\rclpy\\logging.py']

Update on the aforementioned todos:

  • Currently all loggers are using the global severity threshold from rcutils: this will stay until we have a way to set thresholds with more granularity in rcutils.
  • All of the convenience functions take the same set of filter options but none of them have been documented which inhibits autocompletion: I hard-coded documentation for the main log method and referenced it from the other callers in dea180d. We can avoid the hard-coding of filter options at a later date.
  • 'function' and/or 'expression' filter support: post-PR enhancement.
  • Allow log calls to take a format string + args (currently only pre-formatted strings are supported): post-PR enhancement for ROS 1 compatibility.
  • Use rcutils instead of python time: post-PR enhancement.

With that, I'll put this back in review (I think I've addressed the comments to date, LMK if I missed something)

Copy link
Copy Markdown
Member

@dirk-thomas dirk-thomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢 with green CI

@dhood
Copy link
Copy Markdown
Member Author

dhood commented Sep 8, 2017

🚢 🚢 🎉

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@dhood dhood merged commit 48b632f into master Sep 8, 2017
@dhood dhood deleted the rclpy_logging branch September 8, 2017 00:12
@dhood dhood removed the in review Waiting for review (Kanban column) label Sep 8, 2017
@dhood dhood mentioned this pull request Nov 20, 2017
YuanYuYuan pushed a commit to YuanYuYuan/rclpy that referenced this pull request Nov 12, 2025
…tests-to-test-logger

Fixed test that failed without ROS_PACKAGE_PATH being set, and add test_log
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants