ominfra 0.0.0.dev90__py3-none-any.whl → 0.0.0.dev91__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/clouds/aws/journald2aws/main.py +36 -19
- ominfra/clouds/aws/logs.py +2 -2
- ominfra/journald/__init__.py +0 -0
- ominfra/{clouds/aws/journald2aws/journald → journald}/messages.py +27 -15
- ominfra/journald/tailer.py +453 -0
- ominfra/scripts/journald2aws.py +548 -147
- ominfra/{clouds/aws/journald2aws/threadworker.py → threadworker.py} +6 -3
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/METADATA +4 -4
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/RECORD +14 -14
- ominfra/clouds/aws/journald2aws/journald/__init__.py +0 -1
- ominfra/clouds/aws/journald2aws/journald/tailer.py +0 -108
- /ominfra/{clouds/aws/journald2aws/journald → journald}/genmessages.py +0 -0
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev90.dist-info → ominfra-0.0.0.dev91.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@
|
|
4
4
|
"""
|
5
5
|
TODO:
|
6
6
|
- create log group
|
7
|
-
- log stats - chunk sizes etc
|
7
|
+
- log stats - chunk sizes, byte count, num calls, etc
|
8
8
|
|
9
9
|
==
|
10
10
|
|
@@ -53,11 +53,11 @@ from omlish.lite.marshal import unmarshal_obj
|
|
53
53
|
from omlish.lite.pidfile import Pidfile
|
54
54
|
from omlish.lite.runtime import is_debugger_attached
|
55
55
|
|
56
|
+
from ....journald.messages import JournalctlMessage # noqa
|
57
|
+
from ....journald.tailer import JournalctlTailerWorker
|
56
58
|
from ..auth import AwsSigner
|
57
59
|
from ..logs import AwsLogMessagePoster
|
58
60
|
from ..logs import AwsPutLogEventsResponse
|
59
|
-
from .journald.messages import JournalctlMessage # noqa
|
60
|
-
from .journald.tailer import JournalctlTailerWorker
|
61
61
|
|
62
62
|
|
63
63
|
@dc.dataclass(frozen=True)
|
@@ -184,15 +184,18 @@ class JournalctlToAws:
|
|
184
184
|
|
185
185
|
@cached_nullary
|
186
186
|
def _journalctl_tailer_worker(self) -> JournalctlTailerWorker:
|
187
|
-
ac: ta.Optional[str] =
|
188
|
-
if ac is None:
|
189
|
-
ac = self._read_cursor_file()
|
190
|
-
if ac is not None:
|
191
|
-
log.info('Starting from cursor %s', ac)
|
187
|
+
ac: ta.Optional[str] = None
|
192
188
|
|
193
189
|
if (since := self._config.journalctl_since):
|
194
190
|
log.info('Starting since %s', since)
|
195
191
|
|
192
|
+
else:
|
193
|
+
ac = self._config.journalctl_after_cursor
|
194
|
+
if ac is None:
|
195
|
+
ac = self._read_cursor_file()
|
196
|
+
if ac is not None:
|
197
|
+
log.info('Starting from cursor %s', ac)
|
198
|
+
|
196
199
|
return JournalctlTailerWorker(
|
197
200
|
self._journalctl_message_queue(),
|
198
201
|
|
@@ -208,9 +211,9 @@ class JournalctlToAws:
|
|
208
211
|
def run(self) -> None:
|
209
212
|
self._ensure_locked()
|
210
213
|
|
211
|
-
q = self._journalctl_message_queue()
|
212
|
-
jtw = self._journalctl_tailer_worker()
|
213
|
-
mp = self._aws_log_message_poster()
|
214
|
+
q = self._journalctl_message_queue() # type: queue.Queue[ta.Sequence[JournalctlMessage]]
|
215
|
+
jtw = self._journalctl_tailer_worker() # type: JournalctlTailerWorker
|
216
|
+
mp = self._aws_log_message_poster() # type: AwsLogMessagePoster
|
214
217
|
|
215
218
|
jtw.start()
|
216
219
|
|
@@ -220,7 +223,13 @@ class JournalctlToAws:
|
|
220
223
|
log.critical('Journalctl tailer worker died')
|
221
224
|
break
|
222
225
|
|
223
|
-
|
226
|
+
try:
|
227
|
+
msgs: ta.Sequence[JournalctlMessage] = q.get(timeout=1.)
|
228
|
+
except queue.Empty:
|
229
|
+
msgs = []
|
230
|
+
if not msgs:
|
231
|
+
continue
|
232
|
+
|
224
233
|
log.debug('%r', msgs)
|
225
234
|
|
226
235
|
cur_cursor: ta.Optional[str] = None
|
@@ -233,10 +242,14 @@ class JournalctlToAws:
|
|
233
242
|
log.warning('Empty queue chunk')
|
234
243
|
continue
|
235
244
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
245
|
+
feed_msgs = []
|
246
|
+
for m in msgs:
|
247
|
+
feed_msgs.append(mp.Message(
|
248
|
+
message=json.dumps(m.dct, sort_keys=True),
|
249
|
+
ts_ms=int((m.ts_us / 1000.) if m.ts_us is not None else (time.time() * 1000.)),
|
250
|
+
))
|
251
|
+
|
252
|
+
[post] = mp.feed(feed_msgs)
|
240
253
|
log.debug('%r', post)
|
241
254
|
|
242
255
|
if not self._config.dry_run:
|
@@ -303,9 +316,13 @@ def _main() -> None:
|
|
303
316
|
|
304
317
|
#
|
305
318
|
|
306
|
-
for
|
307
|
-
|
308
|
-
|
319
|
+
for ca, pa in [
|
320
|
+
('journalctl_after_cursor', 'after_cursor'),
|
321
|
+
('journalctl_since', 'since'),
|
322
|
+
('dry_run', 'dry_run'),
|
323
|
+
]:
|
324
|
+
if (av := getattr(args, pa)):
|
325
|
+
config = dc.replace(config, **{ca: av})
|
309
326
|
|
310
327
|
#
|
311
328
|
|
ominfra/clouds/aws/logs.py
CHANGED
@@ -68,7 +68,7 @@ class AwsLogMessagePoster:
|
|
68
68
|
- max_items
|
69
69
|
- max_bytes - manually build body
|
70
70
|
- flush_interval
|
71
|
-
-
|
71
|
+
- split sorted chunks if span over 24h
|
72
72
|
"""
|
73
73
|
|
74
74
|
DEFAULT_URL = 'https://logs.{region_name}.amazonaws.com/' # noqa
|
@@ -141,7 +141,7 @@ class AwsLogMessagePoster:
|
|
141
141
|
message=m.message,
|
142
142
|
timestamp=m.ts_ms,
|
143
143
|
)
|
144
|
-
for m in messages
|
144
|
+
for m in sorted(messages, key=lambda m: m.ts_ms)
|
145
145
|
],
|
146
146
|
)
|
147
147
|
|
File without changes
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
2
3
|
import dataclasses as dc
|
3
4
|
import json
|
4
5
|
import typing as ta
|
@@ -23,7 +24,31 @@ class JournalctlMessageBuilder:
|
|
23
24
|
self._buf = DelimitingBuffer(b'\n')
|
24
25
|
|
25
26
|
_cursor_field = '__CURSOR'
|
26
|
-
|
27
|
+
|
28
|
+
_timestamp_fields: ta.Sequence[str] = [
|
29
|
+
'_SOURCE_REALTIME_TIMESTAMP',
|
30
|
+
'__REALTIME_TIMESTAMP',
|
31
|
+
]
|
32
|
+
|
33
|
+
def _get_message_timestamp(self, dct: ta.Mapping[str, ta.Any]) -> ta.Optional[int]:
|
34
|
+
for fld in self._timestamp_fields:
|
35
|
+
if (tsv := dct.get(fld)) is None:
|
36
|
+
continue
|
37
|
+
|
38
|
+
if isinstance(tsv, str):
|
39
|
+
try:
|
40
|
+
return int(tsv)
|
41
|
+
except ValueError:
|
42
|
+
try:
|
43
|
+
return int(float(tsv))
|
44
|
+
except ValueError:
|
45
|
+
log.exception('Failed to parse timestamp: %r', tsv)
|
46
|
+
|
47
|
+
elif isinstance(tsv, (int, float)):
|
48
|
+
return int(tsv)
|
49
|
+
|
50
|
+
log.error('Invalid timestamp: %r', dct)
|
51
|
+
return None
|
27
52
|
|
28
53
|
def _make_message(self, raw: bytes) -> JournalctlMessage:
|
29
54
|
dct = None
|
@@ -37,20 +62,7 @@ class JournalctlMessageBuilder:
|
|
37
62
|
|
38
63
|
else:
|
39
64
|
cursor = dct.get(self._cursor_field)
|
40
|
-
|
41
|
-
if tsv := dct.get(self._timestamp_field):
|
42
|
-
if isinstance(tsv, str):
|
43
|
-
try:
|
44
|
-
ts = int(tsv)
|
45
|
-
except ValueError:
|
46
|
-
try:
|
47
|
-
ts = int(float(tsv))
|
48
|
-
except ValueError:
|
49
|
-
log.exception('Failed to parse timestamp: %r', tsv)
|
50
|
-
elif isinstance(tsv, (int, float)):
|
51
|
-
ts = int(tsv)
|
52
|
-
else:
|
53
|
-
log.exception('Invalid timestamp: %r', tsv)
|
65
|
+
ts = self._get_message_timestamp(dct)
|
54
66
|
|
55
67
|
return JournalctlMessage(
|
56
68
|
raw=raw,
|
@@ -0,0 +1,453 @@
|
|
1
|
+
# ruff: noqa: UP007
|
2
|
+
# @omlish-lite
|
3
|
+
"""
|
4
|
+
TODO:
|
5
|
+
- https://www.rootusers.com/how-to-change-log-rate-limiting-in-linux/
|
6
|
+
|
7
|
+
==
|
8
|
+
|
9
|
+
https://www.freedesktop.org/software/systemd/man/latest/journalctl.html
|
10
|
+
|
11
|
+
Source Options
|
12
|
+
--system, --user :: Show messages from system services and the kernel (with --system). Show messages from service of
|
13
|
+
current user (with --user). If neither is specified, show all messages that the user can see. The
|
14
|
+
--user option affects how --unit= arguments are treated. See --unit=. Note that --user only works if
|
15
|
+
persistent logging is enabled, via the Storage= setting in journald.conf(5).
|
16
|
+
-M, --machine= :: Show messages from a running, local container. Specify a container name to connect to.
|
17
|
+
-m, --merge :: Show entries interleaved from all available journals, including remote ones.
|
18
|
+
-D DIR, --directory=DIR :: Takes a directory path as argument. If specified, journalctl will operate on the specified
|
19
|
+
journal directory DIR instead of the default runtime and system journal paths.
|
20
|
+
-i GLOB, --file=GLOB :: Takes a file glob as an argument. If specified, journalctl will operate on the specified journal
|
21
|
+
files matching GLOB instead of the default runtime and system journal paths. May be specified
|
22
|
+
multiple times, in which case files will be suitably interleaved.
|
23
|
+
--root=ROOT :: Takes a directory path as an argument. If specified, journalctl will operate on journal directories and
|
24
|
+
catalog file hierarchy underneath the specified directory instead of the root directory (e.g.
|
25
|
+
--update-catalog will create ROOT/var/lib/systemd/catalog/database, and journal files under
|
26
|
+
ROOT/run/journal/ or ROOT/var/log/journal/ will be displayed).
|
27
|
+
--image=IMAGE :: Takes a path to a disk image file or block device node. If specified, journalctl will operate on the
|
28
|
+
file system in the indicated disk image. This option is similar to --root=, but operates on file
|
29
|
+
systems stored in disk images or block devices, thus providing an easy way to extract log data from
|
30
|
+
disk images. The disk image should either contain just a file system or a set of file systems within a
|
31
|
+
GPT partition table, following the Discoverable Partitions Specification. For further information on
|
32
|
+
supported disk images, see systemd-nspawn(1)'s switch of the same name.
|
33
|
+
--image-policy=policy :: Takes an image policy string as argument, as per systemd.image-policy(7). The policy is
|
34
|
+
enforced when operating on the disk image specified via --image=, see above. If not specified
|
35
|
+
defaults to the "*" policy, i.e. all recognized file systems in the image are used.
|
36
|
+
--namespace=NAMESPACE :: Takes a journal namespace identifier string as argument. If not specified the data collected by
|
37
|
+
the default namespace is shown. If specified shows the log data of the specified namespace
|
38
|
+
instead. If the namespace is specified as "*" data from all namespaces is shown, interleaved.
|
39
|
+
If the namespace identifier is prefixed with "+" data from the specified namespace and the
|
40
|
+
default namespace is shown, interleaved, but no other. For details about journal namespaces see
|
41
|
+
systemd-journald.service(8).
|
42
|
+
|
43
|
+
Filtering Options
|
44
|
+
-S, --since=, -U, --until= :: Start showing entries on or newer than the specified date, or on or older than the
|
45
|
+
specified date, respectively. Date specifications should be of the format
|
46
|
+
"2012-10-30 18:17:16". If the time part is omitted, "00:00:00" is assumed. If only the
|
47
|
+
seconds component is omitted, ":00" is assumed. If the date component is omitted, the
|
48
|
+
current day is assumed. Alternatively the strings "yesterday", "today", "tomorrow" are
|
49
|
+
understood, which refer to 00:00:00 of the day before the current day, the current day, or
|
50
|
+
the day after the current day, respectively. "now" refers to the current time. Finally,
|
51
|
+
relative times may be specified, prefixed with "-" or "+", referring to times before or
|
52
|
+
after the current time, respectively. For complete time and date specification, see
|
53
|
+
systemd.time(7). Note that --output=short-full prints timestamps that follow precisely
|
54
|
+
this format.
|
55
|
+
-c, --cursor= :: Start showing entries from the location in the journal specified by the passed cursor.
|
56
|
+
--after-cursor= :: Start showing entries from the location in the journal after the location specified by the passed
|
57
|
+
cursor. The cursor is shown when the --show-cursor option is used.
|
58
|
+
--cursor-file=FILE :: If FILE exists and contains a cursor, start showing entries after this location. Otherwise show
|
59
|
+
entries according to the other given options. At the end, write the cursor of the last entry to
|
60
|
+
FILE. Use this option to continually read the journal by sequentially calling journalctl.
|
61
|
+
-b [[ID][±offset]|all], --boot[=[ID][±offset]|all] :: Show messages from a specific boot. This will add a match for
|
62
|
+
"_BOOT_ID=". The argument may be empty, in which case logs for the
|
63
|
+
current boot will be shown. If the boot ID is omitted, a positive
|
64
|
+
offset will look up the boots starting from the beginning of the
|
65
|
+
journal, and an equal-or-less-than zero offset will look up boots
|
66
|
+
starting from the end of the journal. Thus, 1 means the first boot
|
67
|
+
found in the journal in chronological order, 2 the second and so
|
68
|
+
on; while -0 is the last boot, -1 the boot before last, and so on.
|
69
|
+
An empty offset is equivalent to specifying -0, except when the
|
70
|
+
current boot is not the last boot (e.g. because --directory= was
|
71
|
+
specified to look at logs from a different machine). If the
|
72
|
+
32-character ID is specified, it may optionally be followed by
|
73
|
+
offset which identifies the boot relative to the one given by boot
|
74
|
+
ID. Negative values mean earlier boots and positive values mean
|
75
|
+
later boots. If offset is not specified, a value of zero is
|
76
|
+
assumed, and the logs for the boot given by ID are shown. The
|
77
|
+
special argument all can be used to negate the effect of an
|
78
|
+
earlier use of -b.
|
79
|
+
-u, --unit=UNIT|PATTERN :: Show messages for the specified systemd unit UNIT (such as a service unit), or for any of the
|
80
|
+
units matched by PATTERN. If a pattern is specified, a list of unit names found in the
|
81
|
+
journal is compared with the specified pattern and all that match are used. For each unit
|
82
|
+
name, a match is added for messages from the unit ("_SYSTEMD_UNIT=UNIT"), along with
|
83
|
+
additional matches for messages from systemd and messages about coredumps for the specified
|
84
|
+
unit. A match is also added for "_SYSTEMD_SLICE=UNIT", such that if the provided UNIT is a
|
85
|
+
systemd.slice(5) unit, all logs of children of the slice will be shown. With --user, all
|
86
|
+
--unit= arguments will be converted to match user messages as if specified with --user-unit=.
|
87
|
+
This parameter can be specified multiple times.
|
88
|
+
--user-unit= :: Show messages for the specified user session unit. This will add a match for messages from the unit
|
89
|
+
("_SYSTEMD_USER_UNIT=" and "_UID=") and additional matches for messages from session systemd and
|
90
|
+
messages about coredumps for the specified unit. A match is also added for "_SYSTEMD_USER_SLICE=UNIT",
|
91
|
+
such that if the provided UNIT is a systemd.slice(5) unit, all logs of children of the unit will be
|
92
|
+
shown. This parameter can be specified multiple times.
|
93
|
+
-t, --identifier=SYSLOG_IDENTIFIER :: Show messages for the specified syslog identifier SYSLOG_IDENTIFIER. This
|
94
|
+
parameter can be specified multiple times.
|
95
|
+
-T, --exclude-identifier=SYSLOG_IDENTIFIER :: Exclude messages for the specified syslog identifier SYSLOG_IDENTIFIER.
|
96
|
+
This parameter can be specified multiple times.
|
97
|
+
-p, --priority= :: Filter output by message priorities or priority ranges. Takes either a single numeric or textual log
|
98
|
+
level (i.e. between 0/"emerg" and 7/"debug"), or a range of numeric/text log levels in the form
|
99
|
+
FROM..TO. The log levels are the usual syslog log levels as documented in syslog(3), i.e. "emerg"
|
100
|
+
(0), "alert" (1), "crit" (2), "err" (3), "warning" (4), "notice" (5), "info" (6), "debug" (7). If a
|
101
|
+
single log level is specified, all messages with this log level or a lower (hence more important) log
|
102
|
+
level are shown. If a range is specified, all messages within the range are shown, including both the
|
103
|
+
start and the end value of the range. This will add "PRIORITY=" matches for the specified priorities.
|
104
|
+
--facility= :: Filter output by syslog facility. Takes a comma-separated list of numbers or facility names. The names
|
105
|
+
are the usual syslog facilities as documented in syslog(3). --facility=help may be used to display a list
|
106
|
+
of known facility names and exit.
|
107
|
+
-g, --grep= :: Filter output to entries where the MESSAGE= field matches the specified regular expression.
|
108
|
+
PERL-compatible regular expressions are used, see pcre2pattern(3) for a detailed description of the
|
109
|
+
syntax. If the pattern is all lowercase, matching is case insensitive. Otherwise, matching is case
|
110
|
+
sensitive. This can be overridden with the --case-sensitive option, see below. When used with --lines=
|
111
|
+
(not prefixed with "+"), --reverse is implied.
|
112
|
+
--case-sensitive[=BOOLEAN] :: Make pattern matching case sensitive or case insensitive.
|
113
|
+
-k, --dmesg :: Show only kernel messages. This implies -b and adds the match "_TRANSPORT=kernel".
|
114
|
+
|
115
|
+
Output Options
|
116
|
+
-o, --output= :: Controls the formatting of the journal entries that are shown. Takes one of the following options:
|
117
|
+
short :: is the default and generates an output that is mostly identical to the formatting of classic syslog files,
|
118
|
+
showing one line per journal entry.
|
119
|
+
short-full :: is very similar, but shows timestamps in the format the --since= and --until= options accept. Unlike the
|
120
|
+
timestamp information shown in short output mode this mode includes weekday, year and timezone
|
121
|
+
information in the output, and is locale-independent.
|
122
|
+
short-iso :: is very similar, but shows timestamps in the RFC 3339 profile of ISO 8601.
|
123
|
+
short-iso-precise :: as for short-iso but includes full microsecond precision.
|
124
|
+
short-precise :: is very similar, but shows classic syslog timestamps with full microsecond precision.
|
125
|
+
short-monotonic :: is very similar, but shows monotonic timestamps instead of wallclock timestamps.
|
126
|
+
short-delta :: as for short-monotonic but includes the time difference to the previous entry. Maybe unreliable time
|
127
|
+
differences are marked by a "*".
|
128
|
+
short-unix :: is very similar, but shows seconds passed since January 1st 1970 UTC instead of wallclock timestamps
|
129
|
+
("UNIX time"). The time is shown with microsecond accuracy.
|
130
|
+
verbose :: shows the full-structured entry items with all fields.
|
131
|
+
export :: serializes the journal into a binary (but mostly text-based) stream suitable for backups and network
|
132
|
+
transfer (see Journal Export Format for more information). To import the binary stream back into native
|
133
|
+
journald format use systemd-journal-remote(8).
|
134
|
+
json :: formats entries as JSON objects, separated by newline characters (see Journal JSON Format for more
|
135
|
+
information). Field values are generally encoded as JSON strings, with three exceptions: Fields larger than
|
136
|
+
4096 bytes are encoded as null values. (This may be turned off by passing --all, but be aware that this may
|
137
|
+
allocate overly long JSON objects.) Journal entries permit non-unique fields within the same log entry. JSON
|
138
|
+
does not allow non-unique fields within objects. Due to this, if a non-unique field is encountered a JSON
|
139
|
+
array is used as field value, listing all field values as elements. Fields containing non-printable or
|
140
|
+
non-UTF8 bytes are encoded as arrays containing the raw bytes individually formatted as unsigned numbers. Note
|
141
|
+
that this encoding is reversible (with the exception of the size limit).
|
142
|
+
json-pretty :: formats entries as JSON data structures, but formats them in multiple lines in order to make them more
|
143
|
+
readable by humans.
|
144
|
+
json-sse :: formats entries as JSON data structures, but wraps them in a format suitable for Server-Sent Events.
|
145
|
+
json-seq :: formats entries as JSON data structures, but prefixes them with an ASCII Record Separator character (0x1E)
|
146
|
+
and suffixes them with an ASCII Line Feed character (0x0A), in accordance with JavaScript Object Notation
|
147
|
+
(JSON) Text Sequences ("application/json-seq").
|
148
|
+
cat :: generates a very terse output, only showing the actual message of each journal entry with no metadata, not even
|
149
|
+
a timestamp. If combined with the --output-fields= option will output the listed fields for each log record,
|
150
|
+
instead of the message.
|
151
|
+
with-unit :: similar to short-full, but prefixes the unit and user unit names instead of the traditional syslog
|
152
|
+
identifier. Useful when using templated instances, as it will include the arguments in the unit names.
|
153
|
+
--truncate-newline :: Truncate each log message at the first newline character on output, so that only the first line of
|
154
|
+
each message is displayed.
|
155
|
+
--output-fields= :: A comma separated list of the fields which should be included in the output. This has an effect only
|
156
|
+
for the output modes which would normally show all fields (verbose, export, json, json-pretty,
|
157
|
+
json-sse and json-seq), as well as on cat. For the former, the "__CURSOR", "__REALTIME_TIMESTAMP",
|
158
|
+
"__MONOTONIC_TIMESTAMP", and "_BOOT_ID" fields are always printed.
|
159
|
+
-n, --lines= :: Show the most recent journal events and limit the number of events shown. The argument is a positive
|
160
|
+
integer or "all" to disable the limit. Additionally, if the number is prefixed with "+", the oldest
|
161
|
+
journal events are used instead. The default value is 10 if no argument is given. If --follow is used,
|
162
|
+
this option is implied. When not prefixed with "+" and used with --grep=, --reverse is implied.
|
163
|
+
-r, --reverse :: Reverse output so that the newest entries are displayed first.
|
164
|
+
--show-cursor :: The cursor is shown after the last entry after two dashes:
|
165
|
+
-- cursor: s=0639… :: The format of the cursor is private and subject to change.
|
166
|
+
--utc :: Express time in Coordinated Universal Time (UTC).
|
167
|
+
-x, --catalog :: Augment log lines with explanation texts from the message catalog. This will add explanatory help texts
|
168
|
+
to log messages in the output where this is available. These short help texts will explain the context
|
169
|
+
of an error or log event, possible solutions, as well as pointers to support forums, developer
|
170
|
+
documentation, and any other relevant manuals. Note that help texts are not available for all messages,
|
171
|
+
but only for selected ones. For more information on the message catalog, see Journal Message Catalogs.
|
172
|
+
Note: when attaching journalctl output to bug reports, please do not use -x.
|
173
|
+
--no-hostname :: Don't show the hostname field of log messages originating from the local host. This switch has an
|
174
|
+
effect only on the short family of output modes (see above). Note: this option does not remove
|
175
|
+
occurrences of the hostname from log entries themselves, so it does not prevent the hostname from being
|
176
|
+
visible in the logs.
|
177
|
+
--no-full, --full, -l :: Ellipsize fields when they do not fit in available columns. The default is to show full fields,
|
178
|
+
allowing them to wrap or be truncated by the pager, if one is used. The old options -l/--full
|
179
|
+
are not useful anymore, except to undo --no-full.
|
180
|
+
-a, --all :: Show all fields in full, even if they include unprintable characters or are very long. By default, fields
|
181
|
+
with unprintable characters are abbreviated as "blob data". (Note that the pager may escape unprintable
|
182
|
+
characters again.)
|
183
|
+
-f, --follow :: Show only the most recent journal entries, and continuously print new entries as they are appended to
|
184
|
+
the journal.
|
185
|
+
--no-tail :: Show all stored output lines, even in follow mode. Undoes the effect of --lines=.
|
186
|
+
-q, --quiet :: Suppresses all informational messages (i.e. "-- Journal begins at …", "-- Reboot --"), any warning
|
187
|
+
messages regarding inaccessible system journals when run as a normal user.
|
188
|
+
|
189
|
+
Pager Control Options
|
190
|
+
--no-pager :: Do not pipe output into a pager.
|
191
|
+
-e, --pager-end :: Immediately jump to the end of the journal inside the implied pager tool. This implies -n1000 to
|
192
|
+
guarantee that the pager will not buffer logs of unbounded size. This may be overridden with an
|
193
|
+
explicit -n with some other numeric value, while -nall will disable this cap. Note that this option
|
194
|
+
is only supported for the less(1) pager.
|
195
|
+
|
196
|
+
Forward Secure Sealing (FSS) Options
|
197
|
+
--interval= :: Specifies the change interval for the sealing key when generating an FSS key pair with --setup-keys.
|
198
|
+
Shorter intervals increase CPU consumption but shorten the time range of undetectable journal
|
199
|
+
alterations. Defaults to 15min.
|
200
|
+
--verify-key= :: Specifies the FSS verification key to use for the --verify operation.
|
201
|
+
--force :: When --setup-keys is passed and Forward Secure Sealing (FSS) has already been configured, recreate FSS keys.
|
202
|
+
|
203
|
+
Commands
|
204
|
+
-N, --fields :: Print all field names currently used in all entries of the journal.
|
205
|
+
-F, --field= :: Print all possible data values the specified field can take in all entries of the journal.
|
206
|
+
--list-boots :: Show a tabular list of boot numbers (relative to the current boot), their IDs, and the timestamps of the
|
207
|
+
first and last message pertaining to the boot. When specified with -n/--lines=[+]N option, only the
|
208
|
+
first (when the number prefixed with "+") or the last (without prefix) N entries will be shown. When
|
209
|
+
specified with -r/--reverse, the list will be shown in the reverse order.
|
210
|
+
--disk-usage :: Shows the current disk usage of all journal files. This shows the sum of the disk usage of all archived
|
211
|
+
and active journal files.
|
212
|
+
--vacuum-size=, --vacuum-time=, --vacuum-files=
|
213
|
+
--vacuum-size= :: removes the oldest archived journal files until the disk space they use falls below the specified
|
214
|
+
size. Accepts the usual "K", "M", "G" and "T" suffixes (to the base of 1024).
|
215
|
+
--vacuum-time= :: removes archived journal files older than the specified timespan. Accepts the usual "s" (default),
|
216
|
+
"m", "h", "days", "weeks", "months", and "years" suffixes, see systemd.time(7) for details.
|
217
|
+
--vacuum-files= :: leaves only the specified number of separate journal files.
|
218
|
+
Note that running --vacuum-size= has only an indirect effect on the output shown by --disk-usage, as the latter
|
219
|
+
includes active journal files, while the vacuuming operation only operates on archived journal files. Similarly,
|
220
|
+
--vacuum-files= might not actually reduce the number of journal files to below the specified number, as it will not
|
221
|
+
remove active journal files.
|
222
|
+
--vacuum-size=, --vacuum-time= and --vacuum-files= may be combined in a single invocation to enforce any combination
|
223
|
+
of a size, a time and a number of files limit on the archived journal files. Specifying any of these three parameters
|
224
|
+
as zero is equivalent to not enforcing the specific limit, and is thus redundant.
|
225
|
+
These three switches may also be combined with --rotate into one command. If so, all active files are rotated first,
|
226
|
+
and the requested vacuuming operation is executed right after. The rotation has the effect that all currently active
|
227
|
+
files are archived (and potentially new, empty journal files opened as replacement), and hence the vacuuming operation
|
228
|
+
has the greatest effect as it can take all log data written so far into account.
|
229
|
+
--verify :: Check the journal file for internal consistency. If the file has been generated with FSS enabled and the FSS
|
230
|
+
verification key has been specified with --verify-key=, authenticity of the journal file is verified.
|
231
|
+
--sync :: Asks the journal daemon to write all yet unwritten journal data to the backing file system and synchronize all
|
232
|
+
journals. This call does not return until the synchronization operation is complete. This command guarantees
|
233
|
+
that any log messages written before its invocation are safely stored on disk at the time it returns.
|
234
|
+
--relinquish-var :: Asks the journal daemon for the reverse operation to --flush: if requested the daemon will write
|
235
|
+
further log data to /run/log/journal/ and stops writing to /var/log/journal/. A subsequent call to
|
236
|
+
--flush causes the log output to switch back to /var/log/journal/, see above.
|
237
|
+
--smart-relinquish-var :: Similar to --relinquish-var, but executes no operation if the root file system and
|
238
|
+
/var/log/journal/ reside on the same mount point. This operation is used during system
|
239
|
+
shutdown in order to make the journal daemon stop writing data to /var/log/journal/ in case
|
240
|
+
that directory is located on a mount point that needs to be unmounted.
|
241
|
+
--flush :: Asks the journal daemon to flush any log data stored in /run/log/journal/ into /var/log/journal/, if
|
242
|
+
persistent storage is enabled. This call does not return until the operation is complete. Note that this call
|
243
|
+
is idempotent: the data is only flushed from /run/log/journal/ into /var/log/journal/ once during system
|
244
|
+
runtime (but see --relinquish-var below), and this command exits cleanly without executing any operation if
|
245
|
+
this has already happened. This command effectively guarantees that all data is flushed to /var/log/journal/
|
246
|
+
at the time it returns.
|
247
|
+
--rotate :: Asks the journal daemon to rotate journal files. This call does not return until the rotation operation is
|
248
|
+
complete. Journal file rotation has the effect that all currently active journal files are marked as
|
249
|
+
archived and renamed, so that they are never written to in future. New (empty) journal files are then
|
250
|
+
created in their place. This operation may be combined with --vacuum-size=, --vacuum-time= and
|
251
|
+
--vacuum-file= into a single command, see above.
|
252
|
+
--header :: Instead of showing journal contents, show internal header information of the journal fields accessed. This
|
253
|
+
option is particularly useful when trying to identify out-of-order journal entries, as happens for example
|
254
|
+
when the machine is booted with the wrong system time.
|
255
|
+
--list-catalog [128-bit-ID…] :: List the contents of the message catalog as a table of message IDs, plus their short
|
256
|
+
description strings. If any 128-bit-IDs are specified, only those entries are shown.
|
257
|
+
--dump-catalog [128-bit-ID…] :: Show the contents of the message catalog, with entries separated by a line consisting of
|
258
|
+
two dashes and the ID (the format is the same as .catalog files). If any 128-bit-IDs are
|
259
|
+
specified, only those entries are shown.
|
260
|
+
--update-catalog :: Update the message catalog index. This command needs to be executed each time new catalog files are
|
261
|
+
installed, removed, or updated to rebuild the binary catalog index.
|
262
|
+
--setup-keys :: Instead of showing journal contents, generate a new key pair for Forward Secure Sealing (FSS). This will
|
263
|
+
generate a sealing key and a verification key. The sealing key is stored in the journal data directory
|
264
|
+
and shall remain on the host. The verification key should be stored externally. Refer to the Seal=
|
265
|
+
option in journald.conf(5) for information on Forward Secure Sealing and for a link to a refereed
|
266
|
+
scholarly paper detailing the cryptographic theory it is based on.
|
267
|
+
-h, --help :: Print a short help text and exit.
|
268
|
+
--version :: Print a short version string and exit.
|
269
|
+
|
270
|
+
Environment
|
271
|
+
$SYSTEMD_LOG_LEVEL :: The maximum log level of emitted messages (messages with a higher log level, i.e. less important
|
272
|
+
ones, will be suppressed). Takes a comma-separated list of values. A value may be either one of
|
273
|
+
(in order of decreasing importance) emerg, alert, crit, err, warning, notice, info, debug, or an
|
274
|
+
integer in the range 0…7. See syslog(3) for more information. Each value may optionally be
|
275
|
+
prefixed with one of console, syslog, kmsg or journal followed by a colon to set the maximum log
|
276
|
+
level for that specific log target (e.g. SYSTEMD_LOG_LEVEL=debug,console:info specifies to log at
|
277
|
+
debug level except when logging to the console which should be at info level). Note that the
|
278
|
+
global maximum log level takes priority over any per target maximum log levels.
|
279
|
+
$SYSTEMD_LOG_COLOR :: A boolean. If true, messages written to the tty will be colored according to priority. This
|
280
|
+
setting is only useful when messages are written directly to the terminal, because journalctl(1)
|
281
|
+
and other tools that display logs will color messages based on the log level on their own.
|
282
|
+
$SYSTEMD_LOG_TIME :: A boolean. If true, console log messages will be prefixed with a timestamp. This setting is only
|
283
|
+
useful when messages are written directly to the terminal or a file, because journalctl(1) and
|
284
|
+
other tools that display logs will attach timestamps based on the entry metadata on their own.
|
285
|
+
$SYSTEMD_LOG_LOCATION :: A boolean. If true, messages will be prefixed with a filename and line number in the source
|
286
|
+
code where the message originates. Note that the log location is often attached as metadata to
|
287
|
+
journal entries anyway. Including it directly in the message text can nevertheless be
|
288
|
+
convenient when debugging programs.
|
289
|
+
$SYSTEMD_LOG_TID :: A boolean. If true, messages will be prefixed with the current numerical thread ID (TID). Note that
|
290
|
+
the this information is attached as metadata to journal entries anyway. Including it directly in the
|
291
|
+
message text can nevertheless be convenient when debugging programs.
|
292
|
+
$SYSTEMD_LOG_TARGET :: The destination for log messages. One of console (log to the attached tty), console-prefixed (log
|
293
|
+
to the attached tty but with prefixes encoding the log level and "facility", see syslog(3), kmsg
|
294
|
+
(log to the kernel circular log buffer), journal (log to the journal), journal-or-kmsg (log to
|
295
|
+
the journal if available, and to kmsg otherwise), auto (determine the appropriate log target
|
296
|
+
automatically, the default), null (disable log output).
|
297
|
+
$SYSTEMD_LOG_RATELIMIT_KMSG :: Whether to ratelimit kmsg or not. Takes a boolean. Defaults to "true". If disabled,
|
298
|
+
systemd will not ratelimit messages written to kmsg.
|
299
|
+
$SYSTEMD_PAGER :: Pager to use when --no-pager is not given; overrides $PAGER. If neither $SYSTEMD_PAGER nor $PAGER are
|
300
|
+
set, a set of well-known pager implementations are tried in turn, including less(1) and more(1), until
|
301
|
+
one is found. If no pager implementation is discovered no pager is invoked. Setting this environment
|
302
|
+
variable to an empty string or the value "cat" is equivalent to passing --no-pager. Note: if
|
303
|
+
$SYSTEMD_PAGERSECURE is not set, $SYSTEMD_PAGER (as well as $PAGER) will be silently ignored.
|
304
|
+
$SYSTEMD_LESS :: Override the options passed to less (by default "FRSXMK"). Users might want to change two options in
|
305
|
+
particular:
|
306
|
+
K :: This option instructs the pager to exit immediately when Ctrl+C is pressed. To allow less to handle Ctrl+C itself
|
307
|
+
to switch back to the pager command prompt, unset this option. If the value of $SYSTEMD_LESS does not include
|
308
|
+
"K", and the pager that is invoked is less, Ctrl+C will be ignored by the executable, and needs to be handled by
|
309
|
+
the pager.
|
310
|
+
X :: This option instructs the pager to not send termcap initialization and deinitialization strings to the terminal.
|
311
|
+
It is set by default to allow command output to remain visible in the terminal even after the pager exits.
|
312
|
+
Nevertheless, this prevents some pager functionality from working, in particular paged output cannot be scrolled
|
313
|
+
with the mouse. Note that setting the regular $LESS environment variable has no effect for less invocations by
|
314
|
+
systemd tools.
|
315
|
+
$SYSTEMD_LESSCHARSET :: Override the charset passed to less (by default "utf-8", if the invoking terminal is determined
|
316
|
+
to be UTF-8 compatible). Note that setting the regular $LESSCHARSET environment variable has no
|
317
|
+
effect for less invocations by systemd tools.
|
318
|
+
$SYSTEMD_PAGERSECURE :: Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if false,
|
319
|
+
disabled. If $SYSTEMD_PAGERSECURE is not set at all, secure mode is enabled if the effective UID
|
320
|
+
is not the same as the owner of the login session, see geteuid(2) and sd_pid_get_owner_uid(3).
|
321
|
+
In secure mode, LESSSECURE=1 will be set when invoking the pager, and the pager shall disable
|
322
|
+
commands that open or create new files or start new subprocesses. When $SYSTEMD_PAGERSECURE is
|
323
|
+
not set at all, pagers which are not known to implement secure mode will not be used. (Currently
|
324
|
+
only less(1) implements secure mode.) Note: when commands are invoked with elevated privileges,
|
325
|
+
for example under sudo(8) or pkexec(1), care must be taken to ensure that unintended interactive
|
326
|
+
features are not enabled. "Secure" mode for the pager may be enabled automatically as describe
|
327
|
+
above. Setting SYSTEMD_PAGERSECURE=0 or not removing it from the inherited environment allows
|
328
|
+
the user to invoke arbitrary commands. Note that if the $SYSTEMD_PAGER or $PAGER variables are
|
329
|
+
to be honoured, $SYSTEMD_PAGERSECURE must be set too. It might be reasonable to completely
|
330
|
+
disable the pager using --no-pager instead.
|
331
|
+
$SYSTEMD_COLORS :: Takes a boolean argument. When true, systemd and related utilities will use colors in their output,
|
332
|
+
otherwise the output will be monochrome. Additionally, the variable can take one of the following
|
333
|
+
special values: "16", "256" to restrict the use of colors to the base 16 or 256 ANSI colors,
|
334
|
+
respectively. This can be specified to override the automatic decision based on $TERM and what the
|
335
|
+
console is connected to.
|
336
|
+
$SYSTEMD_URLIFY :: The value must be a boolean. Controls whether clickable links should be generated in the output for
|
337
|
+
terminal emulators supporting this. This can be specified to override the decision that systemd makes
|
338
|
+
based on $TERM and other conditions.
|
339
|
+
"""
|
340
|
+
import fcntl
|
341
|
+
import os.path
|
342
|
+
import queue # noqa
|
343
|
+
import subprocess
|
344
|
+
import time
|
345
|
+
import typing as ta
|
346
|
+
|
347
|
+
from omlish.lite.cached import cached_nullary
|
348
|
+
from omlish.lite.check import check_not_none
|
349
|
+
from omlish.lite.logs import log
|
350
|
+
from omlish.lite.subprocesses import subprocess_shell_wrap_exec
|
351
|
+
|
352
|
+
from ..threadworker import ThreadWorker
|
353
|
+
from .messages import JournalctlMessage # noqa
|
354
|
+
from .messages import JournalctlMessageBuilder
|
355
|
+
|
356
|
+
|
357
|
+
class JournalctlTailerWorker(ThreadWorker):
|
358
|
+
DEFAULT_CMD: ta.ClassVar[ta.Sequence[str]] = ['journalctl']
|
359
|
+
|
360
|
+
def __init__(
|
361
|
+
self,
|
362
|
+
output, # type: queue.Queue[ta.Sequence[JournalctlMessage]]
|
363
|
+
*,
|
364
|
+
since: ta.Optional[str] = None,
|
365
|
+
after_cursor: ta.Optional[str] = None,
|
366
|
+
|
367
|
+
cmd: ta.Optional[ta.Sequence[str]] = None,
|
368
|
+
shell_wrap: bool = False,
|
369
|
+
|
370
|
+
read_size: int = 0x4000,
|
371
|
+
sleep_s: float = 1.,
|
372
|
+
|
373
|
+
**kwargs: ta.Any,
|
374
|
+
) -> None:
|
375
|
+
super().__init__(**kwargs)
|
376
|
+
|
377
|
+
self._output = output
|
378
|
+
|
379
|
+
self._since = since
|
380
|
+
self._after_cursor = after_cursor
|
381
|
+
|
382
|
+
self._cmd = cmd or self.DEFAULT_CMD
|
383
|
+
self._shell_wrap = shell_wrap
|
384
|
+
|
385
|
+
self._read_size = read_size
|
386
|
+
self._sleep_s = sleep_s
|
387
|
+
|
388
|
+
self._mb = JournalctlMessageBuilder()
|
389
|
+
|
390
|
+
self._proc: ta.Optional[subprocess.Popen] = None
|
391
|
+
|
392
|
+
@cached_nullary
|
393
|
+
def _full_cmd(self) -> ta.Sequence[str]:
|
394
|
+
cmd = [
|
395
|
+
*self._cmd,
|
396
|
+
'--output', 'json',
|
397
|
+
'--show-cursor',
|
398
|
+
'--follow',
|
399
|
+
]
|
400
|
+
|
401
|
+
if self._since is not None:
|
402
|
+
cmd.extend(['--since', self._since])
|
403
|
+
|
404
|
+
if self._after_cursor is not None:
|
405
|
+
cmd.extend(['--after-cursor', self._after_cursor])
|
406
|
+
|
407
|
+
if self._shell_wrap:
|
408
|
+
cmd = list(subprocess_shell_wrap_exec(*cmd))
|
409
|
+
|
410
|
+
return cmd
|
411
|
+
|
412
|
+
def _run(self) -> None:
|
413
|
+
with subprocess.Popen(
|
414
|
+
self._full_cmd(),
|
415
|
+
stdout=subprocess.PIPE,
|
416
|
+
) as self._proc:
|
417
|
+
stdout = check_not_none(self._proc.stdout)
|
418
|
+
|
419
|
+
fd = stdout.fileno()
|
420
|
+
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
421
|
+
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
|
422
|
+
|
423
|
+
while True:
|
424
|
+
if not self._heartbeat():
|
425
|
+
return
|
426
|
+
|
427
|
+
while stdout.readable():
|
428
|
+
if not self._heartbeat():
|
429
|
+
return
|
430
|
+
|
431
|
+
buf = stdout.read(self._read_size)
|
432
|
+
if not buf:
|
433
|
+
log.debug('Journalctl empty read')
|
434
|
+
break
|
435
|
+
|
436
|
+
log.debug('Journalctl read buffer: %r', buf)
|
437
|
+
msgs = self._mb.feed(buf)
|
438
|
+
if msgs:
|
439
|
+
while True:
|
440
|
+
try:
|
441
|
+
self._output.put(msgs, timeout=1.)
|
442
|
+
except queue.Full:
|
443
|
+
if not self._heartbeat():
|
444
|
+
return
|
445
|
+
else:
|
446
|
+
break
|
447
|
+
|
448
|
+
if self._proc.poll() is not None:
|
449
|
+
log.critical('Journalctl process terminated')
|
450
|
+
return
|
451
|
+
|
452
|
+
log.debug('Journalctl readable')
|
453
|
+
time.sleep(self._sleep_s)
|