Skip to content

Add {short_file_name} as log format option#541

Open
tonynajjar wants to merge 1 commit intoros2:rollingfrom
botsandus:add-short-file-name
Open

Add {short_file_name} as log format option#541
tonynajjar wants to merge 1 commit intoros2:rollingfrom
botsandus:add-short-file-name

Conversation

@tonynajjar
Copy link

@tonynajjar tonynajjar commented Feb 11, 2026

Description

Add a new {short_file_name} format token to the rcutils logging system that outputs only the basename of the source file (e.g., my_node.cpp) instead of the full path (e.g., /opt/ros_ws/src/my_package/src/my_node.cpp).

The existing {file_name} token continues to output the full path as before. The new token uses strrchr to find the last path separator (/ on POSIX, \ on Windows) and returns everything after it.

Changed files

  • src/logging.c — Added expand_short_file_name() handler and registered the {short_file_name} token in the tokens[] array
  • include/rcutils/logging.h — Added short_file_name to the documented list of available format tokens
  • test/test_logging_console_output_handler.cpp — Added unit tests verifying basename extraction from full paths and passthrough for bare filenames
  • test/test_logging_output_format.py — Added integration test launching with {short_file_name}:{line_number} format and validating output
  • test/test_logging_output_format_short_file_name.txt — Expected output fixture for the integration test

Is this user-facing behavior change?

Yes. Users can now use {short_file_name} in the RCUTILS_CONSOLE_OUTPUT_FORMAT environment variable to display only the source file basename in log output, reducing log line length and improving readability.

Did you use Generative AI?

Yes — GitHub Copilot (Claude Opus 4.6)

Additional Information

  • The implementation handles both POSIX (/) and Windows (\) path separators via #ifdef _WIN32. Tested on Ubuntu Linux but I don't have a way to test on Windows.
  • If the file name contains no path separator, the full string is returned unchanged
  • No changes to rcutils_log_location_t struct — the basename is extracted at format-expansion time
  • Docs update PR: Add short_file_name placeholder to logging configuration options ros2_documentation#6226

Signed-off-by: Tony Najjar <tony.najjar@dexory.com>
@tonynajjar
Copy link
Author

I'd love to have it backported to Kilted when merged, it doesn't break ABI

@tonynajjar tonynajjar changed the title Add {short_file_name} Add {short_file_name} as log format option Feb 11, 2026
@tonynajjar
Copy link
Author

@ahcorde this is of similar nature as #526 so you might want to take it. FYI @kscottz if you want to share with the community

@kscottz
Copy link

kscottz commented Feb 11, 2026

@tonynajjar this slaps, thanks so much. Let me see what I can cook up when I make the social media rounds tomorrow. We haven't had a "what's been merged recently post" perhaps we're past due.

Copy link
Collaborator

@fujitatomoya fujitatomoya left a comment

Choose a reason for hiding this comment

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

@tonynajjar thanks for the PR.

i have a question about this approach. what is the major background and requirement for this PR?

assuming that full absolute paths in log output can be noisy and hurt readability.
however, I'm concerned that showing only the basename isn't quite enough. in a typical ROS 2 workspace, many packages can have identically named files (main.cpp, node.cpp, etc.), so {short_file_name} alone would make it hard to tell where a log line is actually coming from.
would it be possible to instead show the path relative to the package root? for example, my_package/src/my_node.cpp instead of just my_node.cpp. that would cut out the workspace-specific noise while still keeping enough context to identify the package. something like {relative_file_name} or {package_file_name} might be a better middle ground.
curious to hear your thoughts — what was the use case that motivated going with just the basename?

@tonynajjar
Copy link
Author

tonynajjar commented Feb 12, 2026

@fujitatomoya you're right, the motivation is to reduce the unnecessary noise and cluttering from the full path (in our case it's quite long)

in a typical ROS 2 workspace, many packages can have identically named files (main.cpp, node.cpp, etc.), so {short_file_name} alone would make it hard to tell where a log line is actually coming from.

I looked into this and although I first though you have a very good point, it turns out that {short_file_name} as implemented will actually show the file where the RCLCPP_INFO macro is called, and not the original file where the node is created, which is actually convenient. I would say that typically the files with the actual node implementation (where most macro calls are) have distinct names.

Take this example from Nav2:

with export RCUTILS_CONSOLE_OUTPUT_FORMAT="[{severity} {time}] [{short_file_name}:{line_number}] [{name}]: {message}"

I get

ros2 run nav2_controller controller_server

[INFO 1770887000.671869363] [controller_server.cpp:45] [controller_server]: Creating controller server

although as you can see here, the controller_server node is started in main.cpp.

Additionally when I look at our full stack of 100+ nodes, I never see main.cpp or node.cpp which is extra assurance. I'm happy to get counter-examples though

@fujitatomoya
Copy link
Collaborator

thanks for the explanation! i was just curious about the background for this additional token. but i am not sure how much this is useful against full file path including performance overhead. l would like to see more feedback on this 👂

@tonynajjar
Copy link
Author

tonynajjar commented Feb 12, 2026

but i am not sure how much this is useful against full file path

For us here is a before and after:

[INFO 1770889009.971313974] [/opt/auto_ws/src/auto-sandbox/src/vendor/navigation2/nav2_controller/src/controller_server.cpp:45] [controller_server]: Creating controller server
[INFO 1770887000.671869363] [controller_server.cpp:45] [controller_server]: Creating controller server

With one line it might not seem like a big deal but with thousands it compounds pretty badly and makes the logs unreadable

@fujitatomoya
Copy link
Collaborator

that is good example 👍

Copy link
Collaborator

@fujitatomoya fujitatomoya left a comment

Choose a reason for hiding this comment

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

overall lgtm, i got a few comments.

@tonynajjar i can see @kscottz 's approval including doc support, so let's proceed !!! thanks for waiting 🙇

{.token = "message", .handler = expand_message},
{.token = "function_name", .handler = expand_function_name},
{.token = "file_name", .handler = expand_file_name},
{.token = "short_file_name", .handler = expand_short_file_name},
Copy link
Collaborator

Choose a reason for hiding this comment

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

i would register "short_file_name" before "file_name", because if it does prefix matching with the shorter token's length, "short_file_name" could match "file_name" first. but i do not think this is a real issue here, because it uses strcmp to complete match check.

(void)end_offset;

if (logging_input->location) {
const char * file_name = logging_input->location->file_name;
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we check if this is not NULL to avoid undefined behavior?

}
#ifdef _WIN32
const char * last_backslash = strrchr(file_name, '\\');
if (last_backslash != NULL && last_backslash > last_sep) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

last_sep could be null?

Suggested change
if (last_backslash != NULL && last_backslash > last_sep) {
if (last_backslash != NULL && (last_sep == NULL || last_backslash > last_sep)) {

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.

3 participants