journal.py revision 9015fa646e04fc3cb180bea24c33d34edbb48ed7
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# -*- Mode: python; coding:utf-8; indent-tabs-mode: nil -*- */
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# This file is part of systemd.
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# Copyright 2012 David Strauss <david@davidstrauss.net>
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# Copyright 2012 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# Copyright 2012 Marti Raudsepp <marti@juffo.org>
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# systemd is free software; you can redistribute it and/or modify it
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# under the terms of the GNU Lesser General Public License as published by
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# the Free Software Foundation; either version 2.1 of the License, or
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# (at your option) any later version.
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# systemd is distributed in the hope that it will be useful, but
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# WITHOUT ANY WARRANTY; without even the implied warranty of
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# Lesser General Public License for more details.
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering# You should have received a copy of the GNU Lesser General Public License
d2134abdd5a21bb7e4b307f403d890901628fcf9Lennart Poettering# along with systemd; If not, see <http://www.gnu.org/licenses/>.
907dd1953b7517534d646f5b2777780020c896e2Kay Sieversfrom syslog import (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering return field.encode('utf-8') + b'=' + value
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering CODE_FILE=None, CODE_LINE=None, CODE_FUNC=None,
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering r"""Send a message to the journal.
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> journal.send('Hello world')
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> journal.send('Hello, again, world', FIELD2='Greetings!')
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> journal.send('Binary message', BINARY=b'\xde\xad\xbe\xef')
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering Value of the MESSAGE argument will be used for the MESSAGE=
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering field. MESSAGE must be a string and will be sent as UTF-8 to
1c7dde3e475978c569a982d65fd86d4b4e3caad8Bastien Nocera MESSAGE_ID can be given to uniquely identify the type of
1c7dde3e475978c569a982d65fd86d4b4e3caad8Bastien Nocera message. It must be a string or a uuid.UUID object.
1c7dde3e475978c569a982d65fd86d4b4e3caad8Bastien Nocera CODE_LINE, CODE_FILE, and CODE_FUNC can be specified to
e9da3678fcfc774b325dc1eaa054d0e00028a1fcLennart Poettering identify the caller. Unless at least on of the three is given,
e9da3678fcfc774b325dc1eaa054d0e00028a1fcLennart Poettering values are extracted from the stack frame of the caller of
e9da3678fcfc774b325dc1eaa054d0e00028a1fcLennart Poettering send(). CODE_FILE and CODE_FUNC must be strings, CODE_LINE
f975e971accc4d50c73ae53167db3df7a7099cf2Lennart Poettering must be an integer.
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering Additional fields for the journal entry can only be specified
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering as keyword arguments. The payload can be either a string or
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering bytes. A string will be sent as UTF-8, and bytes will be sent
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering as-is to the journal.
9a60da2834074d970ca063c210fe9d2f05c70532Thierry Reding Other useful fields include PRIORITY, SYSLOG_FACILITY,
9a60da2834074d970ca063c210fe9d2f05c70532Thierry Reding SYSLOG_IDENTIFIER, SYSLOG_PID.
9a60da2834074d970ca063c210fe9d2f05c70532Thierry Reding if MESSAGE_ID is not None:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering id = getattr(MESSAGE_ID, 'hex', MESSAGE_ID)
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering if CODE_LINE == CODE_FILE == CODE_FUNC == None:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering if CODE_FILE is not None:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering if CODE_LINE is not None:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering args.append('CODE_LINE={:d}'.format(CODE_LINE))
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering if CODE_FUNC is not None:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering args.extend(_make_line(key, val) for key, val in kwargs.items())
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poetteringdef stream(identifier, priority=LOG_DEBUG, level_prefix=False):
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering r"""Return a file object wrapping a stream to journal.
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering Log messages written to this file as simple newline sepearted
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering text strings are written to the journal.
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering The file will be line buffered, so messages are actually sent
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering after a newline character is written.
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering >>> stream = journal.stream('myapp')
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering <open file '<fdopen>', mode 'w' at 0x...>
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering >>> stream.write('message...\n')
be1a67d9d63bfdd4a5f8ba9cfc804030f10f5833Lennart Poettering will produce the following message in the journal::
8745297f9853c4a17bac69e1b7e652fe81bc1940Lennart Poettering SYSLOG_IDENTIFIER=myapp
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering MESSAGE=message...
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering Using the interface with print might be more convinient:
9b85fc6a89386582bfe792dba881800b0a093839Gustavo Sverzut Barbieri >>> from __future__ import print_function
9b85fc6a89386582bfe792dba881800b0a093839Gustavo Sverzut Barbieri >>> print('message...', file=stream)
9b85fc6a89386582bfe792dba881800b0a093839Gustavo Sverzut Barbieri priority is the syslog priority, one of `LOG_EMERG`,
9b85fc6a89386582bfe792dba881800b0a093839Gustavo Sverzut Barbieri `LOG_ALERT`, `LOG_CRIT`, `LOG_ERR`, `LOG_WARNING`,
9b85fc6a89386582bfe792dba881800b0a093839Gustavo Sverzut Barbieri `LOG_NOTICE`, `LOG_INFO`, `LOG_DEBUG`.
139be57d9441b5c890e1e4ee69e15aad03276fdeLennart Poettering level_prefix is a boolean. If true, kernel-style log priority
139be57d9441b5c890e1e4ee69e15aad03276fdeLennart Poettering level prefixes (such as '<1>') are interpreted. See
139be57d9441b5c890e1e4ee69e15aad03276fdeLennart Poettering sd-daemon(3) for more information.
85f19d825e7504676f3a80c78c1d9a7ec35a3b3fMichael Biebl fd = stream_fd(identifier, priority, level_prefix)
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering """Journal handler class for the Python logging framework.
85f19d825e7504676f3a80c78c1d9a7ec35a3b3fMichael Biebl Please see the Python logging module documentation for an
85f19d825e7504676f3a80c78c1d9a7ec35a3b3fMichael Biebl overview: http://docs.python.org/library/logging.html.
b237ef2cfac7ab0b33170809e8cb64628606207dTollef Fog Heen To create a custom logger whose messages go only to journal:
d1ab0ca07372649dad70a0348d75e394f254e1b6Lennart Poettering >>> log = logging.getLogger('custom_logger_name')
309c2a2ce95aae54879b4957d113f03608530c15Lennart Poettering >>> log.propagate = False
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> log.addHandler(journal.JournalHandler())
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> log.warn("Some message: %s", detail)
83bda35801aa3d7ed180ec374a4bcdfe9dc1a8e4Lennart Poettering Note that by default, message levels `INFO` and `DEBUG` are
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering ignored by the logging framework. To enable those log levels:
47be870bd83fb3719dffc3ee9348a409ab762a14Lennart Poettering >>> log.setLevel(logging.DEBUG)
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering To attach journal MESSAGE_ID, an extra field is supported:
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering >>> import uuid
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering >>> mid = uuid.UUID('0123456789ABCDEF0123456789ABCDEF')
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering >>> log.warn("Message with ID", extra={'MESSAGE_ID': mid})
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering To redirect all logging messages to journal regardless of where
591622d7efbc828f00f190d91b6608148b967ff5Lennart Poettering they come from, attach it to the root logger:
56cf987fe74270bde4e16c7ec9e0414a9030723bDaniel J Walsh >>> logging.root.addHandler(journal.JournalHandler())
56cf987fe74270bde4e16c7ec9e0414a9030723bDaniel J Walsh For more complex configurations when using `dictConfig` or
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering `fileConfig`, specify `systemd.journal.JournalHandler` as the
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering handler class. Only standard handler configuration options
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering are supported: `level`, `formatter`, `filters`.
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering The following journal fields will be sent:
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering `MESSAGE`, `PRIORITY`, `THREAD_NAME`, `CODE_FILE`, `CODE_LINE`,
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering `CODE_FUNC`, `LOGGER` (name as supplied to getLogger call),
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering `MESSAGE_ID` (optional, see above).
807e17f05e217b474af39503efb9503d81b12596Lennart Poettering """Write record as journal event.
0213c3f8102bdc934c629d11a44ca0b408762287Lennart Poettering MESSAGE is taken from the message provided by the
0213c3f8102bdc934c629d11a44ca0b408762287Lennart Poettering user, and PRIORITY, LOGGER, THREAD_NAME,
0213c3f8102bdc934c629d11a44ca0b408762287Lennart Poettering CODE_{FILE,LINE,FUNC} fields are appended
5b6319dceedd81f3f1ce7eb70ea5defaef43bcecLennart Poettering automatically. In addition, record.MESSAGE_ID will be
5b6319dceedd81f3f1ce7eb70ea5defaef43bcecLennart Poettering used if present.
5b6319dceedd81f3f1ce7eb70ea5defaef43bcecLennart Poettering mid = getattr(record, 'MESSAGE_ID', None)
0213c3f8102bdc934c629d11a44ca0b408762287Lennart Poettering """Map logging levels to journald priorities.
5b6319dceedd81f3f1ce7eb70ea5defaef43bcecLennart Poettering Since Python log level numbers are "sparse", we have
5b6319dceedd81f3f1ce7eb70ea5defaef43bcecLennart Poettering to map numbers in between the standard levels too.