2012-01-03 21:08:28 +01:00
|
|
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2012 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
2012-04-12 00:20:58 +02:00
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
2012-01-03 21:08:28 +01:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2012-04-12 00:20:58 +02:00
|
|
|
Lesser General Public License for more details.
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-04-12 00:20:58 +02:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2012-01-03 21:08:28 +01:00
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
#include <errno.h>
|
2013-12-12 05:56:13 +01:00
|
|
|
#include <sys/socket.h>
|
2012-01-05 20:11:47 +01:00
|
|
|
#include <string.h>
|
2013-12-11 22:04:03 +01:00
|
|
|
#include <fcntl.h>
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
#include "logs-show.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "util.h"
|
2012-07-13 01:07:41 +02:00
|
|
|
#include "utf8.h"
|
2012-10-25 01:19:24 +02:00
|
|
|
#include "hashmap.h"
|
2013-04-16 05:25:57 +02:00
|
|
|
#include "journal-internal.h"
|
2015-04-10 20:43:52 +02:00
|
|
|
#include "formats-util.h"
|
2015-04-10 19:10:00 +02:00
|
|
|
#include "process-util.h"
|
2015-04-10 23:15:59 +02:00
|
|
|
#include "terminal-util.h"
|
2012-01-03 21:08:28 +01:00
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
/* up to three lines (each up to 100 characters),
|
|
|
|
or 300 characters, whichever is less */
|
|
|
|
#define PRINT_LINE_THRESHOLD 3
|
|
|
|
#define PRINT_CHAR_THRESHOLD 300
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
#define JSON_THRESHOLD 4096
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-11-15 23:03:31 +01:00
|
|
|
static int print_catalog(FILE *f, sd_journal *j) {
|
|
|
|
int r;
|
|
|
|
_cleanup_free_ char *t = NULL, *z = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
r = sd_journal_get_catalog(j, &t);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
z = strreplace(strstrip(t), "\n", "\n-- ");
|
|
|
|
if (!z)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
fputs("-- ", f);
|
|
|
|
fputs(z, f);
|
|
|
|
fputc('\n', f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-05 20:11:47 +01:00
|
|
|
static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
|
|
|
|
size_t fl, nl;
|
|
|
|
void *buf;
|
|
|
|
|
|
|
|
assert(data);
|
|
|
|
assert(field);
|
|
|
|
assert(target);
|
|
|
|
assert(target_size);
|
|
|
|
|
|
|
|
fl = strlen(field);
|
|
|
|
if (length < fl)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (memcmp(data, field, fl))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nl = length - fl;
|
2012-01-07 05:00:28 +01:00
|
|
|
buf = malloc(nl+1);
|
2012-07-25 23:55:59 +02:00
|
|
|
if (!buf)
|
|
|
|
return log_oom();
|
2012-01-05 20:11:47 +01:00
|
|
|
|
2012-07-26 16:05:26 +02:00
|
|
|
memcpy(buf, (const char*) data + fl, nl);
|
|
|
|
((char*)buf)[nl] = 0;
|
|
|
|
|
2012-01-07 04:09:59 +01:00
|
|
|
free(*target);
|
2012-01-05 20:11:47 +01:00
|
|
|
*target = buf;
|
|
|
|
*target_size = nl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static bool shall_print(const char *p, size_t l, OutputFlags flags) {
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
if (flags & OUTPUT_SHOW_ALL)
|
2012-01-05 20:11:47 +01:00
|
|
|
return true;
|
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
if (l >= PRINT_CHAR_THRESHOLD)
|
2012-01-05 20:11:47 +01:00
|
|
|
return false;
|
|
|
|
|
2013-04-24 04:40:26 +02:00
|
|
|
if (!utf8_is_printable(p, l))
|
2012-01-05 20:11:47 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:36:27 +02:00
|
|
|
static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
|
2013-04-24 04:40:26 +02:00
|
|
|
const char *color_on = "", *color_off = "";
|
|
|
|
const char *pos, *end;
|
2013-08-04 01:38:13 +02:00
|
|
|
bool ellipsized = false;
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
int line = 0;
|
2013-04-24 04:40:26 +02:00
|
|
|
|
|
|
|
if (flags & OUTPUT_COLOR) {
|
|
|
|
if (priority <= LOG_ERR) {
|
|
|
|
color_on = ANSI_HIGHLIGHT_RED_ON;
|
|
|
|
color_off = ANSI_HIGHLIGHT_OFF;
|
|
|
|
} else if (priority <= LOG_NOTICE) {
|
|
|
|
color_on = ANSI_HIGHLIGHT_ON;
|
|
|
|
color_off = ANSI_HIGHLIGHT_OFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-20 02:00:09 +01:00
|
|
|
/* A special case: make sure that we print a newline when
|
|
|
|
the message is empty. */
|
|
|
|
if (message_len == 0)
|
|
|
|
fputs("\n", f);
|
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
for (pos = message;
|
|
|
|
pos < message + message_len;
|
|
|
|
pos = end + 1, line++) {
|
|
|
|
bool continuation = line > 0;
|
|
|
|
bool tail_line;
|
2013-04-24 04:40:26 +02:00
|
|
|
int len;
|
|
|
|
for (end = pos; end < message + message_len && *end != '\n'; end++)
|
|
|
|
;
|
|
|
|
len = end - pos;
|
|
|
|
assert(len >= 0);
|
|
|
|
|
2013-08-21 07:34:57 +02:00
|
|
|
/* We need to figure out when we are showing not-last line, *and*
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
* will skip subsequent lines. In that case, we will put the dots
|
|
|
|
* at the end of the line, instead of putting dots in the middle
|
|
|
|
* or not at all.
|
|
|
|
*/
|
|
|
|
tail_line =
|
|
|
|
line + 1 == PRINT_LINE_THRESHOLD ||
|
2013-08-21 07:34:57 +02:00
|
|
|
end + 1 >= message + PRINT_CHAR_THRESHOLD;
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
|
|
|
|
if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
|
|
|
|
(prefix + len + 1 < n_columns && !tail_line)) {
|
2013-04-24 04:40:26 +02:00
|
|
|
fprintf(f, "%*s%s%.*s%s\n",
|
|
|
|
continuation * prefix, "",
|
|
|
|
color_on, len, pos, color_off);
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-24 04:40:26 +02:00
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
/* Beyond this point, ellipsization will happen. */
|
|
|
|
ellipsized = true;
|
2013-04-24 04:40:26 +02:00
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
if (prefix < n_columns && n_columns - prefix >= 3) {
|
|
|
|
if (n_columns - prefix > (unsigned) len + 3)
|
|
|
|
fprintf(f, "%*s%s%.*s...%s\n",
|
2013-08-08 14:32:43 +02:00
|
|
|
continuation * prefix, "",
|
|
|
|
color_on, len, pos, color_off);
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
else {
|
|
|
|
_cleanup_free_ char *e;
|
|
|
|
|
|
|
|
e = ellipsize_mem(pos, len, n_columns - prefix,
|
|
|
|
tail_line ? 100 : 90);
|
|
|
|
if (!e)
|
|
|
|
fprintf(f, "%*s%s%.*s%s\n",
|
|
|
|
continuation * prefix, "",
|
|
|
|
color_on, len, pos, color_off);
|
|
|
|
else
|
|
|
|
fprintf(f, "%*s%s%s%s\n",
|
|
|
|
continuation * prefix, "",
|
|
|
|
color_on, e, color_off);
|
|
|
|
}
|
|
|
|
} else
|
2013-04-24 04:40:26 +02:00
|
|
|
fputs("...\n", f);
|
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
if (tail_line)
|
|
|
|
break;
|
2013-04-24 04:40:26 +02:00
|
|
|
}
|
2013-08-04 01:38:13 +02:00
|
|
|
|
|
|
|
return ellipsized;
|
2013-04-24 04:40:26 +02:00
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int output_short(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
int r;
|
|
|
|
const void *data;
|
|
|
|
size_t length;
|
|
|
|
size_t n = 0;
|
2012-09-27 23:27:10 +02:00
|
|
|
_cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
|
2012-07-26 16:50:35 +02:00
|
|
|
size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0;
|
|
|
|
int p = LOG_INFO;
|
2013-08-04 01:38:13 +02:00
|
|
|
bool ellipsized = false;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
assert(f);
|
2012-01-03 21:08:28 +01:00
|
|
|
assert(j);
|
|
|
|
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
/* Set the threshold to one bigger than the actual print
|
2013-09-14 01:41:52 +02:00
|
|
|
* threshold, so that if the line is actually longer than what
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
* we're willing to print, ellipsization will occur. This way
|
|
|
|
* we won't output a misleading line without any indication of
|
|
|
|
* truncation.
|
|
|
|
*/
|
|
|
|
sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
|
2012-11-21 00:28:00 +01:00
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
|
2012-01-05 20:11:47 +01:00
|
|
|
|
2012-07-26 16:50:35 +02:00
|
|
|
r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-07-26 16:50:35 +02:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2012-01-05 20:11:47 +01:00
|
|
|
r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-05 20:11:47 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2012-01-05 21:43:49 +01:00
|
|
|
r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
|
2012-01-05 20:11:47 +01:00
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-05 20:11:47 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = parse_field(data, length, "_COMM=", &comm, &comm_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-05 20:11:47 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = parse_field(data, length, "_PID=", &pid, &pid_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-05 20:11:47 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2012-01-07 04:09:59 +01:00
|
|
|
r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-07 04:09:59 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2012-01-07 05:00:28 +01:00
|
|
|
r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-07 05:00:28 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-07 05:00:28 +01:00
|
|
|
else if (r > 0)
|
|
|
|
continue;
|
|
|
|
|
2012-01-05 20:11:47 +01:00
|
|
|
r = parse_field(data, length, "MESSAGE=", &message, &message_len);
|
|
|
|
if (r < 0)
|
2012-09-27 23:27:10 +02:00
|
|
|
return r;
|
2012-01-05 20:11:47 +01:00
|
|
|
}
|
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to get journal fields: %m");
|
2013-06-10 03:50:56 +02:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
if (!message)
|
|
|
|
return 0;
|
2012-01-05 20:11:47 +01:00
|
|
|
|
2012-12-23 11:23:59 +01:00
|
|
|
if (!(flags & OUTPUT_SHOW_ALL))
|
|
|
|
strip_tab_ansi(&message, &message_len);
|
|
|
|
|
2012-07-26 16:50:35 +02:00
|
|
|
if (priority_len == 1 && *priority >= '0' && *priority <= '7')
|
|
|
|
p = *priority - '0';
|
|
|
|
|
2012-09-06 00:25:32 +02:00
|
|
|
if (mode == OUTPUT_SHORT_MONOTONIC) {
|
2012-01-07 04:41:30 +01:00
|
|
|
uint64_t t;
|
2012-01-11 03:02:10 +01:00
|
|
|
sd_id128_t boot_id;
|
|
|
|
|
2012-01-07 05:00:28 +01:00
|
|
|
r = -ENOENT;
|
|
|
|
|
|
|
|
if (monotonic)
|
|
|
|
r = safe_atou64(monotonic, &t);
|
|
|
|
|
|
|
|
if (r < 0)
|
2012-01-11 03:02:10 +01:00
|
|
|
r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
2012-01-07 04:41:30 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, "[%5llu.%06llu]",
|
2014-05-22 04:44:03 +02:00
|
|
|
(unsigned long long) (t / USEC_PER_SEC),
|
|
|
|
(unsigned long long) (t % USEC_PER_SEC));
|
2012-01-11 03:02:10 +01:00
|
|
|
|
|
|
|
n += 1 + 5 + 1 + 6 + 1;
|
|
|
|
|
2012-01-07 04:41:30 +01:00
|
|
|
} else {
|
|
|
|
char buf[64];
|
2012-01-07 05:00:28 +01:00
|
|
|
uint64_t x;
|
2012-01-07 04:41:30 +01:00
|
|
|
time_t t;
|
|
|
|
struct tm tm;
|
2014-10-02 14:39:29 +02:00
|
|
|
struct tm *(*gettime_r)(const time_t *, struct tm *);
|
2012-01-11 03:16:24 +01:00
|
|
|
|
2012-01-07 05:00:28 +01:00
|
|
|
r = -ENOENT;
|
2014-10-02 14:39:29 +02:00
|
|
|
gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
|
2012-01-07 05:00:28 +01:00
|
|
|
|
|
|
|
if (realtime)
|
|
|
|
r = safe_atou64(realtime, &x);
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
r = sd_journal_get_realtime_usec(j, &x);
|
2012-01-07 04:41:30 +01:00
|
|
|
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
2012-01-07 04:41:30 +01:00
|
|
|
|
2012-01-07 05:00:28 +01:00
|
|
|
t = (time_t) (x / USEC_PER_SEC);
|
2013-08-04 15:04:20 +02:00
|
|
|
|
|
|
|
switch(mode) {
|
|
|
|
case OUTPUT_SHORT_ISO:
|
2014-10-02 14:39:29 +02:00
|
|
|
r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
|
2013-08-04 15:04:20 +02:00
|
|
|
break;
|
|
|
|
case OUTPUT_SHORT_PRECISE:
|
2014-10-02 14:39:29 +02:00
|
|
|
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
|
2013-08-04 15:04:20 +02:00
|
|
|
if (r > 0) {
|
|
|
|
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
2014-05-22 04:44:03 +02:00
|
|
|
".%06llu", (unsigned long long) (x % USEC_PER_SEC));
|
2013-08-04 15:04:20 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-10-02 14:39:29 +02:00
|
|
|
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
|
2013-08-04 15:04:20 +02:00
|
|
|
}
|
2013-07-18 10:21:45 +02:00
|
|
|
|
|
|
|
if (r <= 0) {
|
2012-01-07 04:41:30 +01:00
|
|
|
log_error("Failed to format time.");
|
2013-07-18 10:21:45 +02:00
|
|
|
return -EINVAL;
|
2012-01-07 04:41:30 +01:00
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputs(buf, f);
|
2012-01-07 04:41:30 +01:00
|
|
|
n += strlen(buf);
|
|
|
|
}
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
if (hostname && shall_print(hostname, hostname_len, flags)) {
|
|
|
|
fprintf(f, " %.*s", (int) hostname_len, hostname);
|
2012-01-05 20:11:47 +01:00
|
|
|
n += hostname_len + 1;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
if (identifier && shall_print(identifier, identifier_len, flags)) {
|
|
|
|
fprintf(f, " %.*s", (int) identifier_len, identifier);
|
2012-01-05 21:43:49 +01:00
|
|
|
n += identifier_len + 1;
|
2012-09-27 23:27:10 +02:00
|
|
|
} else if (comm && shall_print(comm, comm_len, flags)) {
|
|
|
|
fprintf(f, " %.*s", (int) comm_len, comm);
|
2012-01-05 20:11:47 +01:00
|
|
|
n += comm_len + 1;
|
2012-04-11 00:34:06 +02:00
|
|
|
} else
|
2014-11-04 00:28:33 +01:00
|
|
|
fputs(" unknown", f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
if (pid && shall_print(pid, pid_len, flags)) {
|
|
|
|
fprintf(f, "[%.*s]", (int) pid_len, pid);
|
2012-01-05 20:11:47 +01:00
|
|
|
n += pid_len + 2;
|
2012-09-27 23:27:10 +02:00
|
|
|
} else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
|
|
|
|
fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
|
2012-01-07 04:09:59 +01:00
|
|
|
n += fake_pid_len + 2;
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2013-04-24 04:40:26 +02:00
|
|
|
if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
|
2012-01-14 03:07:47 +01:00
|
|
|
char bytes[FORMAT_BYTES_MAX];
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
|
2013-04-24 04:40:26 +02:00
|
|
|
} else {
|
|
|
|
fputs(": ", f);
|
2013-08-04 01:38:13 +02:00
|
|
|
ellipsized |=
|
|
|
|
print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
|
2013-04-24 04:40:26 +02:00
|
|
|
}
|
2012-01-05 20:11:47 +01:00
|
|
|
|
2012-11-15 23:03:31 +01:00
|
|
|
if (flags & OUTPUT_CATALOG)
|
|
|
|
print_catalog(f, j);
|
|
|
|
|
2013-08-04 01:38:13 +02:00
|
|
|
return ellipsized;
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int output_verbose(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
const void *data;
|
|
|
|
size_t length;
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *cursor = NULL;
|
2012-01-03 21:08:28 +01:00
|
|
|
uint64_t realtime;
|
2013-08-04 15:04:20 +02:00
|
|
|
char ts[FORMAT_TIMESTAMP_MAX + 7];
|
2012-01-03 21:08:28 +01:00
|
|
|
int r;
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
assert(f);
|
2012-01-03 21:08:28 +01:00
|
|
|
assert(j);
|
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
2013-08-08 04:55:29 +02:00
|
|
|
r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
log_debug("Source realtime timestamp not found");
|
2015-05-19 00:25:45 +02:00
|
|
|
else if (r < 0)
|
|
|
|
return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
|
|
|
|
else {
|
2013-08-08 04:55:29 +02:00
|
|
|
_cleanup_free_ char *value = NULL;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
|
|
|
|
if (r < 0)
|
2014-11-28 13:19:16 +01:00
|
|
|
log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
|
2013-08-08 04:55:29 +02:00
|
|
|
else {
|
|
|
|
r = safe_atou64(value, &realtime);
|
|
|
|
if (r < 0)
|
2014-11-28 17:09:20 +01:00
|
|
|
log_debug_errno(r, "Failed to parse realtime timestamp: %m");
|
2013-08-08 04:55:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
r = sd_journal_get_realtime_usec(j, &realtime);
|
2015-05-19 00:25:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_journal_get_cursor(j, &cursor);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get cursor: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, "%s [%s]\n",
|
2014-10-08 22:37:45 +02:00
|
|
|
flags & OUTPUT_UTC ?
|
|
|
|
format_timestamp_us_utc(ts, sizeof(ts), realtime) :
|
|
|
|
format_timestamp_us(ts, sizeof(ts), realtime),
|
2012-09-27 23:27:10 +02:00
|
|
|
cursor);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
|
2013-04-24 04:40:26 +02:00
|
|
|
const char *c;
|
|
|
|
int fieldlen;
|
2013-06-27 01:48:24 +02:00
|
|
|
const char *on = "", *off = "";
|
|
|
|
|
2013-04-24 04:40:26 +02:00
|
|
|
c = memchr(data, '=', length);
|
|
|
|
if (!c) {
|
|
|
|
log_error("Invalid field.");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
fieldlen = c - (const char*) data;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2013-06-27 01:48:24 +02:00
|
|
|
if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
|
|
|
|
on = ANSI_HIGHLIGHT_ON;
|
|
|
|
off = ANSI_HIGHLIGHT_OFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & OUTPUT_SHOW_ALL ||
|
logs-show: limit to 3 lines and use dots if not showing full message
So far, we would show up to 128 bytes from a message, simply
cutting of the rest. With multiline messages, it is quite common
for a message to be longer than that, and this model doesn't really
work anymore.
A new limit is added: up to 3 lines will be shown, unless --full is
used (c.f. first line below). The limit for bytes is extended to 300
bytes. An ellipsis will always be used, if some form of truncation
occurs. If the tail of the message is cut off, either because of
length or line limit, dots will be shown at the end of the last
line. If this last line is short, the dots will be simply appended. If
the last line is too long for that, it will be ellipsized with dots at
the very end.
Note that the limits are in bytes, not characters, and we suck at
outputting unicode strings (c.f. last three lines below).
Aug 11 10:46:21 fedora python[67]: test message
line
line...
Aug 11 10:50:47 fedora python[76]: test message word word word word word word word word word word word wor...
Aug 11 10:55:11 fedora python[83]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
Aug 11 11:03:21 fedora python[90]: ąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:03:53 fedora python[97]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą...
Aug 11 11:25:45 fedora python[121]: aąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąą�...
2013-08-11 16:56:09 +02:00
|
|
|
(((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
|
|
|
|
&& utf8_is_printable(data, length))) {
|
2013-06-27 01:48:24 +02:00
|
|
|
fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
|
2013-04-24 04:40:26 +02:00
|
|
|
print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
|
2013-06-27 01:48:24 +02:00
|
|
|
fputs(off, f);
|
2013-04-24 04:40:26 +02:00
|
|
|
} else {
|
|
|
|
char bytes[FORMAT_BYTES_MAX];
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2013-06-27 01:48:24 +02:00
|
|
|
fprintf(f, " %s%.*s=[%s blob data]%s\n",
|
|
|
|
on,
|
2013-04-24 04:40:26 +02:00
|
|
|
(int) (c - (const char*) data),
|
|
|
|
(const char*) data,
|
2013-06-27 01:48:24 +02:00
|
|
|
format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
|
|
|
|
off);
|
2013-04-24 04:40:26 +02:00
|
|
|
}
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-11-15 23:03:31 +01:00
|
|
|
if (flags & OUTPUT_CATALOG)
|
|
|
|
print_catalog(f, j);
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int output_export(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
sd_id128_t boot_id;
|
|
|
|
char sid[33];
|
|
|
|
int r;
|
|
|
|
usec_t realtime, monotonic;
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *cursor = NULL;
|
2012-01-03 21:08:28 +01:00
|
|
|
const void *data;
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
r = sd_journal_get_realtime_usec(j, &realtime);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
r = sd_journal_get_cursor(j, &cursor);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get cursor: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f,
|
|
|
|
"__CURSOR=%s\n"
|
2014-04-25 13:45:15 +02:00
|
|
|
"__REALTIME_TIMESTAMP="USEC_FMT"\n"
|
|
|
|
"__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
|
2012-09-27 23:27:10 +02:00
|
|
|
"_BOOT_ID=%s\n",
|
|
|
|
cursor,
|
2014-04-25 13:45:15 +02:00
|
|
|
realtime,
|
|
|
|
monotonic,
|
2012-09-27 23:27:10 +02:00
|
|
|
sd_id128_to_string(boot_id, sid));
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-04-04 01:00:09 +02:00
|
|
|
/* We already printed the boot id, from the data in
|
|
|
|
* the header, hence let's suppress it here */
|
|
|
|
if (length >= 9 &&
|
2013-08-22 03:20:55 +02:00
|
|
|
startswith(data, "_BOOT_ID="))
|
2012-04-04 01:00:09 +02:00
|
|
|
continue;
|
|
|
|
|
2014-03-31 14:57:28 +02:00
|
|
|
if (utf8_is_printable_newline(data, length, false))
|
|
|
|
fwrite(data, length, 1, f);
|
|
|
|
else {
|
2012-01-03 21:08:28 +01:00
|
|
|
const char *c;
|
|
|
|
uint64_t le64;
|
|
|
|
|
|
|
|
c = memchr(data, '=', length);
|
|
|
|
if (!c) {
|
|
|
|
log_error("Invalid field.");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fwrite(data, c - (const char*) data, 1, f);
|
|
|
|
fputc('\n', f);
|
2012-01-03 21:08:28 +01:00
|
|
|
le64 = htole64(length - (c - (const char*) data) - 1);
|
2012-09-27 23:27:10 +02:00
|
|
|
fwrite(&le64, sizeof(le64), 1, f);
|
|
|
|
fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
|
2014-03-31 14:57:28 +02:00
|
|
|
}
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputc('\n', f);
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputc('\n', f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-18 22:31:27 +02:00
|
|
|
void json_escape(
|
2012-09-27 23:27:10 +02:00
|
|
|
FILE *f,
|
|
|
|
const char* p,
|
|
|
|
size_t l,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
assert(p);
|
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
|
2012-09-27 23:27:10 +02:00
|
|
|
|
|
|
|
fputs("null", f);
|
|
|
|
|
2013-04-24 04:40:26 +02:00
|
|
|
else if (!utf8_is_printable(p, l)) {
|
2012-01-03 21:08:28 +01:00
|
|
|
bool not_first = false;
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputs("[ ", f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
while (l > 0) {
|
|
|
|
if (not_first)
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, ", %u", (uint8_t) *p);
|
2012-01-03 21:08:28 +01:00
|
|
|
else {
|
|
|
|
not_first = true;
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, "%u", (uint8_t) *p);
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
p++;
|
|
|
|
l--;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputs(" ]", f);
|
2012-01-03 21:08:28 +01:00
|
|
|
} else {
|
2012-09-27 23:27:10 +02:00
|
|
|
fputc('\"', f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
while (l > 0) {
|
|
|
|
if (*p == '"' || *p == '\\') {
|
2012-09-27 23:27:10 +02:00
|
|
|
fputc('\\', f);
|
|
|
|
fputc(*p, f);
|
2013-04-24 04:40:26 +02:00
|
|
|
} else if (*p == '\n')
|
|
|
|
fputs("\\n", f);
|
|
|
|
else if (*p < ' ')
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, "\\u%04x", *p);
|
|
|
|
else
|
|
|
|
fputc(*p, f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
p++;
|
|
|
|
l--;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fputc('\"', f);
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int output_json(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
uint64_t realtime, monotonic;
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_free_ char *cursor = NULL;
|
2012-01-03 21:08:28 +01:00
|
|
|
const void *data;
|
|
|
|
size_t length;
|
|
|
|
sd_id128_t boot_id;
|
2013-01-15 21:02:00 +01:00
|
|
|
char sid[33], *k;
|
2012-01-03 21:08:28 +01:00
|
|
|
int r;
|
2012-10-25 01:19:24 +02:00
|
|
|
Hashmap *h = NULL;
|
|
|
|
bool done, separator;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
|
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
r = sd_journal_get_realtime_usec(j, &realtime);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
r = sd_journal_get_cursor(j, &cursor);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get cursor: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-09-06 00:25:32 +02:00
|
|
|
if (mode == OUTPUT_JSON_PRETTY)
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f,
|
|
|
|
"{\n"
|
|
|
|
"\t\"__CURSOR\" : \"%s\",\n"
|
2014-04-25 13:45:15 +02:00
|
|
|
"\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
|
|
|
|
"\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
|
2012-09-27 23:27:10 +02:00
|
|
|
"\t\"_BOOT_ID\" : \"%s\"",
|
|
|
|
cursor,
|
2014-04-25 13:45:15 +02:00
|
|
|
realtime,
|
|
|
|
monotonic,
|
2012-09-27 23:27:10 +02:00
|
|
|
sd_id128_to_string(boot_id, sid));
|
2012-10-11 02:37:10 +02:00
|
|
|
else {
|
|
|
|
if (mode == OUTPUT_JSON_SSE)
|
|
|
|
fputs("data: ", f);
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f,
|
|
|
|
"{ \"__CURSOR\" : \"%s\", "
|
2014-04-25 13:45:15 +02:00
|
|
|
"\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
|
|
|
|
"\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
|
2012-09-27 23:27:10 +02:00
|
|
|
"\"_BOOT_ID\" : \"%s\"",
|
|
|
|
cursor,
|
2014-04-25 13:45:15 +02:00
|
|
|
realtime,
|
|
|
|
monotonic,
|
2012-09-27 23:27:10 +02:00
|
|
|
sd_id128_to_string(boot_id, sid));
|
2012-10-11 02:37:10 +02:00
|
|
|
}
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
h = hashmap_new(&string_hash_ops);
|
2012-10-25 01:19:24 +02:00
|
|
|
if (!h)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_oom();
|
2012-10-25 01:19:24 +02:00
|
|
|
|
|
|
|
/* First round, iterate through the entry and count how often each field appears */
|
2013-06-10 03:50:56 +02:00
|
|
|
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
|
2012-10-25 01:19:24 +02:00
|
|
|
const char *eq;
|
|
|
|
char *n;
|
|
|
|
unsigned u;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-04-04 01:00:09 +02:00
|
|
|
if (length >= 9 &&
|
|
|
|
memcmp(data, "_BOOT_ID=", 9) == 0)
|
|
|
|
continue;
|
|
|
|
|
2012-10-25 01:19:24 +02:00
|
|
|
eq = memchr(data, '=', length);
|
|
|
|
if (!eq)
|
|
|
|
continue;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-10-25 01:19:24 +02:00
|
|
|
n = strndup(data, eq - (const char*) data);
|
|
|
|
if (!n) {
|
2015-05-19 00:25:45 +02:00
|
|
|
r = log_oom();
|
2012-10-25 01:19:24 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
2012-09-06 00:25:32 +02:00
|
|
|
|
2012-10-25 01:19:24 +02:00
|
|
|
u = PTR_TO_UINT(hashmap_get(h, n));
|
|
|
|
if (u == 0) {
|
|
|
|
r = hashmap_put(h, n, UINT_TO_PTR(1));
|
|
|
|
if (r < 0) {
|
|
|
|
free(n);
|
2015-05-19 00:25:45 +02:00
|
|
|
log_oom();
|
2012-10-25 01:19:24 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
|
|
|
|
free(n);
|
2015-05-19 00:25:45 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_oom();
|
2012-10-25 01:19:24 +02:00
|
|
|
goto finish;
|
2015-05-19 00:25:45 +02:00
|
|
|
}
|
2012-10-25 01:19:24 +02:00
|
|
|
}
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2013-06-10 03:50:56 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2012-10-25 01:19:24 +02:00
|
|
|
separator = true;
|
|
|
|
do {
|
|
|
|
done = true;
|
|
|
|
|
|
|
|
SD_JOURNAL_FOREACH_DATA(j, data, length) {
|
|
|
|
const char *eq;
|
|
|
|
char *kk, *n;
|
|
|
|
size_t m;
|
|
|
|
unsigned u;
|
|
|
|
|
|
|
|
/* We already printed the boot id, from the data in
|
|
|
|
* the header, hence let's suppress it here */
|
|
|
|
if (length >= 9 &&
|
|
|
|
memcmp(data, "_BOOT_ID=", 9) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
eq = memchr(data, '=', length);
|
|
|
|
if (!eq)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (separator) {
|
|
|
|
if (mode == OUTPUT_JSON_PRETTY)
|
|
|
|
fputs(",\n\t", f);
|
|
|
|
else
|
|
|
|
fputs(", ", f);
|
|
|
|
}
|
|
|
|
|
|
|
|
m = eq - (const char*) data;
|
|
|
|
|
|
|
|
n = strndup(data, m);
|
|
|
|
if (!n) {
|
2015-05-19 00:25:45 +02:00
|
|
|
r = log_oom();
|
2012-10-25 01:19:24 +02:00
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
|
|
|
|
if (u == 0) {
|
|
|
|
/* We already printed this, let's jump to the next */
|
|
|
|
free(n);
|
|
|
|
separator = false;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
} else if (u == 1) {
|
|
|
|
/* Field only appears once, output it directly */
|
|
|
|
|
|
|
|
json_escape(f, data, m, flags);
|
|
|
|
fputs(" : ", f);
|
|
|
|
|
|
|
|
json_escape(f, eq + 1, length - m - 1, flags);
|
|
|
|
|
|
|
|
hashmap_remove(h, n);
|
|
|
|
free(kk);
|
|
|
|
free(n);
|
|
|
|
|
|
|
|
separator = true;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* Field appears multiple times, output it as array */
|
|
|
|
json_escape(f, data, m, flags);
|
|
|
|
fputs(" : [ ", f);
|
|
|
|
json_escape(f, eq + 1, length - m - 1, flags);
|
|
|
|
|
|
|
|
/* Iterate through the end of the list */
|
|
|
|
|
|
|
|
while (sd_journal_enumerate_data(j, &data, &length) > 0) {
|
|
|
|
if (length < m + 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (memcmp(data, n, m) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (((const char*) data)[m] != '=')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fputs(", ", f);
|
|
|
|
json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs(" ]", f);
|
|
|
|
|
|
|
|
hashmap_remove(h, n);
|
|
|
|
free(kk);
|
|
|
|
free(n);
|
|
|
|
|
|
|
|
/* Iterate data fields form the beginning */
|
|
|
|
done = false;
|
|
|
|
separator = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (!done);
|
|
|
|
|
2012-09-06 00:25:32 +02:00
|
|
|
if (mode == OUTPUT_JSON_PRETTY)
|
2012-09-27 23:27:10 +02:00
|
|
|
fputs("\n}\n", f);
|
2012-10-11 02:37:10 +02:00
|
|
|
else if (mode == OUTPUT_JSON_SSE)
|
|
|
|
fputs("}\n\n", f);
|
2012-09-06 00:25:32 +02:00
|
|
|
else
|
2012-09-27 23:27:10 +02:00
|
|
|
fputs(" }\n", f);
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-10-25 01:19:24 +02:00
|
|
|
r = 0;
|
|
|
|
|
|
|
|
finish:
|
|
|
|
while ((k = hashmap_steal_first_key(h)))
|
|
|
|
free(k);
|
|
|
|
|
|
|
|
hashmap_free(h);
|
|
|
|
|
|
|
|
return r;
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int output_cat(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) {
|
|
|
|
|
2012-01-13 02:58:45 +01:00
|
|
|
const void *data;
|
|
|
|
size_t l;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(j);
|
2012-09-27 23:27:10 +02:00
|
|
|
assert(f);
|
2012-01-13 02:58:45 +01:00
|
|
|
|
2012-11-21 00:28:00 +01:00
|
|
|
sd_journal_set_data_threshold(j, 0);
|
|
|
|
|
2012-01-13 02:58:45 +01:00
|
|
|
r = sd_journal_get_data(j, "MESSAGE", &data, &l);
|
|
|
|
if (r < 0) {
|
2012-09-18 11:12:31 +02:00
|
|
|
/* An entry without MESSAGE=? */
|
|
|
|
if (r == -ENOENT)
|
|
|
|
return 0;
|
|
|
|
|
2014-11-28 19:13:53 +01:00
|
|
|
return log_error_errno(r, "Failed to get data: %m");
|
2012-01-13 02:58:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(l >= 8);
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
fwrite((const char*) data + 8, 1, l - 8, f);
|
|
|
|
fputc('\n', f);
|
2012-01-13 02:58:45 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
static int (*output_funcs[_OUTPUT_MODE_MAX])(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal*j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
OutputFlags flags) = {
|
|
|
|
|
2012-09-06 00:25:32 +02:00
|
|
|
[OUTPUT_SHORT] = output_short,
|
2013-07-18 10:21:45 +02:00
|
|
|
[OUTPUT_SHORT_ISO] = output_short,
|
2013-08-04 15:04:20 +02:00
|
|
|
[OUTPUT_SHORT_PRECISE] = output_short,
|
|
|
|
[OUTPUT_SHORT_MONOTONIC] = output_short,
|
2012-01-03 21:08:28 +01:00
|
|
|
[OUTPUT_VERBOSE] = output_verbose,
|
|
|
|
[OUTPUT_EXPORT] = output_export,
|
2012-01-13 02:58:45 +01:00
|
|
|
[OUTPUT_JSON] = output_json,
|
2012-09-06 00:25:32 +02:00
|
|
|
[OUTPUT_JSON_PRETTY] = output_json,
|
2012-10-11 02:37:10 +02:00
|
|
|
[OUTPUT_JSON_SSE] = output_json,
|
2012-01-13 02:58:45 +01:00
|
|
|
[OUTPUT_CAT] = output_cat
|
2012-01-03 21:08:28 +01:00
|
|
|
};
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
int output_journal(
|
|
|
|
FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
2013-08-04 01:38:13 +02:00
|
|
|
OutputFlags flags,
|
|
|
|
bool *ellipsized) {
|
2012-09-27 23:27:10 +02:00
|
|
|
|
2012-09-04 03:37:46 +02:00
|
|
|
int ret;
|
2012-01-04 18:33:36 +01:00
|
|
|
assert(mode >= 0);
|
2012-01-03 21:08:28 +01:00
|
|
|
assert(mode < _OUTPUT_MODE_MAX);
|
|
|
|
|
2012-03-15 20:49:25 +01:00
|
|
|
if (n_columns <= 0)
|
|
|
|
n_columns = columns();
|
|
|
|
|
2012-09-27 23:27:10 +02:00
|
|
|
ret = output_funcs[mode](f, j, mode, n_columns, flags);
|
2012-09-04 03:37:46 +02:00
|
|
|
fflush(stdout);
|
2013-08-04 01:38:13 +02:00
|
|
|
|
|
|
|
if (ellipsized && ret > 0)
|
|
|
|
*ellipsized = true;
|
|
|
|
|
2012-09-04 03:37:46 +02:00
|
|
|
return ret;
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2014-03-13 03:58:03 +01:00
|
|
|
static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
|
|
|
|
assert(f);
|
|
|
|
assert(flags);
|
|
|
|
|
|
|
|
if (!(*flags & OUTPUT_BEGIN_NEWLINE))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Print a beginning new line if that's request, but only once
|
|
|
|
* on the first line we print. */
|
|
|
|
|
|
|
|
fputc('\n', f);
|
|
|
|
*flags &= ~OUTPUT_BEGIN_NEWLINE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-17 18:55:07 +01:00
|
|
|
static int show_journal(FILE *f,
|
|
|
|
sd_journal *j,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
usec_t not_before,
|
|
|
|
unsigned how_many,
|
2013-08-04 01:38:13 +02:00
|
|
|
OutputFlags flags,
|
|
|
|
bool *ellipsized) {
|
2012-01-03 21:08:28 +01:00
|
|
|
|
|
|
|
int r;
|
2012-01-04 18:33:36 +01:00
|
|
|
unsigned line = 0;
|
|
|
|
bool need_seek = false;
|
2012-07-17 07:35:07 +02:00
|
|
|
int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2013-01-17 18:55:07 +01:00
|
|
|
assert(j);
|
2012-01-04 18:33:36 +01:00
|
|
|
assert(mode >= 0);
|
|
|
|
assert(mode < _OUTPUT_MODE_MAX);
|
2012-08-25 00:55:22 +02:00
|
|
|
|
|
|
|
/* Seek to end */
|
2012-01-03 21:08:28 +01:00
|
|
|
r = sd_journal_seek_tail(j);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to seek to tail: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-01-04 18:33:36 +01:00
|
|
|
r = sd_journal_previous_skip(j, how_many);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to skip previous: %m");
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-01-04 18:33:36 +01:00
|
|
|
for (;;) {
|
|
|
|
for (;;) {
|
|
|
|
usec_t usec;
|
|
|
|
|
|
|
|
if (need_seek) {
|
|
|
|
r = sd_journal_next(j);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to iterate through journal: %m");
|
2012-01-04 18:33:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
2012-01-03 21:08:28 +01:00
|
|
|
|
2012-01-04 18:33:36 +01:00
|
|
|
need_seek = true;
|
|
|
|
|
|
|
|
if (not_before > 0) {
|
|
|
|
r = sd_journal_get_monotonic_usec(j, &usec, NULL);
|
|
|
|
|
|
|
|
/* -ESTALE is returned if the
|
|
|
|
timestamp is not from this boot */
|
|
|
|
if (r == -ESTALE)
|
|
|
|
continue;
|
|
|
|
else if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to get journal time: %m");
|
2012-01-04 18:33:36 +01:00
|
|
|
|
|
|
|
if (usec < not_before)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
line ++;
|
2014-03-13 03:58:03 +01:00
|
|
|
maybe_print_begin_newline(f, &flags);
|
2012-01-04 18:33:36 +01:00
|
|
|
|
2013-08-04 01:38:13 +02:00
|
|
|
r = output_journal(f, j, mode, n_columns, flags, ellipsized);
|
2012-01-04 18:33:36 +01:00
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return r;
|
2012-01-04 18:33:36 +01:00
|
|
|
}
|
|
|
|
|
2012-06-09 10:32:38 +02:00
|
|
|
if (warn_cutoff && line < how_many && not_before > 0) {
|
|
|
|
sd_id128_t boot_id;
|
2015-03-27 12:02:49 +01:00
|
|
|
usec_t cutoff = 0;
|
2012-06-09 10:32:38 +02:00
|
|
|
|
|
|
|
/* Check whether the cutoff line is too early */
|
|
|
|
|
|
|
|
r = sd_id128_get_boot(&boot_id);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to get boot id: %m");
|
2012-06-09 10:32:38 +02:00
|
|
|
|
|
|
|
r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to get journal cutoff time: %m");
|
2012-06-09 10:32:38 +02:00
|
|
|
|
2014-03-13 03:58:03 +01:00
|
|
|
if (r > 0 && not_before < cutoff) {
|
|
|
|
maybe_print_begin_newline(f, &flags);
|
2012-09-27 23:27:10 +02:00
|
|
|
fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
|
2014-03-13 03:58:03 +01:00
|
|
|
}
|
2012-06-09 10:32:38 +02:00
|
|
|
|
|
|
|
warn_cutoff = false;
|
|
|
|
}
|
|
|
|
|
2012-07-17 07:35:07 +02:00
|
|
|
if (!(flags & OUTPUT_FOLLOW))
|
2012-01-03 21:08:28 +01:00
|
|
|
break;
|
|
|
|
|
2014-07-29 12:23:31 +02:00
|
|
|
r = sd_journal_wait(j, USEC_INFINITY);
|
2012-01-04 18:33:36 +01:00
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to wait for journal: %m");
|
2012-01-04 18:33:36 +01:00
|
|
|
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
|
|
|
|
2015-05-19 00:25:45 +02:00
|
|
|
return 0;
|
2013-01-17 18:55:07 +01:00
|
|
|
}
|
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
int add_matches_for_unit(sd_journal *j, const char *unit) {
|
2013-01-17 18:55:07 +01:00
|
|
|
int r;
|
2013-06-21 04:25:49 +02:00
|
|
|
char *m1, *m2, *m3, *m4;
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
assert(j);
|
2013-01-17 18:55:07 +01:00
|
|
|
assert(unit);
|
|
|
|
|
2015-02-03 02:05:59 +01:00
|
|
|
m1 = strjoina("_SYSTEMD_UNIT=", unit);
|
|
|
|
m2 = strjoina("COREDUMP_UNIT=", unit);
|
|
|
|
m3 = strjoina("UNIT=", unit);
|
|
|
|
m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
(void)(
|
|
|
|
/* Look for messages from the service itself */
|
|
|
|
(r = sd_journal_add_match(j, m1, 0)) ||
|
|
|
|
|
|
|
|
/* Look for coredumps of the service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
2013-06-21 03:48:26 +02:00
|
|
|
(r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
|
|
|
|
(r = sd_journal_add_match(j, "_UID=0", 0)) ||
|
2013-03-14 00:30:05 +01:00
|
|
|
(r = sd_journal_add_match(j, m2, 0)) ||
|
|
|
|
|
|
|
|
/* Look for messages from PID 1 about this service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, "_PID=1", 0)) ||
|
2013-06-21 04:25:49 +02:00
|
|
|
(r = sd_journal_add_match(j, m3, 0)) ||
|
|
|
|
|
|
|
|
/* Look for messages from authorized daemons about this service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, "_UID=0", 0)) ||
|
|
|
|
(r = sd_journal_add_match(j, m4, 0))
|
2013-03-14 00:30:05 +01:00
|
|
|
);
|
2013-06-21 04:25:49 +02:00
|
|
|
|
2013-09-30 23:58:44 +02:00
|
|
|
if (r == 0 && endswith(unit, ".slice")) {
|
|
|
|
char *m5 = strappend("_SYSTEMD_SLICE=", unit);
|
|
|
|
|
|
|
|
/* Show all messages belonging to a slice */
|
|
|
|
(void)(
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m5, 0))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
return r;
|
|
|
|
}
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
|
|
|
|
int r;
|
2013-06-21 04:25:49 +02:00
|
|
|
char *m1, *m2, *m3, *m4;
|
|
|
|
char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
assert(j);
|
|
|
|
assert(unit);
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2015-02-03 02:05:59 +01:00
|
|
|
m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
|
|
|
|
m2 = strjoina("USER_UNIT=", unit);
|
|
|
|
m3 = strjoina("COREDUMP_USER_UNIT=", unit);
|
|
|
|
m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
|
2014-04-25 13:45:15 +02:00
|
|
|
sprintf(muid, "_UID="UID_FMT, uid);
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
(void) (
|
|
|
|
/* Look for messages from the user service itself */
|
|
|
|
(r = sd_journal_add_match(j, m1, 0)) ||
|
2013-06-21 04:25:49 +02:00
|
|
|
(r = sd_journal_add_match(j, muid, 0)) ||
|
2013-03-14 00:30:05 +01:00
|
|
|
|
|
|
|
/* Look for messages from systemd about this service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m2, 0)) ||
|
2013-06-21 04:25:49 +02:00
|
|
|
(r = sd_journal_add_match(j, muid, 0)) ||
|
2013-03-14 00:30:05 +01:00
|
|
|
|
|
|
|
/* Look for coredumps of the service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m3, 0)) ||
|
2013-06-21 04:25:49 +02:00
|
|
|
(r = sd_journal_add_match(j, muid, 0)) ||
|
|
|
|
(r = sd_journal_add_match(j, "_UID=0", 0)) ||
|
|
|
|
|
|
|
|
/* Look for messages from authorized daemons about this service */
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
2013-06-21 03:48:26 +02:00
|
|
|
(r = sd_journal_add_match(j, m4, 0)) ||
|
2013-06-21 04:25:49 +02:00
|
|
|
(r = sd_journal_add_match(j, muid, 0)) ||
|
2013-06-21 03:48:26 +02:00
|
|
|
(r = sd_journal_add_match(j, "_UID=0", 0))
|
2013-03-14 00:30:05 +01:00
|
|
|
);
|
2013-09-30 23:58:44 +02:00
|
|
|
|
|
|
|
if (r == 0 && endswith(unit, ".slice")) {
|
|
|
|
char *m5 = strappend("_SYSTEMD_SLICE=", unit);
|
|
|
|
|
|
|
|
/* Show all messages belonging to a slice */
|
|
|
|
(void)(
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m5, 0)) ||
|
|
|
|
(r = sd_journal_add_match(j, muid, 0))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-01-17 18:55:07 +01:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-12-11 22:04:03 +01:00
|
|
|
static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
|
2014-03-24 03:22:44 +01:00
|
|
|
_cleanup_close_pair_ int pair[2] = { -1, -1 };
|
2013-12-17 01:03:09 +01:00
|
|
|
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
|
2013-12-11 22:04:03 +01:00
|
|
|
pid_t pid, child;
|
|
|
|
siginfo_t si;
|
|
|
|
char buf[37];
|
|
|
|
ssize_t k;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(machine);
|
|
|
|
assert(boot_id);
|
|
|
|
|
2014-10-22 23:20:59 +02:00
|
|
|
if (!machine_name_is_valid(machine))
|
2013-12-11 22:04:03 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
2013-12-14 05:06:40 +01:00
|
|
|
r = container_get_leader(machine, &pid);
|
2013-12-11 22:04:03 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-12-14 05:06:40 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
|
2013-12-11 22:04:03 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2013-12-14 05:06:40 +01:00
|
|
|
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
2013-12-11 22:04:03 +01:00
|
|
|
return -errno;
|
|
|
|
|
|
|
|
child = fork();
|
|
|
|
if (child < 0)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
if (child == 0) {
|
|
|
|
int fd;
|
|
|
|
|
2014-03-18 19:22:43 +01:00
|
|
|
pair[0] = safe_close(pair[0]);
|
2013-12-11 22:04:03 +01:00
|
|
|
|
2014-05-18 13:48:53 +02:00
|
|
|
r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
|
2013-12-11 22:04:03 +01:00
|
|
|
if (r < 0)
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
|
|
if (fd < 0)
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
2015-03-10 02:23:53 +01:00
|
|
|
r = loop_read_exact(fd, buf, 36, false);
|
2014-03-18 19:22:43 +01:00
|
|
|
safe_close(fd);
|
2015-03-10 05:18:26 +01:00
|
|
|
if (r < 0)
|
2013-12-11 22:04:03 +01:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
2013-12-14 05:06:40 +01:00
|
|
|
k = send(pair[1], buf, 36, MSG_NOSIGNAL);
|
2013-12-11 22:04:03 +01:00
|
|
|
if (k != 36)
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
_exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2014-03-18 19:22:43 +01:00
|
|
|
pair[1] = safe_close(pair[1]);
|
2013-12-11 22:04:03 +01:00
|
|
|
|
|
|
|
r = wait_for_terminate(child, &si);
|
|
|
|
if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
|
|
|
|
return r < 0 ? r : -EIO;
|
|
|
|
|
2013-12-23 19:10:11 +01:00
|
|
|
k = recv(pair[0], buf, 36, 0);
|
|
|
|
if (k != 36)
|
|
|
|
return -EIO;
|
|
|
|
|
2013-12-11 22:04:03 +01:00
|
|
|
buf[36] = 0;
|
|
|
|
r = sd_id128_from_string(buf, boot_id);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int add_match_this_boot(sd_journal *j, const char *machine) {
|
2013-06-04 00:28:12 +02:00
|
|
|
char match[9+32+1] = "_BOOT_ID=";
|
|
|
|
sd_id128_t boot_id;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(j);
|
|
|
|
|
2013-12-11 22:04:03 +01:00
|
|
|
if (machine) {
|
|
|
|
r = get_boot_id_for_machine(machine, &boot_id);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
|
2013-12-11 22:04:03 +01:00
|
|
|
} else {
|
|
|
|
r = sd_id128_get_boot(&boot_id);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to get boot id: %m");
|
2013-06-04 00:28:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sd_id128_to_string(boot_id, match + 9);
|
|
|
|
r = sd_journal_add_match(j, match, strlen(match));
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add match: %m");
|
2013-06-04 00:28:12 +02:00
|
|
|
|
|
|
|
r = sd_journal_add_conjunction(j);
|
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to add conjunction: %m");
|
2013-06-04 00:28:12 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-14 00:30:05 +01:00
|
|
|
int show_journal_by_unit(
|
2013-01-17 18:55:07 +01:00
|
|
|
FILE *f,
|
|
|
|
const char *unit,
|
|
|
|
OutputMode mode,
|
|
|
|
unsigned n_columns,
|
|
|
|
usec_t not_before,
|
|
|
|
unsigned how_many,
|
|
|
|
uid_t uid,
|
2013-03-14 00:30:05 +01:00
|
|
|
OutputFlags flags,
|
2015-01-08 14:38:52 +01:00
|
|
|
int journal_open_flags,
|
|
|
|
bool system_unit,
|
2013-08-04 01:38:13 +02:00
|
|
|
bool *ellipsized) {
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2013-04-18 09:11:22 +02:00
|
|
|
_cleanup_journal_close_ sd_journal*j = NULL;
|
2013-01-17 18:55:07 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(mode >= 0);
|
|
|
|
assert(mode < _OUTPUT_MODE_MAX);
|
|
|
|
assert(unit);
|
|
|
|
|
|
|
|
if (how_many <= 0)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-08 14:38:52 +01:00
|
|
|
r = sd_journal_open(&j, journal_open_flags);
|
2013-02-04 15:13:23 +01:00
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to open journal: %m");
|
2013-02-04 15:13:23 +01:00
|
|
|
|
2013-12-11 22:04:03 +01:00
|
|
|
r = add_match_this_boot(j, NULL);
|
2013-06-04 00:28:12 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-01-08 14:38:52 +01:00
|
|
|
if (system_unit)
|
2013-03-14 00:30:05 +01:00
|
|
|
r = add_matches_for_unit(j, unit);
|
|
|
|
else
|
|
|
|
r = add_matches_for_user_unit(j, unit, uid);
|
2013-01-17 18:55:07 +01:00
|
|
|
if (r < 0)
|
2015-05-19 00:25:45 +02:00
|
|
|
return log_error_errno(r, "Failed to add unit matches: %m");
|
2013-01-17 18:55:07 +01:00
|
|
|
|
2015-01-06 06:29:40 +01:00
|
|
|
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
|
2013-07-16 20:45:28 +02:00
|
|
|
_cleanup_free_ char *filter;
|
|
|
|
|
|
|
|
filter = journal_make_match_string(j);
|
2015-05-19 00:25:45 +02:00
|
|
|
if (!filter)
|
|
|
|
return log_oom();
|
|
|
|
|
2013-07-16 20:45:28 +02:00
|
|
|
log_debug("Journal filter: %s", filter);
|
|
|
|
}
|
2013-06-04 00:28:12 +02:00
|
|
|
|
2013-08-04 01:38:13 +02:00
|
|
|
return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
|
2012-01-03 21:08:28 +01:00
|
|
|
}
|
2012-01-04 18:33:36 +01:00
|
|
|
|
|
|
|
static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
|
|
|
|
[OUTPUT_SHORT] = "short",
|
2013-07-18 10:21:45 +02:00
|
|
|
[OUTPUT_SHORT_ISO] = "short-iso",
|
2013-08-04 15:04:20 +02:00
|
|
|
[OUTPUT_SHORT_PRECISE] = "short-precise",
|
|
|
|
[OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
|
2012-01-04 18:33:36 +01:00
|
|
|
[OUTPUT_VERBOSE] = "verbose",
|
|
|
|
[OUTPUT_EXPORT] = "export",
|
2012-01-13 02:58:45 +01:00
|
|
|
[OUTPUT_JSON] = "json",
|
2012-09-06 00:25:32 +02:00
|
|
|
[OUTPUT_JSON_PRETTY] = "json-pretty",
|
2012-10-11 02:37:10 +02:00
|
|
|
[OUTPUT_JSON_SSE] = "json-sse",
|
2012-01-13 02:58:45 +01:00
|
|
|
[OUTPUT_CAT] = "cat"
|
2012-01-04 18:33:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
|