Repository: PrefectHQ/prefect

Issue:
Add --reverse option to the prefect flow-run logs CLI
Follow-up to https://github.com/PrefectHQ/prefect/pull/7982

### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar request and didn't find it.
- [X] I searched the Prefect documentation for this feature.

### Prefect Version

2.x

### Describe the current behavior

The CLI command: `prefect flow-run logs <flow_run_id>` shows all logs in chronological order.


### Describe the proposed behavior

It would be great to add a `--reverse` option to show logs in reverse chronological order (print most recent log first). 

```bash
prefect flow-run logs <flow_run_id> [--reverse]
```

### Example Use

_No response_

### Additional context

_No response_


Discussion:
Is there anything left, or any good first issue available to be solved, I want to put some contribution here

@bakhtiarcr7 Yeah this one still needs a contribution! You'll need to add a flag to the CLI command then pass the correct sorting option during the log read request.

Resolving patch:
diff --git a/src/prefect/cli/flow_run.py b/src/prefect/cli/flow_run.py
--- a/src/prefect/cli/flow_run.py
+++ b/src/prefect/cli/flow_run.py
@@ -12,6 +12,7 @@
 from rich.pretty import Pretty
 from rich.table import Table
 
+import prefect.server.schemas as schemas
 from prefect.cli._types import PrefectTyper
 from prefect.cli._utilities import exit_with_error, exit_with_success
 from prefect.cli.root import app
@@ -164,6 +165,12 @@ async def logs(
         ),
         min=1,
     ),
+    reverse: bool = typer.Option(
+        False,
+        "--reverse",
+        "-r",
+        help="Reverse the logs order to print the most recent logs first",
+    ),
 ):
     """
     View logs for a flow run.
@@ -197,7 +204,14 @@ async def logs(
 
             # Get the next page of logs
             page_logs = await client.read_logs(
-                log_filter=log_filter, limit=num_logs_to_return_from_page, offset=offset
+                log_filter=log_filter,
+                limit=num_logs_to_return_from_page,
+                offset=offset,
+                sort=(
+                    schemas.sorting.LogSort.TIMESTAMP_DESC
+                    if reverse
+                    else schemas.sorting.LogSort.TIMESTAMP_ASC
+                ),
             )
 
             # Print the logs
diff --git a/src/prefect/client/orchestration.py b/src/prefect/client/orchestration.py
--- a/src/prefect/client/orchestration.py
+++ b/src/prefect/client/orchestration.py
@@ -2001,7 +2001,11 @@ async def read_flow_run_notification_policies(
         return pydantic.parse_obj_as(List[FlowRunNotificationPolicy], response.json())
 
     async def read_logs(
-        self, log_filter: LogFilter = None, limit: int = None, offset: int = None
+        self,
+        log_filter: LogFilter = None,
+        limit: int = None,
+        offset: int = None,
+        sort: schemas.sorting.LogSort = schemas.sorting.LogSort.TIMESTAMP_ASC,
     ) -> None:
         """
         Read flow and task run logs.
@@ -2010,6 +2014,7 @@ async def read_logs(
             "logs": log_filter.dict(json_compatible=True) if log_filter else None,
             "limit": limit,
             "offset": offset,
+            "sort": sort,
         }
 
         response = await self._client.post(f"/logs/filter", json=body)


Test patch:
diff --git a/tests/cli/test_flow_run.py b/tests/cli/test_flow_run.py
--- a/tests/cli/test_flow_run.py
+++ b/tests/cli/test_flow_run.py
@@ -506,3 +506,30 @@ async def test_when_num_logs_is_smaller_than_one_then_exit_with_error(
                 "Invalid value for '--num-logs' / '-n': 0 is not in the range x>=1."
             ),
         )
+
+    async def test_when_num_logs_passed_with_reverse_param_and_num_logs(
+        self, flow_run_factory
+    ):
+        # Given
+        flow_run = await flow_run_factory(num_logs=self.LOGS_DEFAULT_PAGE_SIZE + 1)
+
+        # When/Then
+        await run_sync_in_worker_thread(
+            invoke_and_assert,
+            command=[
+                "flow-run",
+                "logs",
+                str(flow_run.id),
+                "--num-logs",
+                "10",
+                "--reverse",
+            ],
+            expected_code=0,
+            expected_output_contains=[
+                f"Flow run '{flow_run.name}' - Log {i} from flow_run {flow_run.id}."
+                for i in range(
+                    self.LOGS_DEFAULT_PAGE_SIZE, self.LOGS_DEFAULT_PAGE_SIZE - 10, -1
+                )
+            ],
+            expected_line_count=10,
+        )