Skip to content

Commit b72d3c3

Browse files
committed
Cleaned up message formatters log2timeline#444
1 parent 82e5466 commit b72d3c3

File tree

7 files changed

+169
-123
lines changed

7 files changed

+169
-123
lines changed

plaso/formatters/default.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
from plaso.lib import definitions
66

77

8-
class DefaultFormatter(interface.EventFormatter):
8+
class DefaultEventFormatter(interface.BasicEventFormatter):
99
"""Formatter for events that do not have any defined formatter."""
1010

1111
DATA_TYPE = 'event'
1212
FORMAT_STRING = '<WARNING DEFAULT FORMATTER> Attributes: {attribute_driven}'
1313
FORMAT_STRING_SHORT = '<DEFAULT> {attribute_driven}'
1414

15+
def __init__(self):
16+
"""Initializes a default event formatter."""
17+
super(DefaultEventFormatter, self).__init__(
18+
data_type=self.DATA_TYPE, format_string=self.FORMAT_STRING,
19+
format_string_short=self.FORMAT_STRING_SHORT)
20+
1521
def FormatEventValues(self, event_values):
1622
"""Formats event values using the helpers.
1723

plaso/formatters/interface.py

+120-54
Original file line numberDiff line numberDiff line change
@@ -186,40 +186,37 @@ def FormatEventValues(self, event_values):
186186

187187

188188
class EventFormatter(object):
189-
"""Base class to format event data using a format string.
190-
191-
Define the (long) format string and the short format string by defining
192-
FORMAT_STRING and FORMAT_STRING_SHORT. The syntax of the format strings
193-
is similar to that of format() where the place holder for a certain
194-
event object attribute is defined as {attribute_name}.
189+
"""Base class to format event values.
195190
196191
Attributes:
197192
custom_helpers (list[str]): identifiers of custom event formatter helpers.
198193
helpers (list[EventFormatterHelper]): event formatter helpers.
199194
"""
200195

201-
# The data type is a unique identifier for the event data. The current
202-
# approach is to define it as human readable string in the format
203-
# root:branch: ... :leaf, e.g. a page visited entry inside a Chrome History
204-
# database is defined as: chrome:history:page_visited.
205-
DATA_TYPE = 'internal'
206-
207-
# The format string.
208-
FORMAT_STRING = ''
209-
FORMAT_STRING_SHORT = ''
210-
211196
# The format string can be defined as:
212197
# {name}, {name:format}, {name!conversion}, {name!conversion:format}
213198
_FORMAT_STRING_ATTRIBUTE_NAME_RE = re.compile(
214199
'{([a-z][a-zA-Z0-9_]*)[!]?[^:}]*[:]?[^}]*}')
215200

216-
def __init__(self):
217-
"""Initializes an event formatter object."""
201+
def __init__(self, data_type='internal'):
202+
"""Initializes an event formatter.
203+
204+
Args:
205+
data_type (Optional[str]): unique identifier for the event data supported
206+
by the formatter.
207+
"""
218208
super(EventFormatter, self).__init__()
209+
self._data_type = data_type
219210
self._format_string_attribute_names = None
211+
220212
self.custom_helpers = []
221213
self.helpers = []
222214

215+
@property
216+
def data_type(self):
217+
"""str: unique identifier for the event data supported by the formatter."""
218+
return self._data_type.lower()
219+
223220
def _FormatMessage(self, format_string, event_values):
224221
"""Determines the formatted message.
225222
@@ -293,18 +290,13 @@ def FormatEventValues(self, event_values):
293290
for helper in self.helpers:
294291
helper.FormatEventValues(event_values)
295292

293+
@abc.abstractmethod
296294
def GetFormatStringAttributeNames(self):
297295
"""Retrieves the attribute names in the format string.
298296
299297
Returns:
300298
set(str): attribute names.
301299
"""
302-
if self._format_string_attribute_names is None:
303-
self._format_string_attribute_names = (
304-
self._FORMAT_STRING_ATTRIBUTE_NAME_RE.findall(
305-
self.FORMAT_STRING))
306-
307-
return set(self._format_string_attribute_names)
308300

309301
# pylint: disable=unused-argument
310302
def AddCustomHelper(
@@ -328,6 +320,7 @@ def AddHelper(self, helper):
328320
"""
329321
self.helpers.append(helper)
330322

323+
@abc.abstractmethod
331324
def GetMessage(self, event_values):
332325
"""Determines the message.
333326
@@ -337,8 +330,8 @@ def GetMessage(self, event_values):
337330
Returns:
338331
str: message.
339332
"""
340-
return self._FormatMessage(self.FORMAT_STRING, event_values)
341333

334+
@abc.abstractmethod
342335
def GetMessageShort(self, event_values):
343336
"""Determines the short message.
344337
@@ -348,10 +341,72 @@ def GetMessageShort(self, event_values):
348341
Returns:
349342
str: short message.
350343
"""
351-
if self.FORMAT_STRING_SHORT:
352-
format_string = self.FORMAT_STRING_SHORT
344+
345+
346+
class BasicEventFormatter(EventFormatter):
347+
"""Format event values using a message format string.
348+
349+
Attributes:
350+
custom_helpers (list[str]): identifiers of custom event formatter helpers.
351+
helpers (list[EventFormatterHelper]): event formatter helpers.
352+
"""
353+
354+
def __init__(
355+
self, data_type='basic', format_string=None, format_string_short=None):
356+
"""Initializes a basic event formatter.
357+
358+
The syntax of the format strings is similar to that of format() where
359+
the place holder for a certain event object attribute is defined as
360+
{attribute_name}.
361+
362+
Args:
363+
data_type (Optional[str]): unique identifier for the event data supported
364+
by the formatter.
365+
format_string (Optional[str]): (long) message format string.
366+
format_string_short (Optional[str]): short message format string.
367+
"""
368+
super(BasicEventFormatter, self).__init__(data_type=data_type)
369+
self._format_string_attribute_names = None
370+
self._format_string = format_string
371+
self._format_string_short = format_string_short
372+
373+
def GetFormatStringAttributeNames(self):
374+
"""Retrieves the attribute names in the format string.
375+
376+
Returns:
377+
set(str): attribute names.
378+
"""
379+
if self._format_string_attribute_names is None:
380+
self._format_string_attribute_names = (
381+
self._FORMAT_STRING_ATTRIBUTE_NAME_RE.findall(
382+
self._format_string))
383+
384+
return set(self._format_string_attribute_names)
385+
386+
def GetMessage(self, event_values):
387+
"""Determines the message.
388+
389+
Args:
390+
event_values (dict[str, object]): event values.
391+
392+
Returns:
393+
str: message.
394+
"""
395+
return self._FormatMessage(self._format_string, event_values)
396+
397+
def GetMessageShort(self, event_values):
398+
"""Determines the short message.
399+
400+
Args:
401+
event_values (dict[str, object]): event values.
402+
403+
Returns:
404+
str: short message.
405+
"""
406+
if self._format_string_short:
407+
format_string = self._format_string_short
353408
else:
354-
format_string = self.FORMAT_STRING
409+
format_string = self._format_string
355410

356411
short_message_string = self._FormatMessage(format_string, event_values)
357412

@@ -363,28 +418,38 @@ def GetMessageShort(self, event_values):
363418

364419

365420
class ConditionalEventFormatter(EventFormatter):
366-
"""Base class to conditionally format event data using format string pieces.
421+
"""Conditionally format event values using format string pieces."""
367422

368-
Define the (long) format string and the short format string by defining
369-
FORMAT_STRING_PIECES and FORMAT_STRING_SHORT_PIECES. The syntax of the
370-
format strings pieces is similar to of the event formatter
371-
(EventFormatter). Every format string piece should contain a single
372-
attribute name or none.
423+
_DEFAULT_FORMAT_STRING_SEPARATOR = ' '
373424

374-
FORMAT_STRING_SEPARATOR is used to control the string which the separate
375-
string pieces should be joined. It contains a space by default.
376-
"""
377-
# The format string pieces.
378-
FORMAT_STRING_PIECES = ['']
379-
FORMAT_STRING_SHORT_PIECES = ['']
425+
def __init__(
426+
self, data_type='conditional', format_string_pieces=None,
427+
format_string_separator=None, format_string_short_pieces=None):
428+
"""Initializes a conditional event formatter.
429+
430+
The syntax of the format strings pieces is similar to of the basic event
431+
formatter (BasicEventFormatter). Every format string piece should contain
432+
at maximum one unique attribute name. Format string pieces without an
433+
attribute name are supported.
380434
381-
# The separator used to join the string pieces.
382-
FORMAT_STRING_SEPARATOR = ' '
435+
Args:
436+
data_type (Optional[str]): unique identifier for the event data supported
437+
by the formatter.
438+
format_string_pieces (Optional[list[str]]): (long) message format string
439+
pieces.
440+
format_string_separator (Optional[str]): string by which separate format
441+
string pieces should be joined.
442+
format_string_short_pieces (Optional[list[str]]): short message format
443+
string pieces.
444+
"""
445+
if format_string_separator is None:
446+
format_string_separator = self._DEFAULT_FORMAT_STRING_SEPARATOR
383447

384-
def __init__(self):
385-
"""Initializes the conditional formatter."""
386-
super(ConditionalEventFormatter, self).__init__()
448+
super(ConditionalEventFormatter, self).__init__(data_type=data_type)
449+
self._format_string_pieces = format_string_pieces or []
387450
self._format_string_pieces_map = []
451+
self._format_string_separator = format_string_separator
452+
self._format_string_short_pieces = format_string_short_pieces or []
388453
self._format_string_short_pieces_map = []
389454

390455
def _CreateFormatStringMap(
@@ -433,11 +498,11 @@ def _CreateFormatStringMaps(self):
433498
"""
434499
self._format_string_pieces_map = []
435500
self._CreateFormatStringMap(
436-
self.FORMAT_STRING_PIECES, self._format_string_pieces_map)
501+
self._format_string_pieces, self._format_string_pieces_map)
437502

438503
self._format_string_short_pieces_map = []
439504
self._CreateFormatStringMap(
440-
self.FORMAT_STRING_SHORT_PIECES, self._format_string_short_pieces_map)
505+
self._format_string_short_pieces, self._format_string_short_pieces_map)
441506

442507
def _ConditionalFormatMessage(
443508
self, format_string_pieces, format_string_pieces_map, event_values):
@@ -469,7 +534,7 @@ def _ConditionalFormatMessage(
469534

470535
string_pieces.append(format_string_pieces[map_index])
471536

472-
format_string = self.FORMAT_STRING_SEPARATOR.join(string_pieces)
537+
format_string = self._format_string_separator.join(string_pieces)
473538

474539
return self._FormatMessage(format_string, event_values)
475540

@@ -481,7 +546,7 @@ def GetFormatStringAttributeNames(self):
481546
"""
482547
if self._format_string_attribute_names is None:
483548
self._format_string_attribute_names = []
484-
for format_string_piece in self.FORMAT_STRING_PIECES:
549+
for format_string_piece in self._format_string_pieces:
485550
attribute_names = self._FORMAT_STRING_ATTRIBUTE_NAME_RE.findall(
486551
format_string_piece)
487552

@@ -503,7 +568,8 @@ def GetMessage(self, event_values):
503568
self._CreateFormatStringMaps()
504569

505570
return self._ConditionalFormatMessage(
506-
self.FORMAT_STRING_PIECES, self._format_string_pieces_map, event_values)
571+
self._format_string_pieces, self._format_string_pieces_map,
572+
event_values)
507573

508574
def GetMessageShort(self, event_values):
509575
"""Determines the short message.
@@ -517,12 +583,12 @@ def GetMessageShort(self, event_values):
517583
if not self._format_string_pieces_map:
518584
self._CreateFormatStringMaps()
519585

520-
if (self.FORMAT_STRING_SHORT_PIECES and
521-
self.FORMAT_STRING_SHORT_PIECES != ['']):
522-
format_string_pieces = self.FORMAT_STRING_SHORT_PIECES
586+
if (self._format_string_short_pieces and
587+
self._format_string_short_pieces != ['']):
588+
format_string_pieces = self._format_string_short_pieces
523589
format_string_pieces_map = self._format_string_short_pieces_map
524590
else:
525-
format_string_pieces = self.FORMAT_STRING_PIECES
591+
format_string_pieces = self._format_string_pieces
526592
format_string_pieces_map = self._format_string_pieces_map
527593

528594
short_message_string = self._ConditionalFormatMessage(

plaso/formatters/yaml_formatters_file.py

+8-17
Original file line numberDiff line numberDiff line change
@@ -211,26 +211,17 @@ def _ReadFormatterDefinition(self, formatter_definition_values):
211211
raise errors.ParseError(
212212
'Invalid event formatter definition missing short message.')
213213

214-
# TODO: pylint will complain about invalid-name because of the override
215-
# of class "constants", hence that setattr is used. Change this once
216-
# formatters have been migrated to configuration file. Also see:
217-
# https://github.com/log2timeline/plaso/issues/444
218214
if formatter_type == 'basic':
219-
formatter = interface.EventFormatter()
220-
# TODO: check if message and short_message are strings
221-
setattr(formatter, 'FORMAT_STRING', message)
222-
setattr(formatter, 'FORMAT_STRING_SHORT', short_message)
215+
formatter = interface.BasicEventFormatter(
216+
data_type=data_type, format_string=message,
217+
format_string_short=short_message)
223218

224219
elif formatter_type == 'conditional':
225-
formatter = interface.ConditionalEventFormatter()
226-
separator = formatter_definition_values.get(
227-
'separator', formatter.FORMAT_STRING_SEPARATOR)
228-
# TODO: check if message and short_message are list of strings
229-
setattr(formatter, 'FORMAT_STRING_PIECES', message)
230-
setattr(formatter, 'FORMAT_STRING_SHORT_PIECES', short_message)
231-
setattr(formatter, 'FORMAT_STRING_SEPARATOR', separator)
232-
233-
setattr(formatter, 'DATA_TYPE', data_type)
220+
separator = formatter_definition_values.get('separator', None)
221+
formatter = interface.ConditionalEventFormatter(
222+
data_type=data_type, format_string_pieces=message,
223+
format_string_separator=separator,
224+
format_string_short_pieces=short_message)
234225

235226
boolean_helpers = formatter_definition_values.get('boolean_helpers', [])
236227
self._ReadBooleanHelpers(formatter, boolean_helpers)

plaso/output/mediator.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class OutputMediator(object):
2929
# LCID 0x0409 is en-US.
3030
DEFAULT_LCID = 0x0409
3131

32-
_DEFAULT_MESSAGE_FORMATTER = default.DefaultFormatter()
32+
_DEFAULT_MESSAGE_FORMATTER = default.DefaultEventFormatter()
3333

3434
_WINEVT_RC_DATABASE = 'winevt-rc.db'
3535

@@ -103,8 +103,7 @@ def _ReadMessageFormattersFile(self, path):
103103
if custom_formatter_helper:
104104
message_formatter.AddHelper(custom_formatter_helper)
105105

106-
data_type = message_formatter.DATA_TYPE.lower()
107-
self._message_formatters[data_type] = message_formatter
106+
self._message_formatters[message_formatter.data_type] = message_formatter
108107

109108
def GetDisplayNameForPathSpec(self, path_spec):
110109
"""Retrieves the display name for a path specification.

tests/formatters/default.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
from tests.formatters import test_lib
1010

1111

12-
class DefaultFormatterTest(test_lib.EventFormatterTestCase):
12+
class DefaultEventFormatterTest(test_lib.EventFormatterTestCase):
1313
"""Tests for the default event formatter."""
1414

1515
def testInitialization(self):
1616
"""Tests the initialization."""
17-
event_formatter = default.DefaultFormatter()
17+
event_formatter = default.DefaultEventFormatter()
1818
self.assertIsNotNone(event_formatter)
1919

2020
def testGetFormatStringAttributeNames(self):
2121
"""Tests the GetFormatStringAttributeNames function."""
22-
event_formatter = default.DefaultFormatter()
22+
event_formatter = default.DefaultEventFormatter()
2323

2424
expected_attribute_names = ['attribute_driven']
2525

0 commit comments

Comments
 (0)