Add "--log-file-format" flag for customizing the log message format (#658).
This commit is contained in:
parent
01811e03ba
commit
7e6bee84b0
6 changed files with 85 additions and 9 deletions
3
NEWS
3
NEWS
|
@ -7,6 +7,9 @@
|
||||||
https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#archive-naming
|
https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#archive-naming
|
||||||
* #479, #588: The "prefix" options have been deprecated in favor of the new "archive_name_format"
|
* #479, #588: The "prefix" options have been deprecated in favor of the new "archive_name_format"
|
||||||
auto-matching behavior and the "match_archives" option.
|
auto-matching behavior and the "match_archives" option.
|
||||||
|
* #658: Add "--log-file-format" flag for customizing the log message format. See the documentation
|
||||||
|
for more information:
|
||||||
|
https://torsion.org/borgmatic/docs/how-to/inspect-your-backups/#logging-to-file
|
||||||
* #662: Fix regression in which the "check_repositories" option failed to match repositories.
|
* #662: Fix regression in which the "check_repositories" option failed to match repositories.
|
||||||
* #663: Fix regression in which the "transfer" action produced a traceback.
|
* #663: Fix regression in which the "transfer" action produced a traceback.
|
||||||
* Add spellchecking of source code during test runs.
|
* Add spellchecking of source code during test runs.
|
||||||
|
|
|
@ -178,10 +178,12 @@ def make_parsers():
|
||||||
help='Log verbose progress to monitoring integrations that support logging (from only errors to very verbose: -1, 0, 1, or 2)',
|
help='Log verbose progress to monitoring integrations that support logging (from only errors to very verbose: -1, 0, 1, or 2)',
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--log-file',
|
'--log-file', type=str, help='Write log messages to this file instead of syslog',
|
||||||
|
)
|
||||||
|
global_group.add_argument(
|
||||||
|
'--log-file-format',
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
help='Log format string used for log messages written to the log file',
|
||||||
help='Write log messages to this file instead of syslog',
|
|
||||||
)
|
)
|
||||||
global_group.add_argument(
|
global_group.add_argument(
|
||||||
'--override',
|
'--override',
|
||||||
|
|
|
@ -700,6 +700,7 @@ def main(): # pragma: no cover
|
||||||
verbosity_to_log_level(global_arguments.log_file_verbosity),
|
verbosity_to_log_level(global_arguments.log_file_verbosity),
|
||||||
verbosity_to_log_level(global_arguments.monitoring_verbosity),
|
verbosity_to_log_level(global_arguments.monitoring_verbosity),
|
||||||
global_arguments.log_file,
|
global_arguments.log_file,
|
||||||
|
global_arguments.log_file_format,
|
||||||
)
|
)
|
||||||
except (FileNotFoundError, PermissionError) as error:
|
except (FileNotFoundError, PermissionError) as error:
|
||||||
configure_logging(logging.CRITICAL)
|
configure_logging(logging.CRITICAL)
|
||||||
|
|
|
@ -156,6 +156,7 @@ def configure_logging(
|
||||||
log_file_log_level=None,
|
log_file_log_level=None,
|
||||||
monitoring_log_level=None,
|
monitoring_log_level=None,
|
||||||
log_file=None,
|
log_file=None,
|
||||||
|
log_file_format=None,
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
Configure logging to go to both the console and (syslog or log file). Use the given log levels,
|
Configure logging to go to both the console and (syslog or log file). Use the given log levels,
|
||||||
|
@ -200,12 +201,18 @@ def configure_logging(
|
||||||
|
|
||||||
if syslog_path and not interactive_console():
|
if syslog_path and not interactive_console():
|
||||||
syslog_handler = logging.handlers.SysLogHandler(address=syslog_path)
|
syslog_handler = logging.handlers.SysLogHandler(address=syslog_path)
|
||||||
syslog_handler.setFormatter(logging.Formatter('borgmatic: %(levelname)s %(message)s'))
|
syslog_handler.setFormatter(
|
||||||
|
logging.Formatter('borgmatic: {levelname} {message}', style='{') # noqa: FS003
|
||||||
|
)
|
||||||
syslog_handler.setLevel(syslog_log_level)
|
syslog_handler.setLevel(syslog_log_level)
|
||||||
handlers = (console_handler, syslog_handler)
|
handlers = (console_handler, syslog_handler)
|
||||||
elif log_file:
|
elif log_file:
|
||||||
file_handler = logging.handlers.WatchedFileHandler(log_file)
|
file_handler = logging.handlers.WatchedFileHandler(log_file)
|
||||||
file_handler.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s'))
|
file_handler.setFormatter(
|
||||||
|
logging.Formatter(
|
||||||
|
log_file_format or '[{asctime}] {levelname}: {message}', style='{' # noqa: FS003
|
||||||
|
)
|
||||||
|
)
|
||||||
file_handler.setLevel(log_file_log_level)
|
file_handler.setLevel(log_file_log_level)
|
||||||
handlers = (console_handler, file_handler)
|
handlers = (console_handler, file_handler)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -154,5 +154,39 @@ borgmatic --log-file /path/to/file.log
|
||||||
|
|
||||||
Note that if you use the `--log-file` flag, you are responsible for rotating
|
Note that if you use the `--log-file` flag, you are responsible for rotating
|
||||||
the log file so it doesn't grow too large, for example with
|
the log file so it doesn't grow too large, for example with
|
||||||
[logrotate](https://wiki.archlinux.org/index.php/Logrotate). Also, there is a
|
[logrotate](https://wiki.archlinux.org/index.php/Logrotate).
|
||||||
`--log-file-verbosity` flag to customize the log file's log level.
|
|
||||||
|
You can the `--log-file-verbosity` flag to customize the log file's log level:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
borgmatic --log-file /path/to/file.log --log-file-verbosity 2
|
||||||
|
```
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in borgmatic version 1.7.11</span>
|
||||||
|
Use the `--log-file-format` flag to override the default log message format.
|
||||||
|
This format string can contain a series of named placeholders wrapped in curly
|
||||||
|
brackets. For instance, the default log format is: `[{asctime}] {levelname}:
|
||||||
|
{message}`. This means each log message is recorded as the log time (in square
|
||||||
|
brackets), a logging level name, a colon, and the actual log message.
|
||||||
|
|
||||||
|
So if you just want each log message to get logged *without* a timestamp or a
|
||||||
|
logging level name:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
borgmatic --log-file /path/to/file.log --log-file-format "{message}"
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is a list of available placeholders:
|
||||||
|
|
||||||
|
* `{asctime}`: time the log message was created
|
||||||
|
* `{levelname}`: level of the log message (`INFO`, `DEBUG`, etc.)
|
||||||
|
* `{lineno}`: line number in the source file where the log message originated
|
||||||
|
* `{message}`: actual log message
|
||||||
|
* `{pathname}`: path of the source file where the log message originated
|
||||||
|
|
||||||
|
See the [Python logging
|
||||||
|
documentation](https://docs.python.org/3/library/logging.html#logrecord-attributes)
|
||||||
|
for additional placeholders.
|
||||||
|
|
||||||
|
Note that this `--log-file-format` flg only applies to the specified
|
||||||
|
`--log-file` and not to syslog or other logging.
|
||||||
|
|
|
@ -285,7 +285,7 @@ def test_configure_logging_skips_syslog_if_interactive_console():
|
||||||
module.configure_logging(console_log_level=logging.INFO)
|
module.configure_logging(console_log_level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_logging_to_logfile_instead_of_syslog():
|
def test_configure_logging_to_log_file_instead_of_syslog():
|
||||||
flexmock(module).should_receive('add_custom_log_levels')
|
flexmock(module).should_receive('add_custom_log_levels')
|
||||||
flexmock(module.logging).ANSWER = module.ANSWER
|
flexmock(module.logging).ANSWER = module.ANSWER
|
||||||
flexmock(module).should_receive('Multi_stream_handler').and_return(
|
flexmock(module).should_receive('Multi_stream_handler').and_return(
|
||||||
|
@ -309,7 +309,36 @@ def test_configure_logging_to_logfile_instead_of_syslog():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_configure_logging_skips_logfile_if_argument_is_none():
|
def test_configure_logging_to_log_file_formats_with_custom_log_format():
|
||||||
|
flexmock(module).should_receive('add_custom_log_levels')
|
||||||
|
flexmock(module.logging).ANSWER = module.ANSWER
|
||||||
|
flexmock(module.logging).should_receive('Formatter').with_args(
|
||||||
|
'{message}', style='{' # noqa: FS003
|
||||||
|
).once()
|
||||||
|
flexmock(module).should_receive('Multi_stream_handler').and_return(
|
||||||
|
flexmock(setFormatter=lambda formatter: None, setLevel=lambda level: None)
|
||||||
|
)
|
||||||
|
|
||||||
|
flexmock(module).should_receive('interactive_console').and_return(False)
|
||||||
|
flexmock(module.logging).should_receive('basicConfig').with_args(
|
||||||
|
level=logging.DEBUG, handlers=tuple
|
||||||
|
)
|
||||||
|
flexmock(module.os.path).should_receive('exists').with_args('/dev/log').and_return(True)
|
||||||
|
flexmock(module.logging.handlers).should_receive('SysLogHandler').never()
|
||||||
|
file_handler = logging.handlers.WatchedFileHandler('/tmp/logfile')
|
||||||
|
flexmock(module.logging.handlers).should_receive('WatchedFileHandler').with_args(
|
||||||
|
'/tmp/logfile'
|
||||||
|
).and_return(file_handler).once()
|
||||||
|
|
||||||
|
module.configure_logging(
|
||||||
|
console_log_level=logging.INFO,
|
||||||
|
log_file_log_level=logging.DEBUG,
|
||||||
|
log_file='/tmp/logfile',
|
||||||
|
log_file_format='{message}', # noqa: FS003
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_configure_logging_skips_log_file_if_argument_is_none():
|
||||||
flexmock(module).should_receive('add_custom_log_levels')
|
flexmock(module).should_receive('add_custom_log_levels')
|
||||||
flexmock(module.logging).ANSWER = module.ANSWER
|
flexmock(module.logging).ANSWER = module.ANSWER
|
||||||
flexmock(module).should_receive('Multi_stream_handler').and_return(
|
flexmock(module).should_receive('Multi_stream_handler').and_return(
|
||||||
|
|
Loading…
Reference in a new issue