Description
launch.logging maintains a latest symlink pointing at the most recent log directory. It is created in _renew_latest_log_dir() with an absolute target:
https://github.com/ros2/launch/blob/rolling/launch/launch/logging/__init__.py#L93-L108
def _renew_latest_log_dir(*, log_dir: str) -> bool:
base_dir = os.path.dirname(log_dir)
latest_dir = os.path.join(base_dir, 'latest')
if os.path.lexists(latest_dir):
if not os.path.islink(latest_dir):
return False
os.unlink(latest_dir)
os.symlink(log_dir, latest_dir, target_is_directory=True) # absolute target
return True
Because latest and the dated log directory are always siblings in base_dir, the link target could just as well be relative (the directory's basename). Proposed change:
os.symlink(
os.path.basename(log_dir), latest_dir, target_is_directory=True)
Motivation
The absolute target breaks whenever the log directory is viewed under a different absolute path than the one in effect when the link was written. The most common case is a shared/mounted log directory between a host and a Docker container:
- Container writes logs to
/root/.ros/log, so latest -> /root/.ros/log/<run>.
- The same volume is mounted on the host at e.g.
/home/user/ros-logs, where /root/.ros/log/<run> does not exist, so latest dangles.
The reverse (host writes, container reads) fails the same way. It also affects any setup where the logs are relocated, bind-mounted, or inspected from a different mount namespace.
A relative target resolves correctly regardless of the absolute mount point, since latest and its target stay in the same directory. There is no scenario in which latest and the dated directory are not siblings, so the relative form is always equivalent for in-place use and strictly more portable.
Design / Implementation Considerations
- One-line change in
_renew_latest_log_dir(): use os.path.basename(log_dir) as the symlink target instead of the full log_dir.
target_is_directory=True is retained (only relevant on Windows).
- Reading
os.path.realpath(latest_dir) / accessing files through latest/ is unchanged for local use — a relative symlink resolves identically when the CWD-independent parent directory is intact.
- Tools that call
os.readlink('.../latest') and expect an absolute path would now get a basename. This seems unlikely (the documented/contract value is "the latest log directory", reachable via the link itself), but it is the one behavioural difference worth noting.
- Backward compatibility: existing
latest links are recreated on the next run, so no migration is needed.
I'm happy to open a PR with the change plus a test asserting the link target is relative and still resolves to the run directory.
Additional Information
We currently work around this downstream by monkey-patching _renew_latest_log_dir to emit a relative target. It would be cleaner for launch to do this by default, as there appears to be no downside for the standard local-use case.
Description
launch.loggingmaintains alatestsymlink pointing at the most recent log directory. It is created in_renew_latest_log_dir()with an absolute target:https://github.com/ros2/launch/blob/rolling/launch/launch/logging/__init__.py#L93-L108
Because
latestand the dated log directory are always siblings inbase_dir, the link target could just as well be relative (the directory's basename). Proposed change:Motivation
The absolute target breaks whenever the log directory is viewed under a different absolute path than the one in effect when the link was written. The most common case is a shared/mounted log directory between a host and a Docker container:
/root/.ros/log, solatest -> /root/.ros/log/<run>./home/user/ros-logs, where/root/.ros/log/<run>does not exist, solatestdangles.The reverse (host writes, container reads) fails the same way. It also affects any setup where the logs are relocated, bind-mounted, or inspected from a different mount namespace.
A relative target resolves correctly regardless of the absolute mount point, since
latestand its target stay in the same directory. There is no scenario in whichlatestand the dated directory are not siblings, so the relative form is always equivalent for in-place use and strictly more portable.Design / Implementation Considerations
_renew_latest_log_dir(): useos.path.basename(log_dir)as the symlink target instead of the fulllog_dir.target_is_directory=Trueis retained (only relevant on Windows).os.path.realpath(latest_dir)/ accessing files throughlatest/is unchanged for local use — a relative symlink resolves identically when the CWD-independent parent directory is intact.os.readlink('.../latest')and expect an absolute path would now get a basename. This seems unlikely (the documented/contract value is "the latest log directory", reachable via the link itself), but it is the one behavioural difference worth noting.latestlinks are recreated on the next run, so no migration is needed.I'm happy to open a PR with the change plus a test asserting the link target is relative and still resolves to the run directory.
Additional Information
We currently work around this downstream by monkey-patching
_renew_latest_log_dirto emit a relative target. It would be cleaner forlaunchto do this by default, as there appears to be no downside for the standard local-use case.