diff --git a/CHANGELOG.md b/CHANGELOG.md index ca6250fc..3a245050 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and start a new "In Progress" section above it. ## In progress: 0.142.0 +- Support non-standard `audience` query parameter on `GET /jobs/{job_id}/logs` (e.g. `all` to include developer-only logs), passed to `BatchJobs.get_log_entries` ([openeo-geotrellis-extensions#872](https://github.com/Open-EO/openeo-geotrellis-extensions/issues/872)) - Add `resample_cube_temporal` process (`DriverDataCube.resample_cube_temporal`, dry-run support, validation of `dimension`/`valid_within`) - Require at least Python 3.11 (drop support for Python 3.8, 3.9 and 3.10 [#370](https://github.com/Open-EO/openeo-python-driver/issues/370)) - Require at least PySTAC 1.10 ([#396](https://github.com/Open-EO/openeo-python-driver/issues/396)) diff --git a/openeo_driver/_version.py b/openeo_driver/_version.py index 829f0459..288d207e 100644 --- a/openeo_driver/_version.py +++ b/openeo_driver/_version.py @@ -1 +1 @@ -__version__ = "0.142.0a5" +__version__ = "0.142.0a6" diff --git a/openeo_driver/backend.py b/openeo_driver/backend.py index 26a7e445..326db2c2 100644 --- a/openeo_driver/backend.py +++ b/openeo_driver/backend.py @@ -723,9 +723,13 @@ def get_log_entries( offset: Union[str, None] = None, limit: Union[str, None] = None, level: str = DEFAULT_LOG_LEVEL_RETRIEVAL, + audience: Optional[str] = None, ) -> Iterable[dict]: """ https://openeo.org/documentation/1.0/developers/api/reference.html#operation/debug-job + + :param audience: (non-standard) only return logs for this audience (e.g. "user", "developer" or "all"). + Semantics and default (`None`) are backend-specific. """ raise NotImplementedError diff --git a/openeo_driver/dummy/dummy_backend.py b/openeo_driver/dummy/dummy_backend.py index 442b8a09..59eac7cf 100644 --- a/openeo_driver/dummy/dummy_backend.py +++ b/openeo_driver/dummy/dummy_backend.py @@ -1053,6 +1053,7 @@ def get_log_entries( offset: Union[str, None] = None, limit: Union[str, None] = None, level: str = DEFAULT_LOG_LEVEL_RETRIEVAL, + audience: Optional[str] = None, ) -> Iterable[dict]: self._get_job_info(job_id=job_id, user_id=user_id) default_logs = [{"id": "1", "level": "info", "message": "hello world"}] @@ -1062,7 +1063,9 @@ def get_log_entries( actual_level = normalize_log_level(log.get("level")) if actual_level < requested_level: continue - yield log + if audience and audience != "all" and log.get("audience", audience) != audience: + continue + yield {k: v for k, v in log.items() if k != "audience"} elif isinstance(log, Exception): raise log else: diff --git a/openeo_driver/views.py b/openeo_driver/views.py index 16043443..51772a9a 100644 --- a/openeo_driver/views.py +++ b/openeo_driver/views.py @@ -1258,18 +1258,18 @@ def get_job_logs(job_id, user: User): offset = request.args.get("offset", default=None) limit = request.args.get("limit", default=None, type=int) level = request.args.get("level", default=DEFAULT_LOG_LEVEL_RETRIEVAL) + # Non-standard: e.g. "user", "developer" or "all" (backend-specific semantics and default) + audience = request.args.get("audience", default=None) request_id = FlaskRequestCorrelationIdLogging.get_request_id() # TODO: implement paging support: `limit`, next/prev/first/last `links`, ... - # TODO: remove this `function_has_argument` once all implementations are migrated + get_log_entries_kwargs = dict(job_id=job_id, user_id=user.user_id, offset=offset, level=level) + # TODO: remove these `function_has_argument` checks once all implementations are migrated if function_has_argument(backend_implementation.batch_jobs.get_log_entries, argument="limit"): - logs = backend_implementation.batch_jobs.get_log_entries( - job_id=job_id, user_id=user.user_id, offset=offset, level=level, limit=limit - ) - else: - logs = backend_implementation.batch_jobs.get_log_entries( - job_id=job_id, user_id=user.user_id, offset=offset, level=level - ) + get_log_entries_kwargs["limit"] = limit + if audience and function_has_argument(backend_implementation.batch_jobs.get_log_entries, argument="audience"): + get_log_entries_kwargs["audience"] = audience + logs = backend_implementation.batch_jobs.get_log_entries(**get_log_entries_kwargs) def generate(): yield "{" diff --git a/tests/test_views.py b/tests/test_views.py index 74f62200..2096af95 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -4334,6 +4334,30 @@ def test_get_batch_job_logs_level(self, api): "links": [], } + @pytest.mark.parametrize( + ["params", "expected_ids"], + [ + ({}, ["1", "2"]), + ({"audience": "user"}, ["1"]), + ({"audience": "developer"}, ["2"]), + ({"audience": "all"}, ["1", "2"]), + ], + ) + def test_get_batch_job_logs_audience(self, api, params, expected_ids): + log_db = { + "07024ee9-7847-4b8a-b260-6c879a2b3cdc": [ + {"id": "1", "level": "info", "message": "for users", "audience": "user"}, + {"id": "2", "level": "info", "message": "for devs", "audience": "developer"}, + ] + } + with self._fresh_job_registry(): + with mock.patch.dict(dummy_backend.DummyBatchJobs._custom_job_logs, log_db): + resp = api.get( + "/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/logs", headers=self.AUTH_HEADER, params=params + ) + logs = resp.assert_status_code(200).json["logs"] + assert [log["id"] for log in logs] == expected_ids + def test_get_batch_job_logs_failure(self, api): with self._fresh_job_registry(): with mock.patch.dict(