ros2 / ros2/launch

Use a relative target for the `latest` log symlink so it survives different absolute mount paths (host/Docker)

Open Beginner friendly
#978 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
155
Forks
182
Avg merge
2d 14h
Merged PRs (30d)
6

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in launch/launch/logging/init.py at _renew_latest_log_dir(), where the latest symlink is created. Check the existing logging tests, then verify that the link target is relative and still resolves to the dated log directory when accessed through latest/.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.