mirror of https://github.com/fail2ban/fail2ban
				
				
				
			Merge pull request #581 from kwirk/datetemplate-regroupdict
ENH: Full regex for datepattern, utilising modified Python `_strptime`pull/592/head
						commit
						4aa50684ab
					
				| 
						 | 
				
			
			@ -43,28 +43,24 @@ class DateDetector:
 | 
			
		|||
		self.__known_names.add(name)
 | 
			
		||||
		self.__templates.append(template)
 | 
			
		||||
	
 | 
			
		||||
	def appendTemplate(self, template, **kwargs):
 | 
			
		||||
	def appendTemplate(self, template):
 | 
			
		||||
		if isinstance(template, str):
 | 
			
		||||
			template = DatePatternRegex(template, **kwargs)
 | 
			
		||||
		else:
 | 
			
		||||
			assert not kwargs
 | 
			
		||||
			template = DatePatternRegex(template)
 | 
			
		||||
		DateDetector._appendTemplate(self, template)
 | 
			
		||||
 | 
			
		||||
	def addDefaultTemplate(self):
 | 
			
		||||
		self.__lock.acquire()
 | 
			
		||||
		try:
 | 
			
		||||
			if sys.version_info >= (2, 5): # because of '%.f'
 | 
			
		||||
				# asctime with subsecond: Sun Jan 23 21:59:59.011 2005 
 | 
			
		||||
				self.appendTemplate("%a %b %d %H:%M:%S.%f %Y")
 | 
			
		||||
			# asctime with subsecond: Sun Jan 23 21:59:59.011 2005 
 | 
			
		||||
			self.appendTemplate("%a %b %d %H:%M:%S\.%f %Y")
 | 
			
		||||
			# asctime: Sun Jan 23 21:59:59 2005 
 | 
			
		||||
			self.appendTemplate("%a %b %d %H:%M:%S %Y")
 | 
			
		||||
			# asctime without year: Sun Jan 23 21:59:59 
 | 
			
		||||
			self.appendTemplate("%a %b %d %H:%M:%S")
 | 
			
		||||
			# standard: Jan 23 21:59:59 
 | 
			
		||||
			self.appendTemplate("%b %d %H:%M:%S")
 | 
			
		||||
			if sys.version_info >= (2, 5): # because of '%.f'
 | 
			
		||||
				# proftpd date: 2005-01-23 21:59:59,333
 | 
			
		||||
				self.appendTemplate("%Y-%m-%d %H:%M:%S,%f")
 | 
			
		||||
			# proftpd date: 2005-01-23 21:59:59,333
 | 
			
		||||
			self.appendTemplate("%Y-%m-%d %H:%M:%S,%f")
 | 
			
		||||
			# simple date: 2005-01-23 21:59:59 
 | 
			
		||||
			self.appendTemplate("%Y-%m-%d %H:%M:%S")
 | 
			
		||||
			# simple date: 2005/01/23 21:59:59 
 | 
			
		||||
| 
						 | 
				
			
			@ -81,10 +77,9 @@ class DateDetector:
 | 
			
		|||
			# CPanel 05/20/2008:01:57:39
 | 
			
		||||
			self.appendTemplate("%m/%d/%Y:%H:%M:%S")
 | 
			
		||||
			# custom for syslog-ng 2006.12.21 06:43:20
 | 
			
		||||
			self.appendTemplate("%Y.%m.%d %H:%M:%S")
 | 
			
		||||
			if sys.version_info >= (2, 5): # because of '%.f'
 | 
			
		||||
				# named 26-Jul-2007 15:20:52.252 
 | 
			
		||||
				self.appendTemplate("%d-%b-%Y %H:%M:%S.%f")
 | 
			
		||||
			self.appendTemplate("%Y\.%m\.%d %H:%M:%S")
 | 
			
		||||
			# named 26-Jul-2007 15:20:52.252 
 | 
			
		||||
			self.appendTemplate("%d-%b-%Y %H:%M:%S\.%f")
 | 
			
		||||
			# roundcube 26-Jul-2007 15:20:52 +0200
 | 
			
		||||
			self.appendTemplate("%d-%b-%Y %H:%M:%S %z")
 | 
			
		||||
			# 26-Jul-2007 15:20:52
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +87,7 @@ class DateDetector:
 | 
			
		|||
			# 17-07-2008 17:23:25
 | 
			
		||||
			self.appendTemplate("%d-%m-%Y %H:%M:%S")
 | 
			
		||||
			# 01-27-2012 16:22:44.252
 | 
			
		||||
			self.appendTemplate("%m-%d-%Y %H:%M:%S.%f")
 | 
			
		||||
			self.appendTemplate("%m-%d-%Y %H:%M:%S\.%f")
 | 
			
		||||
			# TAI64N
 | 
			
		||||
			template = DateTai64n()
 | 
			
		||||
			template.setName("TAI64N")
 | 
			
		||||
| 
						 | 
				
			
			@ -106,15 +101,15 @@ class DateDetector:
 | 
			
		|||
			template.setName("ISO 8601")
 | 
			
		||||
			self.appendTemplate(template)
 | 
			
		||||
			# Only time information in the log
 | 
			
		||||
			self.appendTemplate("%H:%M:%S", anchor=True)
 | 
			
		||||
			self.appendTemplate("^%H:%M:%S")
 | 
			
		||||
			# <09/16/08@05:03:30>
 | 
			
		||||
			self.appendTemplate("<%m/%d/%y@%H:%M:%S>", anchor=True)
 | 
			
		||||
			self.appendTemplate("^<%m/%d/%y@%H:%M:%S>")
 | 
			
		||||
			# MySQL: 130322 11:46:11
 | 
			
		||||
			self.appendTemplate("%y%m%d %H:%M:%S", anchor=True)
 | 
			
		||||
			self.appendTemplate("^%y%m%d  ?%H:%M:%S")
 | 
			
		||||
			# Apache Tomcat
 | 
			
		||||
			self.appendTemplate("%b %d, %Y %I:%M:%S %p")
 | 
			
		||||
			# ASSP: Apr-27-13 02:33:06
 | 
			
		||||
			self.appendTemplate("%b-%d-%y %H:%M:%S", anchor=True)
 | 
			
		||||
			self.appendTemplate("^%b-%d-%y %H:%M:%S")
 | 
			
		||||
		finally:
 | 
			
		||||
			self.__lock.release()
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,11 +31,12 @@ from datetime import timedelta
 | 
			
		|||
 | 
			
		||||
from .mytime import MyTime
 | 
			
		||||
from . import iso8601
 | 
			
		||||
from .strptime import reGroupDictStrptime, timeRE
 | 
			
		||||
 | 
			
		||||
logSys = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DateTemplate:
 | 
			
		||||
class DateTemplate(object):
 | 
			
		||||
	
 | 
			
		||||
	def __init__(self):
 | 
			
		||||
		self.__name = ""
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +56,7 @@ class DateTemplate:
 | 
			
		|||
		if (wordBegin and not re.search(r'^\^', regex)):
 | 
			
		||||
			regex = r'\b' + regex
 | 
			
		||||
		self.__regex = regex
 | 
			
		||||
		self.__cRegex = re.compile(regex, re.UNICODE)
 | 
			
		||||
		self.__cRegex = re.compile(regex, re.UNICODE | re.IGNORECASE)
 | 
			
		||||
		
 | 
			
		||||
	def getRegex(self):
 | 
			
		||||
		return self.__regex
 | 
			
		||||
| 
						 | 
				
			
			@ -230,44 +231,32 @@ except ValueError:
 | 
			
		|||
	DateStrptime._z = False
 | 
			
		||||
 | 
			
		||||
class DatePatternRegex(DateStrptime):
 | 
			
		||||
	_reEscape = r"([\\.^$*+?\(\){}\[\]|])"
 | 
			
		||||
	_patternRE = r"%(%|[aAbBdfHIjmMpSUwWyYz])"
 | 
			
		||||
	_patternRE = r"%%(%%|[%s])" % "".join(timeRE.keys())
 | 
			
		||||
	_patternName = {
 | 
			
		||||
		'a': "DAY", 'A': "DAYNAME", 'b': "MON", 'B': "MONTH", 'd': "Day",
 | 
			
		||||
		'H': "24hour", 'I': "12hour", 'j': "Yearday", 'm': "Month",
 | 
			
		||||
		'M': "Minute", 'p': "AMPM", 'S': "Second", 'U': "Yearweek",
 | 
			
		||||
		'w': "Weekday", 'W': "Yearweek", 'y': 'Year2', 'Y': "Year", '%': "%",
 | 
			
		||||
		'z': "Zone offset", 'f': "Microseconds" }
 | 
			
		||||
	_patternRegex = {
 | 
			
		||||
		'a': r"\w{3}", 'A': r"\w+", 'b': r"\w{3}", 'B': r"\w+",
 | 
			
		||||
		'd': r"(?:3[0-1]|[1-2]\d|[ 0]?\d)",
 | 
			
		||||
		'f': r"(?P<_f>\d{1,6})", 'H': r"(?:2[0-3]|1\d|[ 0]?\d)",
 | 
			
		||||
		'I': r"(?:1[0-2]|[ 0]?\d)",
 | 
			
		||||
		'j': r"(?:36[0-6]3[0-5]\d|[1-2]\d\d|[ 0]?\d\d|[ 0]{0,2}\d)",
 | 
			
		||||
		'm': r"(?:1[0-2]|[ 0]?[1-9])", 'M': r"[0-5]\d", 'p': r"[AP]M",
 | 
			
		||||
		'S': r"(?:6[01]|[0-5]\d)", 'U': r"(?:5[0-3]|[1-4]\d|[ 0]?\d)",
 | 
			
		||||
		'w': r"[0-6]", 'W': r"(?:5[0-3]|[ 0]?\d)", 'y': r"\d{2}",
 | 
			
		||||
		'Y': r"\d{4}",
 | 
			
		||||
		'z': r"(?P<_z>[+-]\d{4})", '%': "%"}
 | 
			
		||||
		'z': "Zone offset", 'f': "Microseconds", 'Z': "Zone name"}
 | 
			
		||||
	for key in set(timeRE) - set(_patternName): # may not have them all...
 | 
			
		||||
		_patternName[key] = "%%%s" % key
 | 
			
		||||
 | 
			
		||||
	def __init__(self, pattern=None, **kwargs):
 | 
			
		||||
		DateStrptime.__init__(self)
 | 
			
		||||
		super(DatePatternRegex, self).__init__()
 | 
			
		||||
		if pattern:
 | 
			
		||||
			self.setPattern(pattern, **kwargs)
 | 
			
		||||
 | 
			
		||||
	def setPattern(self, pattern, anchor=False, **kwargs):
 | 
			
		||||
		DateStrptime.setPattern(self, pattern.strip())
 | 
			
		||||
	def setPattern(self, pattern):
 | 
			
		||||
		super(DatePatternRegex, self).setPattern(pattern)
 | 
			
		||||
		super(DatePatternRegex, self).setName(
 | 
			
		||||
			re.sub(self._patternRE, r'%(\1)s', pattern) % self._patternName)
 | 
			
		||||
		super(DatePatternRegex, self).setRegex(
 | 
			
		||||
			re.sub(self._patternRE, r'%(\1)s', pattern) % timeRE)
 | 
			
		||||
 | 
			
		||||
		name = re.sub(self._patternRE, r'%(\1)s', pattern) % self._patternName
 | 
			
		||||
		DateStrptime.setName(self, name)
 | 
			
		||||
 | 
			
		||||
		# Custom escape as don't want to escape "%"
 | 
			
		||||
		pattern = re.sub(self._reEscape, r'\\\1', pattern)
 | 
			
		||||
		regex = re.sub(
 | 
			
		||||
			self._patternRE, r'%(\1)s', pattern) % self._patternRegex
 | 
			
		||||
		if anchor:
 | 
			
		||||
			regex = r"^" + regex
 | 
			
		||||
		DateStrptime.setRegex(self, regex, **kwargs)
 | 
			
		||||
	def getDate(self, line):
 | 
			
		||||
		dateMatch = self.matchDate(line)
 | 
			
		||||
		if dateMatch:
 | 
			
		||||
			return reGroupDictStrptime(dateMatch.groupdict()), dateMatch
 | 
			
		||||
 | 
			
		||||
	def setRegex(self, line):
 | 
			
		||||
		raise NotImplementedError("Regex derived from pattern")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -213,10 +213,7 @@ class Filter(JailThread):
 | 
			
		|||
			template.setName("TAI64N")
 | 
			
		||||
		else:
 | 
			
		||||
			template = DatePatternRegex()
 | 
			
		||||
			if pattern[0] == "^": # Special extra to enable anchor
 | 
			
		||||
				template.setPattern(pattern[1:], anchor=True)
 | 
			
		||||
			else:
 | 
			
		||||
				template.setPattern(pattern, anchor=False)
 | 
			
		||||
			template.setPattern(pattern)
 | 
			
		||||
		self.dateDetector = DateDetector()
 | 
			
		||||
		self.dateDetector.appendTemplate(template)
 | 
			
		||||
		logSys.info("Date pattern set to `%r`: `%s`" %
 | 
			
		||||
| 
						 | 
				
			
			@ -237,8 +234,6 @@ class Filter(JailThread):
 | 
			
		|||
			elif len(templates) == 1:
 | 
			
		||||
				if hasattr(templates[0], "getPattern"):
 | 
			
		||||
					pattern =  templates[0].getPattern()
 | 
			
		||||
					if templates[0].getRegex()[0] == "^":
 | 
			
		||||
						pattern = "^" + pattern
 | 
			
		||||
				else:
 | 
			
		||||
					pattern = None
 | 
			
		||||
				return pattern, templates[0].getName()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,193 @@
 | 
			
		|||
# emacs: -*- mode: python; coding: utf-8; py-indent-offset: 4; indent-tabs-mode: t -*-
 | 
			
		||||
# vi: set ft=python sts=4 ts=4 sw=4 noet :
 | 
			
		||||
 | 
			
		||||
# This file is part of Fail2Ban.
 | 
			
		||||
#
 | 
			
		||||
# Fail2Ban is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# Fail2Ban 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 General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with Fail2Ban; if not, write to the Free Software
 | 
			
		||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
import time
 | 
			
		||||
import calendar
 | 
			
		||||
import datetime
 | 
			
		||||
from _strptime import LocaleTime, TimeRE, _calc_julian_from_U_or_W
 | 
			
		||||
 | 
			
		||||
from .mytime import MyTime
 | 
			
		||||
 | 
			
		||||
locale_time = LocaleTime()
 | 
			
		||||
timeRE = TimeRE()
 | 
			
		||||
if 'z' not in timeRE: # python2.6 not present
 | 
			
		||||
	timeRE['z'] = r"(?P<z>[+-]\d{2}[0-5]\d)"
 | 
			
		||||
 | 
			
		||||
def reGroupDictStrptime(found_dict):
 | 
			
		||||
	"""This is tweaked from python built-in _strptime"""
 | 
			
		||||
 | 
			
		||||
	now = MyTime.now()
 | 
			
		||||
	year = month = day = hour = minute = None
 | 
			
		||||
	hour = minute = None
 | 
			
		||||
	second = fraction = 0
 | 
			
		||||
	tz = -1
 | 
			
		||||
	tzoffset = None
 | 
			
		||||
	# Default to -1 to signify that values not known; not critical to have,
 | 
			
		||||
	# though
 | 
			
		||||
	week_of_year = -1
 | 
			
		||||
	week_of_year_start = -1
 | 
			
		||||
	# weekday and julian defaulted to -1 so as to signal need to calculate
 | 
			
		||||
	# values
 | 
			
		||||
	weekday = julian = -1
 | 
			
		||||
	for group_key in found_dict.keys():
 | 
			
		||||
		# Directives not explicitly handled below:
 | 
			
		||||
		#   c, x, X
 | 
			
		||||
		#	  handled by making out of other directives
 | 
			
		||||
		#   U, W
 | 
			
		||||
		#	  worthless without day of the week
 | 
			
		||||
		if group_key == 'y':
 | 
			
		||||
			year = int(found_dict['y'])
 | 
			
		||||
			# Open Group specification for strptime() states that a %y
 | 
			
		||||
			#value in the range of [00, 68] is in the century 2000, while
 | 
			
		||||
			#[69,99] is in the century 1900
 | 
			
		||||
			if year <= 68:
 | 
			
		||||
				year += 2000
 | 
			
		||||
			else:
 | 
			
		||||
				year += 1900
 | 
			
		||||
		elif group_key == 'Y':
 | 
			
		||||
			year = int(found_dict['Y'])
 | 
			
		||||
		elif group_key == 'm':
 | 
			
		||||
			month = int(found_dict['m'])
 | 
			
		||||
		elif group_key == 'B':
 | 
			
		||||
			month = locale_time.f_month.index(found_dict['B'].lower())
 | 
			
		||||
		elif group_key == 'b':
 | 
			
		||||
			month = locale_time.a_month.index(found_dict['b'].lower())
 | 
			
		||||
		elif group_key == 'd':
 | 
			
		||||
			day = int(found_dict['d'])
 | 
			
		||||
		elif group_key == 'H':
 | 
			
		||||
			hour = int(found_dict['H'])
 | 
			
		||||
		elif group_key == 'I':
 | 
			
		||||
			hour = int(found_dict['I'])
 | 
			
		||||
			ampm = found_dict.get('p', '').lower()
 | 
			
		||||
			# If there was no AM/PM indicator, we'll treat this like AM
 | 
			
		||||
			if ampm in ('', locale_time.am_pm[0]):
 | 
			
		||||
				# We're in AM so the hour is correct unless we're
 | 
			
		||||
				# looking at 12 midnight.
 | 
			
		||||
				# 12 midnight == 12 AM == hour 0
 | 
			
		||||
				if hour == 12:
 | 
			
		||||
					hour = 0
 | 
			
		||||
			elif ampm == locale_time.am_pm[1]:
 | 
			
		||||
				# We're in PM so we need to add 12 to the hour unless
 | 
			
		||||
				# we're looking at 12 noon.
 | 
			
		||||
				# 12 noon == 12 PM == hour 12
 | 
			
		||||
				if hour != 12:
 | 
			
		||||
					hour += 12
 | 
			
		||||
		elif group_key == 'M':
 | 
			
		||||
			minute = int(found_dict['M'])
 | 
			
		||||
		elif group_key == 'S':
 | 
			
		||||
			second = int(found_dict['S'])
 | 
			
		||||
		elif group_key == 'f':
 | 
			
		||||
			s = found_dict['f']
 | 
			
		||||
			# Pad to always return microseconds.
 | 
			
		||||
			s += "0" * (6 - len(s))
 | 
			
		||||
			fraction = int(s)
 | 
			
		||||
		elif group_key == 'A':
 | 
			
		||||
			weekday = locale_time.f_weekday.index(found_dict['A'].lower())
 | 
			
		||||
		elif group_key == 'a':
 | 
			
		||||
			weekday = locale_time.a_weekday.index(found_dict['a'].lower())
 | 
			
		||||
		elif group_key == 'w':
 | 
			
		||||
			weekday = int(found_dict['w'])
 | 
			
		||||
			if weekday == 0:
 | 
			
		||||
				weekday = 6
 | 
			
		||||
			else:
 | 
			
		||||
				weekday -= 1
 | 
			
		||||
		elif group_key == 'j':
 | 
			
		||||
			julian = int(found_dict['j'])
 | 
			
		||||
		elif group_key in ('U', 'W'):
 | 
			
		||||
			week_of_year = int(found_dict[group_key])
 | 
			
		||||
			if group_key == 'U':
 | 
			
		||||
				# U starts week on Sunday.
 | 
			
		||||
				week_of_year_start = 6
 | 
			
		||||
			else:
 | 
			
		||||
				# W starts week on Monday.
 | 
			
		||||
				week_of_year_start = 0
 | 
			
		||||
		elif group_key == 'z':
 | 
			
		||||
			z = found_dict['z']
 | 
			
		||||
			tzoffset = int(z[1:3]) * 60 + int(z[3:5])
 | 
			
		||||
			if z.startswith("-"):
 | 
			
		||||
				tzoffset = -tzoffset
 | 
			
		||||
		elif group_key == 'Z':
 | 
			
		||||
			# Since -1 is default value only need to worry about setting tz if
 | 
			
		||||
			# it can be something other than -1.
 | 
			
		||||
			found_zone = found_dict['Z'].lower()
 | 
			
		||||
			for value, tz_values in enumerate(locale_time.timezone):
 | 
			
		||||
				if found_zone in tz_values:
 | 
			
		||||
					# Deal with bad locale setup where timezone names are the
 | 
			
		||||
					# same and yet time.daylight is true; too ambiguous to
 | 
			
		||||
					# be able to tell what timezone has daylight savings
 | 
			
		||||
					if (time.tzname[0] == time.tzname[1] and
 | 
			
		||||
					   time.daylight and found_zone not in ("utc", "gmt")):
 | 
			
		||||
						break
 | 
			
		||||
					else:
 | 
			
		||||
						tz = value
 | 
			
		||||
						break
 | 
			
		||||
 | 
			
		||||
	# Fail2Ban will assume it's this year
 | 
			
		||||
	assume_year = False
 | 
			
		||||
	if year is None:
 | 
			
		||||
		year = now.year
 | 
			
		||||
		assume_year = True
 | 
			
		||||
	# If we know the week of the year and what day of that week, we can figure
 | 
			
		||||
	# out the Julian day of the year.
 | 
			
		||||
	if julian == -1 and week_of_year != -1 and weekday != -1:
 | 
			
		||||
		week_starts_Mon = True if week_of_year_start == 0 else False
 | 
			
		||||
		julian = _calc_julian_from_U_or_W(year, week_of_year, weekday,
 | 
			
		||||
											week_starts_Mon)
 | 
			
		||||
	# Cannot pre-calculate datetime.datetime() since can change in Julian
 | 
			
		||||
	# calculation and thus could have different value for the day of the week
 | 
			
		||||
	# calculation.
 | 
			
		||||
	if julian != -1 and (month is None or day is None):
 | 
			
		||||
		datetime_result = datetime.datetime.fromordinal((julian - 1) + datetime.datetime(year, 1, 1).toordinal())
 | 
			
		||||
		year = datetime_result.year
 | 
			
		||||
		month = datetime_result.month
 | 
			
		||||
		day = datetime_result.day
 | 
			
		||||
	# Add timezone info
 | 
			
		||||
	tzname = found_dict.get("Z")
 | 
			
		||||
	if tzoffset is not None:
 | 
			
		||||
		gmtoff = tzoffset * 60
 | 
			
		||||
	else:
 | 
			
		||||
		gmtoff = None
 | 
			
		||||
 | 
			
		||||
	# Fail2Ban assume today
 | 
			
		||||
	assume_today = False
 | 
			
		||||
	if month is None and day is None:
 | 
			
		||||
		month = now.month
 | 
			
		||||
		day = now.day
 | 
			
		||||
		assume_today = True
 | 
			
		||||
 | 
			
		||||
	# Actully create date
 | 
			
		||||
	date_result =  datetime.datetime(
 | 
			
		||||
		year, month, day, hour, minute, second, fraction)
 | 
			
		||||
	if gmtoff:
 | 
			
		||||
		date_result = date_result - datetime.timedelta(seconds=gmtoff)
 | 
			
		||||
 | 
			
		||||
	if date_result > now and assume_today:
 | 
			
		||||
		# Rollover at midnight, could mean it's yesterday...
 | 
			
		||||
		date_result = date_result - datetime.timedelta(days=1)
 | 
			
		||||
	if date_result > now and assume_year:
 | 
			
		||||
		# Could be last year?
 | 
			
		||||
		# also reset month and day as it's not yesterday...
 | 
			
		||||
		date_result = date_result.replace(
 | 
			
		||||
			year=year-1, month=month, day=day)
 | 
			
		||||
 | 
			
		||||
	if gmtoff is not None:
 | 
			
		||||
		return calendar.timegm(date_result.utctimetuple())
 | 
			
		||||
	else:
 | 
			
		||||
		return time.mktime(date_result.utctimetuple())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -148,47 +148,6 @@ class DateDetectorTest(unittest.TestCase):
 | 
			
		|||
		self.assertEqual(logTime, mu)
 | 
			
		||||
		self.assertEqual(logMatch.group(), '2012/10/11 02:37:17')
 | 
			
		||||
 | 
			
		||||
	def testDateDetectorTemplateOverlap(self):
 | 
			
		||||
		patterns = [template.getPattern()
 | 
			
		||||
			for template in self.__datedetector.getTemplates()
 | 
			
		||||
			if hasattr(template, "getPattern")]
 | 
			
		||||
 | 
			
		||||
		year = 2008 # Leap year, 08 for %y can be confused with both %d and %m
 | 
			
		||||
		def iterDates(year):
 | 
			
		||||
			for month in xrange(1, 13):
 | 
			
		||||
				for day in xrange(2, calendar.monthrange(year, month)[1]+1, 9):
 | 
			
		||||
					for hour in xrange(0, 24, 6):
 | 
			
		||||
						for minute in xrange(0, 60, 15):
 | 
			
		||||
							for second in xrange(0, 60, 15): # Far enough?
 | 
			
		||||
								yield datetime.datetime(
 | 
			
		||||
									year, month, day, hour, minute, second, 300, Utc())
 | 
			
		||||
 | 
			
		||||
		overlapedTemplates = set()
 | 
			
		||||
		for date in iterDates(year):
 | 
			
		||||
			for pattern in patterns:
 | 
			
		||||
				datestr = date.strftime(pattern)
 | 
			
		||||
				datestr = re.sub(r'%f','300', datestr) # for python 2.5 where there is no %f
 | 
			
		||||
				datestrs = set([
 | 
			
		||||
					datestr,
 | 
			
		||||
					re.sub(r"(\s)0", r"\1 ", datestr),
 | 
			
		||||
					re.sub(r"(\s)0", r"\1", datestr)])
 | 
			
		||||
				for template in self.__datedetector.getTemplates():
 | 
			
		||||
					template.resetHits()
 | 
			
		||||
					for datestr in datestrs:
 | 
			
		||||
						if template.matchDate(datestr): # or getDate?
 | 
			
		||||
							template.incHits()
 | 
			
		||||
 | 
			
		||||
				matchedTemplates = [template
 | 
			
		||||
					for template in self.__datedetector.getTemplates()
 | 
			
		||||
					if template.getHits() > 0]
 | 
			
		||||
				self.assertNotEqual(matchedTemplates, [], "Date %r should match at least one template" % pattern)
 | 
			
		||||
				if len(matchedTemplates) > 1:
 | 
			
		||||
					overlapedTemplates.add((pattern, tuple(sorted(template.getName()
 | 
			
		||||
						for template in matchedTemplates))))
 | 
			
		||||
		if overlapedTemplates:
 | 
			
		||||
			print("WARNING: The following date templates overlap:")
 | 
			
		||||
			pprint.pprint(overlapedTemplates)
 | 
			
		||||
 | 
			
		||||
	def testDateTemplate(self):
 | 
			
		||||
			t = DateTemplate()
 | 
			
		||||
			t.setRegex('^a{3,5}b?c*$')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -205,7 +205,7 @@ class BasicFilter(unittest.TestCase):
 | 
			
		|||
		self.filter.setDatePattern("^%Y-%m-%d-%H%M%S.%f %z")
 | 
			
		||||
		self.assertEqual(self.filter.getDatePattern(),
 | 
			
		||||
			("^%Y-%m-%d-%H%M%S.%f %z",
 | 
			
		||||
			"Year-Month-Day-24hourMinuteSecond.Microseconds Zone offset"))
 | 
			
		||||
			"^Year-Month-Day-24hourMinuteSecond.Microseconds Zone offset"))
 | 
			
		||||
 | 
			
		||||
class IgnoreIP(LogCaptureTestCase):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -291,15 +291,11 @@ Similar to actions, filters have an [Init] section which can be overridden in \f
 | 
			
		|||
specifies the maximum number of lines to buffer to match multi-line regexs. For some log formats this will not required to be changed. Other logs may require to increase this value if a particular log file is frequently written to.
 | 
			
		||||
.TP
 | 
			
		||||
\fBdatepattern\fR
 | 
			
		||||
specifies a custom date pattern as an alternative to the default date detectors e.g. %Y-%m-%d %H:%M
 | 
			
		||||
specifies a custom date pattern/regex as an alternative to the default date detectors e.g. %Y-%m-%d %H:%M(?::%S)?. For a list of valid format directives, see Python library documentation for strptime behaviour.
 | 
			
		||||
.br
 | 
			
		||||
The following are acceptable format fields (see strptime(3) for descriptions):
 | 
			
		||||
.nf
 | 
			
		||||
%% %a %A %b %B %d %H %I %j %m %M %p %S %U %w %W %y %Y
 | 
			
		||||
.fi
 | 
			
		||||
.br
 | 
			
		||||
 | 
			
		||||
Also, special values of \fIEpoch\fR (UNIX Timestamp), \fITAI64N\fR and \fIISO8601\fR can be used.
 | 
			
		||||
.br
 | 
			
		||||
\fBNOTE:\fR due to config file string substitution, that %'s must be escaped by an % in config files.
 | 
			
		||||
.TP
 | 
			
		||||
\fBjournalmatch\fR
 | 
			
		||||
specifies the systemd journal match used to filter the journal entries. See \fBjournalctl(1)\fR and \fBsystemd.journal-fields(7)\fR for matches syntax and more details on special journal fields. This option is only valid for the \fIsystemd\fR backend.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue