]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal-gatewayd: make num_entries in Range header optional again
authorJan Čermák <sairon@sairon.cz>
Wed, 18 Jun 2025 15:32:49 +0000 (17:32 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 20 Jun 2025 17:08:03 +0000 (02:08 +0900)
Since 435c372ce5059082212d37ac7039844f14f34a80 added in v256,
num_entries part of the Range header is mandatory and error is returned
when it's not filled in. This makes using the "follow" argument clumsy,
because for an indefinite following of the logs, arbitrary high number
must be specified. This change makes it possible to omit it again and
documents this behavior in the man page.

Moreover, as the cursor part of the header was never mandatory, enclose
it in square brackets in the documentation as well and elaborate how
indexing works.

Following are some concrete examples of the Range header which are now
accepted:

 entries= (or entries=:)
  - everything starting from the first event

 entries=cursor
  - everything starting from `cursor`

 entries=:-9:10
  - last 10 events and close the connection

If the follow flag is set:

 entries=:-4:10
  - last 5 events, wait for 5 new and close connection

 entries=:-9:
  - last 10 events and keep streaming

Note that only the very last one is changing current behavior, but
reintroduces pre-v256 compatibility.

Fixes #37172

man/systemd-journal-gatewayd.service.xml
src/journal-remote/journal-gatewayd.c
test/units/TEST-04-JOURNAL.journal-gatewayd.sh

index bd7a43e181e5a0092b030ff299858cc811731d38..cf224738c5cb2bc369016bd2be3ec0ba026fb824 100644 (file)
     <title>Range header</title>
 
     <para>
-      <option>Range: entries=<replaceable>cursor</replaceable>[[:<replaceable>num_skip</replaceable>]:<replaceable>num_entries</replaceable>]</option>
+      <option>Range: entries=[<replaceable>cursor</replaceable>][[:<replaceable>num_skip</replaceable>]:[<replaceable>num_entries</replaceable>]]</option>
     </para>
     <para>
       <option>Range: realtime=[<replaceable>since</replaceable>]:[<replaceable>until</replaceable>][[:<replaceable>num_skip</replaceable>]:<replaceable>num_entries</replaceable>]</option>
     </para>
 
     <para>where
-      <replaceable>cursor</replaceable> is a cursor string,
+      <replaceable>cursor</replaceable> is a cursor string, defaults to the first entry,
       <replaceable>since</replaceable> and <replaceable>until</replaceable> are timestamps (seconds since 1970-01-01 00:00:00 UTC),
       <replaceable>num_skip</replaceable> is an integer,
       <replaceable>num_entries</replaceable> is an unsigned integer.
     </para>
 
     <para>Range defaults to all available events.</para>
+
+    <para>If <replaceable>num_skip</replaceable> is negative and no <replaceable>cursor</replaceable> is
+    given, the last entry will be the reference point.</para>
   </refsect1>
 
   <refsect1>
       <varlistentry>
         <term><uri>follow</uri></term>
 
-        <listitem><para>wait for new events
-        (like <command>journalctl --follow</command>, except that
-        the number of events returned is not limited).</para>
+        <listitem><para>wait for new events (like <command>journalctl --follow</command>, the number of
+        events returned is not limited, unless <replaceable>num_entries</replaceable> is specified in the
+        <replaceable>Range</replaceable> header).</para>
 
         <xi:include href="version-info.xml" xpointer="v197"/>
         </listitem>
index a1de0045e8e65f6cb1e74cb3711b4e43ef03c6c4..8f6c3f1fafc775a8e81a9bf2459ee1cdbec26db5 100644 (file)
@@ -333,14 +333,16 @@ static int request_parse_range_skip_and_n_entries(
         }
 
         p = (colon2 ?: colon) + 1;
-        r = safe_atou64(p, &m->n_entries);
-        if (r < 0)
-                return r;
+        if (!isempty(p)) {
+                r = safe_atou64(p, &m->n_entries);
+                if (r < 0)
+                        return r;
 
-        if (m->n_entries <= 0)
-                return -EINVAL;
+                if (m->n_entries <= 0)
+                        return -EINVAL;
 
-        m->n_entries_set = true;
+                m->n_entries_set = true;
+        }
 
         return 0;
 }
index 35ac91ba4029c226951f31683f0be2f98a62b125..ef85dc17c678d6cbc64d0089be24d8bb77148352 100755 (executable)
@@ -67,6 +67,21 @@ curl -LSfs \
      --header "Range: entries=$BOOT_CURSOR:5:10" \
      http://localhost:19531/entries >"$LOG_FILE"
 jq -se "length == 10" "$LOG_FILE"
+# Check that follow with no num_entries follows "indefinitely"
+(
+    set +e; \
+    timeout 5 curl -LSfs \
+         --header "Accept: application/json" \
+         --header "Range: entries=:-1:" \
+         http://localhost:19531/entries?follow >"$LOG_FILE" ; \
+    test $? -eq 124 # timeout should kill the curl process waiting for new entries
+)
+# Check that follow with num_entries returns the specified number of entries and exits
+timeout 5 curl -LSfs \
+     --header "Accept: application/json" \
+     --header "Range: entries=:-20:10" \
+     http://localhost:19531/entries?follow >"$LOG_FILE"
+jq -se "length == 10" "$LOG_FILE"
 # Check if the specified cursor refers to an existing entry and return just that entry
 curl -LSfs \
      --header "Accept: application/json" \