组织日志解析器函数的最佳方式是什么?
What is the best way to organise a log parser function?
我一直在编写一个日志解析器来从一些日志中获取一些信息,然后在其他地方使用它。这个想法是 运行 它覆盖一系列日志文件,并将有用的信息存储在数据库中以备将来使用。我使用的语言是 python(3.8)
从日志中提取的信息类型是 json 类型的字符串,我将其存储在字典中、普通字母数字字符串、时间戳(我们将其转换为日期时间对象)、整数和浮点数 - 有时作为值字典格式。
我制作了一个 parse_logs(filepath) 方法,该方法采用文件路径和 returns 字典列表,其中包含所有消息。一条消息可以包含上述多种类型,为了解析这些日志,我编写了多种方法将消息从日志行中分离到一个字符串列表中,然后操作这些构成消息的行列表提取各种信息。
这导致了一个主 parse_logs(filepath: str) -> list
函数具有多个辅助函数(如 extract_datetime_from_header(header_line: str) -> datetime
、 extract_message(messages: list) -> list
和 process_message(message: list) -> dict
每个都做特定的事情,但不是对我正在处理的项目的任何其他部分都很有用,因为它们非常具体地有助于实现此功能。
我唯一想做的事情(至少现在)是获取这些消息并将其信息保存在数据库中。
-因此,我考虑通过两种主要方式来组织我的代码:一种是创建一个 LogParser class,它将有一个日志路径和一个消息列表作为属性,以及所有功能都作为 class 方法。 (在那种情况下,助手 classes 的缩进级别应该是多少?它们应该是它们自己的方法还是应该只是在它们应该启用的方法中定义的函数?)。
另一个只是有一个基本函数(并将所有辅助函数嵌套在其中,因为我假设我不希望它们作为独立函数导入)并且只是 运行 该方法仅以路径作为参数,并且它将 return 消息列表传递给调用者函数,该函数将获取列表、解析它并将每条消息移动到数据库中的位置。
-我正在考虑的另一件事是是否使用 dataclasses 而不是数据字典。速度差异并不重要,因为它是一个脚本,每天只需要 运行 几次作为 cronjob,如果它需要 5 秒或 20 秒到 运行(除非差异更大,否则我只在半 MB 的日志示例上对其进行了测试,而不是预期的 4-6 GB)
我最后关心的是将消息对象保存在内存中并将它们直接提供给数据库编写器。我做了一些测试和估计,我预计 150MB 似乎是最坏情况下的合理上限(这是一个只包含有用数据的日志,比我们目前拥有的最大日志大 40% -所以即使我们扩展到这个数量的 3 倍,我认为一台 16GB RAM 的机器应该能够毫无问题地处理它。
所以,综上所述,我想询问有关如何处理组织代码的最佳实践,即:
- class/oop 方法是否比仅编写完成工作的函数更好?是不是更readable/maintainable?
- 我应该使用数据classes 还是坚持使用字典?两者的 advantages/disadvantages 是多少?哪个更好维护,哪个更高效?
- 如果我关心处理来自数据库的数据而不是来自这些对象(dicts 或数据 classes),哪种方法更有效?
- 在数据库事务完成之前将消息对象保留在内存中是否可以,还是我应该以不同的方式处理它?我曾考虑过在解析完单个日志后执行单个事务(但有人告诉我这可能会导致可扩展性差,因为临时消息列表会不断增加内存中的数据,直到它们在数据库事务中使用 - 并且单个大事务也可能反过来变慢)或将每条消息在解析时(作为字典对象)写入磁盘中的文件然后解析该中介(是正确的词?)文件到将处理数据库事务并分批处理的函数(有人告诉我这也不是一个好习惯),或者在解析消息时直接写入数据库(在每条消息之后或小批量进行,以便总消息列表不会变得太大)。我什至想过走 producer/consumer 路线并保留一个共享变量,生产者(日志解析器)将附加到该共享变量,而消费者(数据库编写器)将使用该共享变量,直到日志被完全解析。但是这条路线我以前没有做过(除了几次面试题,比较简单,感觉很难调试和维护,所以我现在没有信心去做)。关于上述内容的最佳做法是什么?
非常感谢您的宝贵时间!我知道我问的有点多,但我确实想写下我的所有想法并阅读一些人的意见。到那时,我将尝试实现上述所有想法(可能 producer/consumer 除外),看看哪个对我来说更易于维护、更易于阅读且直观正确。
- Is the class/oop way a better practice than just writing functions that do the work? Is it more readable/maintainable?
我认为不一定有最佳方法。我已经看到以下工作同样出色:
OOP:您将有一个 Parser
class,它使用实例变量来共享解析状态。解析器可以是线程安全的,也可以不是。
闭包:您将使用嵌套函数在输入和解析状态上创建闭包。
功能性:您将输入和解析状态传递给返回解析状态的函数(例如 AST + 更新的游标索引)。
- Should I use dataclasses or stick to dictionaries? What are the advantages/disadvantages of both? Which is better maintainable and which is more efficient?
AST 通常以两种方式表示 (homogenous vs heterogenous):
同类:您将有一个 ASTNode { type, children }
class 来表示所有节点类型。
异构:每种类型都有一个具体节点 class。
您的方法有点混合了两者,因为作为 key/value 存储,字典在指向其他节点时比列表索引更具表现力,但所有节点仍以相同的底层表示类型。我通常喜欢使用自定义 classes 的 #2,因为它们会自我记录树的结构,尽管在动态类型语言中可能没有那么多好处。
至于性能,IDK Python 足够好,但快速谷歌搜索似乎指出字典的整体性能最高。
- If I care about handling data from the database and not from these objects(dicts or data classes), which is the more efficient way to go?
如果内存中的 AST 消费者不感兴趣并且你不会有太多的 AST 处理操作那么我想在 AST 表示上投入大量时间和精力就不那么重要了,尽管如果你只有几种从一开始就明确表示的节点数量不应该是一个巨大的努力。
- Is it alright to keep the message objects in-memory until the database transaction is complete...
老实说,当你谈论运行时和内存优化时,它真的取决于。我会说避免陷入过早优化。这些日志可能有多大?会不会内存溢出?操作如此耗时以至于崩溃并不得不重新开始是不可接受的吗?
这些都是可以帮助您确定最合适方法的问题。
我一直在编写一个日志解析器来从一些日志中获取一些信息,然后在其他地方使用它。这个想法是 运行 它覆盖一系列日志文件,并将有用的信息存储在数据库中以备将来使用。我使用的语言是 python(3.8)
从日志中提取的信息类型是 json 类型的字符串,我将其存储在字典中、普通字母数字字符串、时间戳(我们将其转换为日期时间对象)、整数和浮点数 - 有时作为值字典格式。
我制作了一个 parse_logs(filepath) 方法,该方法采用文件路径和 returns 字典列表,其中包含所有消息。一条消息可以包含上述多种类型,为了解析这些日志,我编写了多种方法将消息从日志行中分离到一个字符串列表中,然后操作这些构成消息的行列表提取各种信息。
这导致了一个主 parse_logs(filepath: str) -> list
函数具有多个辅助函数(如 extract_datetime_from_header(header_line: str) -> datetime
、 extract_message(messages: list) -> list
和 process_message(message: list) -> dict
每个都做特定的事情,但不是对我正在处理的项目的任何其他部分都很有用,因为它们非常具体地有助于实现此功能。
我唯一想做的事情(至少现在)是获取这些消息并将其信息保存在数据库中。
-因此,我考虑通过两种主要方式来组织我的代码:一种是创建一个 LogParser class,它将有一个日志路径和一个消息列表作为属性,以及所有功能都作为 class 方法。 (在那种情况下,助手 classes 的缩进级别应该是多少?它们应该是它们自己的方法还是应该只是在它们应该启用的方法中定义的函数?)。 另一个只是有一个基本函数(并将所有辅助函数嵌套在其中,因为我假设我不希望它们作为独立函数导入)并且只是 运行 该方法仅以路径作为参数,并且它将 return 消息列表传递给调用者函数,该函数将获取列表、解析它并将每条消息移动到数据库中的位置。 -我正在考虑的另一件事是是否使用 dataclasses 而不是数据字典。速度差异并不重要,因为它是一个脚本,每天只需要 运行 几次作为 cronjob,如果它需要 5 秒或 20 秒到 运行(除非差异更大,否则我只在半 MB 的日志示例上对其进行了测试,而不是预期的 4-6 GB) 我最后关心的是将消息对象保存在内存中并将它们直接提供给数据库编写器。我做了一些测试和估计,我预计 150MB 似乎是最坏情况下的合理上限(这是一个只包含有用数据的日志,比我们目前拥有的最大日志大 40% -所以即使我们扩展到这个数量的 3 倍,我认为一台 16GB RAM 的机器应该能够毫无问题地处理它。
所以,综上所述,我想询问有关如何处理组织代码的最佳实践,即:
- class/oop 方法是否比仅编写完成工作的函数更好?是不是更readable/maintainable?
- 我应该使用数据classes 还是坚持使用字典?两者的 advantages/disadvantages 是多少?哪个更好维护,哪个更高效?
- 如果我关心处理来自数据库的数据而不是来自这些对象(dicts 或数据 classes),哪种方法更有效?
- 在数据库事务完成之前将消息对象保留在内存中是否可以,还是我应该以不同的方式处理它?我曾考虑过在解析完单个日志后执行单个事务(但有人告诉我这可能会导致可扩展性差,因为临时消息列表会不断增加内存中的数据,直到它们在数据库事务中使用 - 并且单个大事务也可能反过来变慢)或将每条消息在解析时(作为字典对象)写入磁盘中的文件然后解析该中介(是正确的词?)文件到将处理数据库事务并分批处理的函数(有人告诉我这也不是一个好习惯),或者在解析消息时直接写入数据库(在每条消息之后或小批量进行,以便总消息列表不会变得太大)。我什至想过走 producer/consumer 路线并保留一个共享变量,生产者(日志解析器)将附加到该共享变量,而消费者(数据库编写器)将使用该共享变量,直到日志被完全解析。但是这条路线我以前没有做过(除了几次面试题,比较简单,感觉很难调试和维护,所以我现在没有信心去做)。关于上述内容的最佳做法是什么?
非常感谢您的宝贵时间!我知道我问的有点多,但我确实想写下我的所有想法并阅读一些人的意见。到那时,我将尝试实现上述所有想法(可能 producer/consumer 除外),看看哪个对我来说更易于维护、更易于阅读且直观正确。
- Is the class/oop way a better practice than just writing functions that do the work? Is it more readable/maintainable?
我认为不一定有最佳方法。我已经看到以下工作同样出色:
OOP:您将有一个
Parser
class,它使用实例变量来共享解析状态。解析器可以是线程安全的,也可以不是。闭包:您将使用嵌套函数在输入和解析状态上创建闭包。
功能性:您将输入和解析状态传递给返回解析状态的函数(例如 AST + 更新的游标索引)。
- Should I use dataclasses or stick to dictionaries? What are the advantages/disadvantages of both? Which is better maintainable and which is more efficient?
AST 通常以两种方式表示 (homogenous vs heterogenous):
同类:您将有一个
ASTNode { type, children }
class 来表示所有节点类型。异构:每种类型都有一个具体节点 class。
您的方法有点混合了两者,因为作为 key/value 存储,字典在指向其他节点时比列表索引更具表现力,但所有节点仍以相同的底层表示类型。我通常喜欢使用自定义 classes 的 #2,因为它们会自我记录树的结构,尽管在动态类型语言中可能没有那么多好处。
至于性能,IDK Python 足够好,但快速谷歌搜索似乎指出字典的整体性能最高。
- If I care about handling data from the database and not from these objects(dicts or data classes), which is the more efficient way to go?
如果内存中的 AST 消费者不感兴趣并且你不会有太多的 AST 处理操作那么我想在 AST 表示上投入大量时间和精力就不那么重要了,尽管如果你只有几种从一开始就明确表示的节点数量不应该是一个巨大的努力。
- Is it alright to keep the message objects in-memory until the database transaction is complete...
老实说,当你谈论运行时和内存优化时,它真的取决于。我会说避免陷入过早优化。这些日志可能有多大?会不会内存溢出?操作如此耗时以至于崩溃并不得不重新开始是不可接受的吗?
这些都是可以帮助您确定最合适方法的问题。