Skip to content

feat(service_adguard_home): add the query log - #181

Merged
retransmit merged 17 commits into
developmentfrom
feature/adguard-query-log
Oct 7, 2026
Merged

retransmit merged 17 commits into
developmentfrom
feature/adguard-query-log

Conversation

@retransmit

Copy link
Copy Markdown
Owner

Second stage of AdGuard Home (#166): the Query log.

What it adds

  • Query log tab under a new bottom bar (Home, Query log) - newest first, read a page at a time as the list is scrolled, searched by domain or client, narrowed with the web UI's ten filters. The log is not read until the tab is opened
  • A query in full - request, response, the rule that matched and the list it is on, the client. Block or Unblock for everyone or for that client only, and Disallow or Allow the client behind a confirmation, all following the web UI's own steps
  • Clear query log in the app bar menu, behind a confirmation
  • The refused sign-in screen now says how many tries in a row were refused, on Home and the dashboard widget too

Notes

  • One read sends at most five requests. A rare match in a long log then waits behind "Keep searching" instead of scanning the server in a loop
  • A disallow the server would silently ignore (a client let in by a range of the allowed clients) is refused with the reason. The web UI reports it as done
  • The sign-in rule holds on the new tab: one request for a wrong password, nothing while idle, one per Try again

Testing

260 tests in service_adguard_home and 200 in the app. Verified on an emulator against AdGuard Home v0.107.79, with every read and write compared with the server. The look was checked on a phone.

Not done yet: searches typed ahead of a slow server are all sent in turn; editing the instance from the Query log returns to Home with the old search text still in the box; at 320 dp and twice the text size a row's client is cut to an ellipsis.

…he named clients

An entry carries the question, the answer, the rule that matched, the
client and how long it took. Its result is named and coloured as the web
UI names and colours it, and a reason this app does not know is shown as
the server wrote it.

The fixtures are fifteen entries of a real v0.107.79 log, one of every
kind that server produced.
…and list name

How long an answer took is written as the web UI writes it. A query from
today reads as a time of day and an older one has its date in front. The
list a matched rule is on is named from the lists already read, or from
the server's own sources.
…ess list and the clients

The log is asked for a page at a time, from where the page before
stopped, narrowed by a search and one of the ten filters. The access
list is written back whole, since the server replaces all of it.
…ess list edit

Blocking for one client writes the rule the web UI writes for it, with
the client's name escaped. Shutting a client out or letting it back in
follows the web UI's steps, the allowlist case included, and leaves the
blocked hosts as they were.
… a search and a filter

The log is read when it is first watched, and older entries from where
the page before stopped. A short answer that is not the end is followed
up at once, as the web UI does, but one read sends at most five
requests: a rare match in a long log then waits to be asked on instead
of scanning the server in a loop.

An answer that arrives after the search or the filter changed is thrown
away, and the read it belonged to stops asking. After a refused sign-in
nothing here reaches the server.

The actions gain blocking for one client, shutting a client out or
letting it back in, and clearing the log. The last allowed client is
never taken off the allowed clients.
The log is listed newest first: the name and when on one line, what came
of the query, its type, the client and how long it took on the next. It
is searched as the typing pauses and narrowed with the web UI's ten
filters. Older entries are read as the end of the list comes into view.

A row opens the query in full: the request, the response with the rule
that matched and the list it is on, and the client. From there the name
can be blocked or unblocked, for everyone or for that client only, and
the client shut out or let back in, which asks first and says what it
will do. A refused sign-in takes the place of all of it.
… bar

The Query log tab is built when it is first opened and kept after that,
so opening the service does not read a log nobody is looking at. Back
goes to Home from the Query log before it leaves the service.

Clear query log sits in the app bar's menu while that tab is showing,
and asks first.
… enough to fit

"Blocked by parental control" was cut off beside the client on a phone.
A row says "Parental control", and the entry in full keeps the long
form.
The three actions were at the end of the entry, a scroll away once it
had a few rules or answers. Block or Unblock now sits under the
scrolling part, with the two things that can be done to the client in a
menu beside it.
…f the sheet

With the actions fixed under it, the scrolling part took the width of
its widest line and was centred, so a short entry sat in the middle.
…ead it again

Once the log was cleared, or a search found nothing, there was nothing
to pull: the first new query could only be seen by leaving the tab.
…ne, and clear its narrowing in one read

The end of the list asks for more a frame after it is drawn and the
search box a moment after the typing. A call that arrived after the
screen was left threw. It is now dropped.

Clearing the search and the filter sent two reads, the first for a
question that was already out of date. It is one.
…s none

"NaN" and "Infinity" parse as numbers and cannot be rounded, so one such
entry failed the whole page of the query log it came in.
…y so beside Try again

A try that was refused again looked exactly like no try at all, which
invites another tap, and the fifth wrong try in a row is the one that
gets the address blocked for fifteen minutes. The session now counts the
refusals that reached the server, and from the second on the refused
screen says how many there have been.
… log

Changing a client's access:
- The sheet closed "whatever is on top" once the server had answered. If
  it had been closed by then, on a slow connection, that was the screen
  itself. It now closes only itself, shows that the change is on its way
  and takes no other action meanwhile.
- A failure that arrived after the sheet was closed said nothing, leaving
  the client believed to be shut out. It is said at the foot of the
  screen.
- A client the allowed clients let in by a range or a client id has no
  entry of its own to take off. The lists went back unchanged and the
  client was reported disallowed. It is now refused, with the reason.

A query with no name, such as one for the root, offered Block, and the
rule written for it was "||^". It no longer does.

Try again on one tab now reads a query log that is showing on the other:
after it worked on Home, the log went on saying the sign-in was refused.
One tap is still one request.

The failed-read and search-in-progress screens scroll, so their button is
not under the keyboard on a small phone. Retry after a failure deep in a
search goes on from where the search had got to. The end of the list no
longer claims to be the end while the list is being read again. A failed
read of the log's settings is not repeated ten times by itself.
… refused in a row

Try again is on the card as well, and the fifth wrong try in a row gets
the address blocked wherever it is tapped.
@retransmit
retransmit merged commit c1d4926 into development Oct 7, 2026
1 check failed
@retransmit
retransmit deleted the feature/adguard-query-log branch October 7, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant