Introduced new parameters for logging within fail2ban-server;

Usage `logtarget = target[facility=..., datetime=on|off, format="..."]`:
  - `facility` - specify syslog facility (default `daemon`, see https://docs.python.org/2/library/logging.handlers.html#sysloghandler
     for the list of facilities);
  - `datetime` - add date-time to the message (default on, ignored if `format` specified);
  - `format` - specify own format how it will be logged, for example for short-log into STDOUT:
      `fail2ban-server -f --logtarget 'stdout[format="%(relativeCreated)5d | %(message)s"]' start`;
Closes gh-1980
pull/1989/head
sebres 2017-12-05 18:54:21 +01:00
parent de97dedba0
commit 1bf6636446
2 changed files with 20 additions and 6 deletions

View File

@ -37,7 +37,7 @@ from .filter import FileFilter, JournalFilter
from .transmitter import Transmitter from .transmitter import Transmitter
from .asyncserver import AsyncServer, AsyncServerException from .asyncserver import AsyncServer, AsyncServerException
from .. import version from .. import version
from ..helpers import getLogger, str2LogLevel, getVerbosityFormat, excepthook from ..helpers import getLogger, extractOptions, str2LogLevel, getVerbosityFormat, excepthook
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = getLogger(__name__) logSys = getLogger(__name__)
@ -547,6 +547,7 @@ class Server:
def setLogTarget(self, target): def setLogTarget(self, target):
# check reserved targets in uppercase, don't change target, because it can be file: # check reserved targets in uppercase, don't change target, because it can be file:
target, logOptions = extractOptions(target)
systarget = target.upper() systarget = target.upper()
with self.__loggingLock: with self.__loggingLock:
# don't set new handlers if already the same # don't set new handlers if already the same
@ -559,7 +560,12 @@ class Server:
# set a format which is simpler for console use # set a format which is simpler for console use
fmt = "%(name)-24s[%(process)d]: %(levelname)-7s %(message)s" fmt = "%(name)-24s[%(process)d]: %(levelname)-7s %(message)s"
if systarget == "SYSLOG": if systarget == "SYSLOG":
facility = logging.handlers.SysLogHandler.LOG_DAEMON facility = logOptions.get('facility', 'DAEMON').upper()
try:
facility = getattr(logging.handlers.SysLogHandler, 'LOG_' + facility)
except AttributeError: # pragma: no cover
logSys.error("Unable to set facility %r, using 'DAEMON'", logOptions.get('facility'))
facility = logging.handlers.SysLogHandler.LOG_DAEMON
if self.__syslogSocket == "auto": if self.__syslogSocket == "auto":
import platform import platform
self.__syslogSocket = self.__autoSyslogSocketPaths.get( self.__syslogSocket = self.__autoSyslogSocketPaths.get(
@ -610,9 +616,16 @@ class Server:
if self.__verbose is None: if self.__verbose is None:
self.__verbose = logging.DEBUG - logger.getEffectiveLevel() + 1 self.__verbose = logging.DEBUG - logger.getEffectiveLevel() + 1
# If handler don't already add date to the message: # If handler don't already add date to the message:
addtime = systarget not in ("SYSLOG", "SYSOUT") addtime = logOptions.get('datetime')
if addtime is not None:
addtime = addtime in ('1', 'on', 'true', 'yes')
else:
addtime = systarget not in ("SYSLOG", "SYSOUT")
# If log-format is redefined in options:
if logOptions.get('format', '') != '':
fmt = logOptions.get('format')
# verbose log-format: # verbose log-format:
if self.__verbose is not None and self.__verbose > 2: # pragma: no cover elif self.__verbose is not None and self.__verbose > 2: # pragma: no cover
fmt = getVerbosityFormat(self.__verbose-1, fmt = getVerbosityFormat(self.__verbose-1,
addtime=addtime) addtime=addtime)
elif addtime: elif addtime:

View File

@ -171,7 +171,7 @@ def _start_params(tmp, use_stock=False, use_stock_cfg=None,
_write_file(pjoin(cfg, "fail2ban.conf"), "w", _write_file(pjoin(cfg, "fail2ban.conf"), "w",
"[Definition]", "[Definition]",
"loglevel = INFO", "loglevel = INFO",
"logtarget = " + logtarget, "logtarget = " + logtarget.replace('%', '%%'),
"syslogsocket = auto", "syslogsocket = auto",
"socket = " + pjoin(tmp, "f2b.sock"), "socket = " + pjoin(tmp, "f2b.sock"),
"pidfile = " + pjoin(tmp, "f2b.pid"), "pidfile = " + pjoin(tmp, "f2b.pid"),
@ -735,7 +735,8 @@ class Fail2banServerTest(Fail2banClientServerBase):
def testKillAfterStart(self, tmp): def testKillAfterStart(self, tmp):
try: try:
# to prevent fork of test-cases process, start server in background via command: # to prevent fork of test-cases process, start server in background via command:
startparams = _start_params(tmp, logtarget=pjoin(tmp, "f2b.log")) startparams = _start_params(tmp, logtarget=pjoin(tmp,
'f2b.log[format="SRV: %(relativeCreated)3d | %(message)s", datetime=off]'))
# start (in new process, using the same python version): # start (in new process, using the same python version):
cmd = (sys.executable, pjoin(BIN, SERVER)) cmd = (sys.executable, pjoin(BIN, SERVER))
logSys.debug('Start %s ...', cmd) logSys.debug('Start %s ...', cmd)