diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ac1bab..6ca3f1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ use patch releases for compatibility fixes instead. ## Unreleased +### Added + +- Added `since` argument to `Beaker.job.follow`. + ## [v1.26.15](https://github.com/allenai/beaker-py/releases/tag/v1.26.15) - 2024-05-30 ### Fixed diff --git a/beaker/services/job.py b/beaker/services/job.py index c81b3f1..dc418f3 100644 --- a/beaker/services/job.py +++ b/beaker/services/job.py @@ -395,6 +395,7 @@ def follow( timeout: Optional[float] = None, strict: bool = False, include_timestamps: bool = True, + since: Optional[Union[str, datetime, timedelta]] = None, ) -> Generator[bytes, None, Job]: """ Follow a job live, creating a generator that produces log lines (as bytes) from the job @@ -419,6 +420,10 @@ def follow( :class:`~beaker.exceptions.JobFailedError` will be raised for non-zero exit codes. :param include_timestamps: If ``True`` (the default) timestamps from the Beaker logs will be included in the output. + :param since: Only show logs since a particular time. Could be a :class:`~datetime.datetime` object + (naive datetimes will be treated as UTC), a timestamp string in the form of RFC 3339 + (e.g. "2013-01-02T13:23:37Z"), or a relative time + (e.g. a :class:`~datetime.timedelta` or a string like "42m"). :raises JobNotFound: If any job can't be found. :raises JobTimeoutError: If the ``timeout`` expires. @@ -443,13 +448,13 @@ def follow( ... """ - from ..util import log_and_wait, split_timestamp + from ..util import format_since, log_and_wait, split_timestamp if timeout is not None and timeout <= 0: raise ValueError("'timeout' must be a positive number") start = time.monotonic() - last_timestamp: Optional[str] = None + last_timestamp: Optional[str] = None if since is None else format_since(since) lines_for_timestamp: Dict[str, Set[bytes]] = defaultdict(set) def get_line_to_yield(line: bytes) -> Optional[bytes]: