]>
git.proxmox.com Git - proxmox-mini-journalreader.git/blob - src/mini-journalreader.c
f6ae87450edc638c19fa6aab1fa41c3a74b23740
2 Copyright (C) 2019 Proxmox Server Solutions GmbH
4 Copyright: mini-journal is under GNU GPL, the GNU General Public License.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 2 dated June, 1991.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 Author: Dominik Csapak <d.csapak@proxmox.com>
28 #include <systemd/sd-journal.h>
34 static char buf
[BUFSIZE
+1];
35 static size_t offset
= 0;
37 uint64_t convert_argument(const char *argument
) {
40 uint64_t value
= strtoull(argument
, &end
, 10);
41 if (errno
!= 0 || *end
!= '\0') {
42 fprintf(stderr
, "%s is not a valid number\n", argument
);
49 uint64_t get_timestamp(sd_journal
*j
) {
51 int r
= sd_journal_get_realtime_usec(j
, ×tamp
);
53 fprintf(stderr
, "Failed %s\n", strerror(-r
));
54 return 0xFFFFFFFFFFFFFFFF;
59 void print_to_buf(const char * string
, uint32_t length
) {
63 size_t string_offset
= 0;
64 size_t remaining
= length
;
65 while (offset
+ remaining
> BUFSIZE
) {
66 strncpy(buf
+offset
, string
+string_offset
, BUFSIZE
-offset
);
67 string_offset
+= BUFSIZE
-offset
;
68 remaining
= length
- string_offset
;
69 write (1, buf
, BUFSIZE
);
72 strncpy(buf
+offset
, string
+string_offset
, remaining
);
76 bool printed_first_cursor
= false;
78 void print_cursor(sd_journal
*j
) {
81 r
= sd_journal_get_cursor(j
, &cursor
);
83 fprintf(stderr
, "Failed to get cursor: %s\n", strerror(-r
));
86 print_to_buf(cursor
, strlen(cursor
));
87 print_to_buf("\n", 1);
91 void print_first_cursor(sd_journal
*j
) {
92 if (!printed_first_cursor
) {
94 printed_first_cursor
= true;
98 static uint64_t last_timestamp
;
99 static char timestring
[16];
100 static char bootid
[32];
102 void print_reboot(sd_journal
*j
) {
105 int r
= sd_journal_get_data(j
, "_BOOT_ID", (const void **)&d
, &l
);
107 fprintf(stderr
, "Failed %s\n", strerror(-r
));
111 // remove '_BOOT_ID='
115 if (bootid
[0] != '\0') { // we have some bootid
116 if (strncmp(bootid
, d
, l
)) { // a new bootid found
117 strncpy(bootid
, d
, l
);
118 print_to_buf("-- Reboot --\n", 13);
121 strncpy(bootid
, d
, l
);
125 void print_timestamp(sd_journal
*j
) {
127 int r
= sd_journal_get_realtime_usec(j
, ×tamp
);
129 fprintf(stderr
, "Failed %s\n", strerror(-r
));
133 if (timestamp
>= (last_timestamp
+(1000*1000))) {
134 timestamp
= timestamp
/ (1000*1000); // usec to sec
136 localtime_r((time_t *)×tamp
, &time
);
137 strftime(timestring
, 16, "%b %d %T", &time
);
138 last_timestamp
= timestamp
;
141 print_to_buf(timestring
, 15);
144 void print_pid(sd_journal
*j
) {
147 int r
= sd_journal_get_data(j
, "_PID", (const void **)&d
, &l
);
149 // we sometimes have no pid
157 print_to_buf("[", 1);
159 print_to_buf("]", 1);
162 bool print_field(sd_journal
*j
, const char *field
) {
165 int r
= sd_journal_get_data(j
, field
, (const void **)&d
, &l
);
167 // some fields do not exists
171 int fieldlen
= strlen(field
)+1;
179 void print_line(sd_journal
*j
) {
182 print_to_buf(" ", 1);
183 print_field(j
, "_HOSTNAME");
184 print_to_buf(" ", 1);
185 if (!print_field(j
, "SYSLOG_IDENTIFIER") &&
186 !print_field(j
, "_COMM")) {
187 print_to_buf("unknown", strlen("unknown") - 1);
190 print_to_buf(": ", 2);
191 print_field(j
, "MESSAGE");
192 print_to_buf("\n", 1);
195 void usage(char *progname
) {
196 fprintf(stderr
, "usage: %s [OPTIONS]\n", progname
);
197 fprintf(stderr
, " -b begin\tbegin at this epoch\n");
198 fprintf(stderr
, " -e end\tend at this epoch\n");
199 fprintf(stderr
, " -d directory\tpath to journal directory\n");
200 fprintf(stderr
, " -n number\tprint the last number entries\n");
201 fprintf(stderr
, " -f from\tprint from this cursor\n");
202 fprintf(stderr
, " -t to\tprint to this cursor\n");
203 fprintf(stderr
, " -h \t\tthis help\n");
204 fprintf(stderr
, "\n");
205 fprintf(stderr
, "giving a range conflicts with -n\n");
206 fprintf(stderr
, "-b and -f conflict\n");
207 fprintf(stderr
, "-e and -t conflict\n");
210 int main(int argc
, char *argv
[]) {
212 const char *directory
= NULL
;
213 const char *startcursor
= NULL
;
214 const char *endcursor
= NULL
;
219 while ((c
= getopt (argc
, argv
, "b:e:d:n:f:t:h")) != -1) {
222 begin
= convert_argument(optarg
);
223 begin
= begin
*1000*1000;
226 end
= convert_argument(optarg
);
233 number
= convert_argument(optarg
);
236 startcursor
= optarg
;
252 if (number
&& (begin
|| startcursor
)) {
257 if (begin
&& startcursor
) {
262 if (end
&& endcursor
) {
272 // to prevent calling it everytime we generate a timestamp
277 if (directory
== NULL
) {
278 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
);
280 r
= sd_journal_open_directory(&j
, directory
, 0);
284 fprintf(stderr
, "Failed to open journal: %s\n", strerror(-r
));
288 // if we want to print the last x entries, seek to cursor or end,
289 // then x entries back, print the cursor and finally print the
290 // entries until end or cursor
293 r
= sd_journal_seek_realtime_usec(j
, end
);
294 } else if (endcursor
!= NULL
) {
295 r
= sd_journal_seek_cursor(j
, endcursor
);
298 r
= sd_journal_seek_tail(j
);
302 fprintf(stderr
, "Failed to seek to end/cursor: %s\n", strerror(-r
));
306 // seek back number entries and print cursor
307 r
= sd_journal_previous_skip(j
, number
+ 1);
309 fprintf(stderr
, "Failed to seek back: %s\n", strerror(-r
));
314 r
= sd_journal_seek_realtime_usec(j
, begin
);
315 } else if (startcursor
) {
316 r
= sd_journal_seek_cursor(j
, startcursor
);
318 r
= sd_journal_seek_head(j
);
322 fprintf(stderr
, "Failed to seek to begin/cursor: %s\n", strerror(-r
));
326 // if we have a start cursor, we want to skip the first entry
328 r
= sd_journal_next(j
);
330 fprintf(stderr
, "Failed to seek to begin/cursor: %s\n", strerror(-r
));
333 print_first_cursor(j
);
338 while ((r
= sd_journal_next(j
)) > 0 && (end
== 0 || get_timestamp(j
) < end
)) {
339 print_first_cursor(j
);
340 if (endcursor
!= NULL
&& sd_journal_test_cursor(j
, endcursor
)) {
346 // print optional reboot
349 // print final cursor
352 // print remaining buffer
353 write(1, buf
, offset
);