diff --git a/selfprivacy_api/graphql/queries/logs.py b/selfprivacy_api/graphql/queries/logs.py index 6aa864f..6841f30 100644 --- a/selfprivacy_api/graphql/queries/logs.py +++ b/selfprivacy_api/graphql/queries/logs.py @@ -1,25 +1,8 @@ """System logs""" from datetime import datetime -import os import typing import strawberry -from systemd import journal - - -def get_events_from_journal( - j: journal.Reader, limit: int, next: typing.Callable[[journal.Reader], typing.Dict] -): - events = [] - i = 0 - while i < limit: - entry = next(j) - if entry == None or entry == dict(): - break - if entry["MESSAGE"] != "": - events.append(LogEntry(entry)) - i += 1 - - return events +from selfprivacy_api.utils.systemd_journal import get_paginated_logs @strawberry.type @@ -95,31 +78,11 @@ class Logs: ) -> PaginatedEntries: if limit > 50: raise Exception("You can't fetch more than 50 entries via single request.") - j = journal.Reader() - - if up_cursor == None and down_cursor == None: - j.seek_tail() - - events = get_events_from_journal(j, limit, lambda j: j.get_previous()) - events.reverse() - - return PaginatedEntries.from_entries(events) - elif up_cursor == None and down_cursor != None: - j.seek_cursor(down_cursor) - j.get_previous() # pagination is exclusive - - events = get_events_from_journal(j, limit, lambda j: j.get_previous()) - events.reverse() - - return PaginatedEntries.from_entries(events) - elif up_cursor != None and down_cursor == None: - j.seek_cursor(up_cursor) - j.get_next() # pagination is exclusive - - events = get_events_from_journal(j, limit, lambda j: j.get_next()) - - return PaginatedEntries.from_entries(events) - else: - raise NotImplemented( - "Pagination by both up_cursor and down_cursor is not implemented" + return PaginatedEntries.from_entries( + list( + map( + lambda x: LogEntry(x), + get_paginated_logs(limit, up_cursor, down_cursor), + ) ) + ) diff --git a/selfprivacy_api/graphql/schema.py b/selfprivacy_api/graphql/schema.py index a515d0c..534bacf 100644 --- a/selfprivacy_api/graphql/schema.py +++ b/selfprivacy_api/graphql/schema.py @@ -177,8 +177,7 @@ class Subscription: @strawberry.subscription async def log_entries( - self, - info: strawberry.types.Info, + self, info: strawberry.types.Info ) -> AsyncGenerator[LogEntry, None]: reject_if_unauthenticated(info) return log_stream() diff --git a/selfprivacy_api/utils/systemd_journal.py b/selfprivacy_api/utils/systemd_journal.py new file mode 100644 index 0000000..6c03c93 --- /dev/null +++ b/selfprivacy_api/utils/systemd_journal.py @@ -0,0 +1,55 @@ +import typing +from systemd import journal + + +def get_events_from_journal( + j: journal.Reader, limit: int, next: typing.Callable[[journal.Reader], typing.Dict] +): + events = [] + i = 0 + while i < limit: + entry = next(j) + if entry is None or entry == dict(): + break + if entry["MESSAGE"] != "": + events.append(entry) + i += 1 + + return events + + +def get_paginated_logs( + limit: int = 20, + up_cursor: str + | None = None, # All entries returned will be lesser than this cursor. Sets upper bound on results. + down_cursor: str + | None = None, # All entries returned will be greater than this cursor. Sets lower bound on results. +): + j = journal.Reader() + + if up_cursor is None and down_cursor is None: + j.seek_tail() + + events = get_events_from_journal(j, limit, lambda j: j.get_previous()) + events.reverse() + + return events + elif up_cursor is None and down_cursor is not None: + j.seek_cursor(down_cursor) + j.get_previous() # pagination is exclusive + + events = get_events_from_journal(j, limit, lambda j: j.get_previous()) + events.reverse() + + return events + elif up_cursor is not None and down_cursor is None: + j.seek_cursor(up_cursor) + j.get_next() # pagination is exclusive + + events = get_events_from_journal(j, limit, lambda j: j.get_next()) + + return events + else: + raise NotImplementedError( + "Pagination by both up_cursor and down_cursor is not implemented" + )