You can do that, but only by going through all entries in your journal manually, using the sd-journal
C API. It's not complicated, and copying together an example, some of it from bits and pieces from the sd_journal_next
manpage and replacing _get_data
with _enumerate_data
:
I put the source code here. **This is a bit quick&dirty, the sd_*
documentation is really not that good, so here's to hoping things are correct:
/* SPDX-License-Identifier: GPLv3 */
/* Copyright 2023 Marcus Müller
* Somewhat based on man sd_journal_get_data (MIT-0), but most of the original work by
* Marcus Müller
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-journal.h>
const char* KEY = "_SYSTEMD_UNIT=";
const char* ALTKEY = "_TRANSPORT=";
int main(int argc, char* argv[])
{
int r;
size_t KEYLEN = strlen(KEY);
size_t ALTKEYLEN = strlen(ALTKEY);
sd_journal* j;
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
if (r < 0) {
errno = -r;
fprintf(stderr, "Failed to open journal: %m\n");
return 1;
}
/* Print header */
puts("unit name;length\n");
SD_JOURNAL_FOREACH(j)
{
const char* data_ptr;
size_t field_length;
size_t total_length = 0;
char* unitname = NULL;
size_t unitname_len = 0;
int unit_found = 0;
while (0 < sd_journal_enumerate_data(j, (const void**)&data_ptr, &field_length)) {
/* We just break the counting if we encounter a broken entry. */
total_length += field_length;
if (unit_found == 0) {
if (field_length > KEYLEN && strncmp(data_ptr, KEY, KEYLEN) == 0) {
unit_found = 1;
unitname_len = field_length - KEYLEN;
unitname = realloc(unitname, unitname_len);
strncpy(unitname, data_ptr + KEYLEN, unitname_len);
} else if (field_length > ALTKEYLEN && (unitname_len == 0) &&
strncmp(data_ptr, ALTKEY, ALTKEYLEN) == 0) {
unitname_len = field_length - ALTKEYLEN;
unitname = realloc(unitname, unitname_len);
strncpy(unitname, data_ptr + ALTKEYLEN, unitname_len);
}
}
}
if (unitname_len == 0) {
printf("UNKNOWN;%zu\n", total_length);
} else {
printf("%*s;%zu\n", (int)unitname_len, unitname, total_length);
free(unitname);
}
}
sd_journal_close(j);
return 0;
}
save as journalsizes.c
, compile with
c99 -o journalsizes $(pkg-config --cflags --libs libsystemd) journalsizes.c
and run by ./journalsizes
to get a semicolon-separated list of unit names ; log entry lengths in bytes.
You can use that, for example, by putting into a text file called accumulate_logsizes.sql the following:
.mode csv
.separator ;
.import "|./journalsizes" journal
SELECT
"unit name",
SUM("length")/(1024*1024.0) AS megabyte
FROM
journal
GROUP BY
"unit name"
ORDER BY
megabyte
DESC LIMIT 10;
and running that through sqlite3
:
sqlite3 < accumulate_logsizes.sql
sd_journal_open'". I compiled it with
gcc -o journalsizes journalsizes.c -lsystemd` and it compiles successfully. – Daniel Aug 18 '23 at 17:12sqlite3 < accumulate_logsizes.sql 2>/dev/null
to hide warnings like this: ".mode column
into the sql to get better display. Otherwise this is perfect, I appreciate this. – Daniel Aug 18 '23 at 17:22