Skip to content

Commit 5ea993c

Browse files
committed
logfile: Improve source code
1 parent 06de4e3 commit 5ea993c

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

check-plugins/logfile/logfile

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ from lib.globals import (STATE_CRIT, STATE_OK, # pylint: disable=C0413
2626
STATE_UNKNOWN, STATE_WARN)
2727

2828
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
29-
__version__ = '2023071203'
29+
__version__ = '2023112801'
3030

31-
DESCRIPTION = "Scans a logfile for set of pattern or regex and alarms on the number of findings."
31+
DESCRIPTION = """Scans a logfile for a set of patterns or regex and alerts
32+
on the number of matches."""
3233

3334
DEFAULT_ALARM_DURATION = 60 # minutes (1 hour)
3435
DEFAULT_CRIT = 1
@@ -51,7 +52,9 @@ def parse_args():
5152

5253
parser.add_argument(
5354
'--alarm-duration',
54-
help='How long should this check return an alarm on new matches (in minutes)? This is overwritten by --icinga-callback. Default: %(default)s',
55+
help='How long should this check return an alert on new matches (in minutes)? '
56+
'This is overwritten by --icinga-callback. '
57+
'Default: %(default)s',
5558
dest='ALARM_DURATION',
5659
type=int,
5760
default=DEFAULT_ALARM_DURATION,
@@ -67,7 +70,8 @@ def parse_args():
6770

6871
parser.add_argument(
6972
'-c', '--critical',
70-
help='Set the critical threshold for the number of found critical matches. Default: %(default)s',
73+
help='Set the critical threshold for the number of found critical matches. '
74+
'Default: %(default)s',
7175
dest='CRIT',
7276
default=DEFAULT_CRIT,
7377
)
@@ -82,23 +86,24 @@ def parse_args():
8286

8387
parser.add_argument(
8488
'--critical-regex',
85-
help='Any line matching this python regex will count as a critical.',
89+
help='Any line matching this Python regex will count as a critical.',
8690
action='append',
8791
dest='CRIT_REGEX',
8892
default=[],
8993
)
9094

9195
parser.add_argument(
9296
'--filename',
93-
help='Set the path of the logfile.',
97+
help='Set the path to the logfile.',
9498
dest='FILENAME',
9599
required=True,
96100
type=str,
97101
)
98102

99103
parser.add_argument(
100104
'--icinga-callback',
101-
help='Get the service acknowledgement from Icinga. This overwrites --alarm-duration. Default: %(default)s',
105+
help='Get the service acknowledgement from Icinga. This overwrites `--alarm-duration`. '
106+
'Default: %(default)s',
102107
dest='ICINGA_CALLBACK',
103108
action='store_true',
104109
default=DEFAULT_ICINGA_CALLBACK,
@@ -112,7 +117,9 @@ def parse_args():
112117

113118
parser.add_argument(
114119
'--icinga-service-name',
115-
help='Unique name of the service using this check within Icinga. Take it from the `__name` service attribute, for example `icinga-server!my-service-name`.',
120+
help='Unique name of the service using this check within Icinga. '
121+
'Take it from the `__name` service attribute, for example '
122+
'`icinga-server!my-service-name`.',
116123
dest='ICINGA_SERVICE_NAME',
117124
)
118125

@@ -138,7 +145,7 @@ def parse_args():
138145

139146
parser.add_argument(
140147
'--ignore-regex',
141-
help='Any line matching this python regex will be ignored.',
148+
help='Any line matching this Python regex will be ignored.',
142149
action='append',
143150
default=[],
144151
dest='IGNORE_REGEX',
@@ -154,7 +161,8 @@ def parse_args():
154161

155162
parser.add_argument(
156163
'-w', '--warning',
157-
help='Set the warning threshold for the number of found warning matches. Default: %(default)s',
164+
help='Set the warning threshold for the number of found warning matches. '
165+
'Default: %(default)s',
158166
dest='WARN',
159167
default=DEFAULT_WARN,
160168
)
@@ -169,7 +177,7 @@ def parse_args():
169177

170178
parser.add_argument(
171179
'--warning-regex',
172-
help='Any line matching this python regex will count as a warning.',
180+
help='Any line matching this Python regex will count as a warning.',
173181
action='append',
174182
dest='WARN_REGEX',
175183
default=[],
@@ -185,17 +193,26 @@ def main():
185193
except SystemExit:
186194
sys.exit(STATE_UNKNOWN)
187195

196+
try:
197+
file_stat = os.stat(args.FILENAME)
198+
except FileNotFoundError as e:
199+
# no traceback wanted, so using oao() instead of cu()
200+
lib.base.oao('{}: "{}"'.format(e.strerror, args.FILENAME), STATE_UNKNOWN)
201+
188202
if not any((args.WARN_PATTERN, args.WARN_REGEX, args.CRIT_PATTERN, args.CRIT_REGEX)):
189203
lib.base.cu('At least one pattern or regex is required.')
190204

191-
if args.ICINGA_CALLBACK and not all((args.ICINGA_URL, args.ICINGA_PASSWORD, args.ICINGA_USERNAME, args.ICINGA_SERVICE_NAME)):
192-
lib.base.cu('--icinga-callback requires --icinga-url, --icinga-password, --icinga-username and --icinga-service-name.')
205+
if args.ICINGA_CALLBACK \
206+
and not all((args.ICINGA_URL, args.ICINGA_PASSWORD, args.ICINGA_USERNAME, args.ICINGA_SERVICE_NAME)): # pylint: disable=C0301
207+
lib.base.cu('`--icinga-callback` requires `--icinga-url`, `--icinga-password`, `--icinga-username` and `--icinga-service-name`.') # pylint: disable=C0301
193208

194209
# create the db table
195210
conn = lib.base.coe(
196-
lib.db_sqlite.connect(filename='linuxfabrik-monitoring-plugins-logfile-{}.db'.format(
197-
os.path.basename(args.FILENAME)
198-
))
211+
lib.db_sqlite.connect(
212+
filename='linuxfabrik-monitoring-plugins-logfile-{}.db'.format(
213+
os.path.basename(args.FILENAME),
214+
)
215+
)
199216
)
200217
definition = '''
201218
filename TEXT NOT NULL PRIMARY KEY,
@@ -211,7 +228,6 @@ def main():
211228
'''
212229
lib.base.coe(lib.db_sqlite.create_table(conn, definition, table='matching_lines'))
213230

214-
file_stat = os.stat(args.FILENAME)
215231
current_inode = file_stat.st_ino
216232
current_size = file_stat.st_size
217233

@@ -229,8 +245,7 @@ def main():
229245
if old_file_stats:
230246
# this is not the first time we are scanning this logfile, try to continue where we left off
231247
offset = old_file_stats.get('offset', 0)
232-
233-
if (current_inode != old_file_stats.get('inode')
248+
if (current_inode != old_file_stats.get('inode') \
234249
or current_size < offset):
235250
# this means the file has been rotated
236251
offset = 0
@@ -249,25 +264,21 @@ def main():
249264
logfile.seek(offset)
250265
for line in logfile:
251266
line_counter += 1
252-
# due to lazy evaluation, the regex will only be executed if the pattern does not match
267+
# due to lazy evaluation, the regex will only be executed
268+
# if the pattern does not match
253269
# see https://docs.python.org/3/reference/expressions.html#boolean-operations
254-
if any(warn_pattern in line for warn_pattern in args.WARN_PATTERN)\
270+
if any(warn_pattern in line for warn_pattern in args.WARN_PATTERN) \
255271
or any(item.search(line) for item in compiled_warn_regex):
256-
if not any(ignore_pattern in line for ignore_pattern in args.IGNORE_PATTERN)\
272+
if not any(ignore_pattern in line for ignore_pattern in args.IGNORE_PATTERN) \
257273
and not any(item.search(line) for item in compiled_ignore_regex):
258274
warn_matches.append(line.strip())
259275

260-
if any(crit_pattern in line for crit_pattern in args.CRIT_PATTERN)\
276+
if any(crit_pattern in line for crit_pattern in args.CRIT_PATTERN) \
261277
or any(item.search(line) for item in compiled_crit_regex):
262-
if not any(ignore_pattern in line for ignore_pattern in args.IGNORE_PATTERN)\
278+
if not any(ignore_pattern in line for ignore_pattern in args.IGNORE_PATTERN) \
263279
and not any(item.search(line) for item in compiled_ignore_regex):
264280
crit_matches.append(line.strip())
265-
266281
offset = logfile.tell()
267-
except FileNotFoundError:
268-
lib.base.cu("Could not find logfile '{}'.".format(args.FILENAME))
269-
# make sure conn is always closed
270-
lib.db_sqlite.close(conn)
271282
except PermissionError:
272283
lib.base.cu("Permission denied opening '{}'.".format(args.FILENAME))
273284
# make sure conn is always closed
@@ -281,7 +292,8 @@ def main():
281292
}
282293
lib.base.coe(lib.db_sqlite.replace(conn, new_file_stats, table='file_stats'))
283294

284-
# if we are using the alarm duration (aka not using the icinga callback), remove all outdated matches from the db now
295+
# if we are using the alarm duration (aka not using the icinga callback),
296+
# remove all outdated matches from the db now
285297
now = lib.time.now(as_type='datetime')
286298
if not args.ICINGA_CALLBACK:
287299
outdated = now - datetime.timedelta(minutes=args.ALARM_DURATION)
@@ -296,7 +308,8 @@ def main():
296308
))
297309

298310
# get the old matches and take them into consideration for the state
299-
# for example, if there are no new lines we still want to alarm the old ones until the service is acknowledged
311+
# for example, if there are no new lines we still want to alarm the old ones
312+
# until the service is acknowledged
300313
old_warn_matches = lib.base.coe(lib.db_sqlite.select(
301314
conn,
302315
'''
@@ -352,9 +365,9 @@ def main():
352365
else:
353366
msg_addendum += 'Note: Acknowledge this service to reset the state to OK.'
354367
except IndexError:
355-
msg_addendum += 'Note: Could not determine the acknowledgement from the Icinga API, this could be due to an incorrect service name.'
368+
msg_addendum += 'Note: Could not determine the acknowledgement from the Icinga API, this could be due to an incorrect service name.' # pylint: disable=C0301
356369
else:
357-
msg_addendum += 'Note: Could not determine the acknowledgement from the Icinga API:\n{}.'.format(icinga)
370+
msg_addendum += 'Note: Could not determine the acknowledgement from the Icinga API:\n{}.'.format(icinga) # pylint: disable=C0301
358371

359372
# save to db, these lines will be alarmed until the service is acknowledged in icinga2
360373
for match in warn_matches:
@@ -416,14 +429,14 @@ def main():
416429
msg += '\n\nCritical matches:\n* ' + '\n* '.join(crit_matches)
417430

418431
if old_warn_matches:
419-
msg += '\n\nOld warning matches:\n* ' + '\n* '.join([match['line'] for match in old_warn_matches])
432+
msg += '\n\nOld warning matches:\n* ' + '\n* '.join([match['line'] for match in old_warn_matches]) # pylint: disable=C0301
420433

421434
if old_crit_matches:
422-
msg += '\n\nOld critical matches:\n* ' + '\n* '.join([match['line'] for match in old_crit_matches])
435+
msg += '\n\nOld critical matches:\n* ' + '\n* '.join([match['line'] for match in old_crit_matches]) # pylint: disable=C0301
423436

424437
perfdata = lib.base.get_perfdata('scanned_lines', line_counter, None, None, None, None, None)
425-
perfdata += lib.base.get_perfdata('warn_matches', len(warn_matches), None, args.WARN, None, None, None)
426-
perfdata += lib.base.get_perfdata('crit_matches', len(crit_matches), None, args.WARN, None, None, None)
438+
perfdata += lib.base.get_perfdata('warn_matches', len(warn_matches), None, args.WARN, None, None, None) # pylint: disable=C0301
439+
perfdata += lib.base.get_perfdata('crit_matches', len(crit_matches), None, args.WARN, None, None, None) # pylint: disable=C0301
427440

428441
lib.base.oao(msg + '\n\n' + msg_addendum, state, perfdata, always_ok=args.ALWAYS_OK)
429442

0 commit comments

Comments
 (0)