哪种设计(使用 OOP)更好?外部化还是内部化日志记录?
Which design (using OOP) is better? Externalized or internalized logging?
我需要验证日志信息(错误消息)以及结果集。这里logging在我这里也可以理解为report generation
外部化日志记录
我是否应该将日志消息(对于任何错误)与结果一起存储并在业务逻辑步骤之后进行日志记录
优点:
- 这为我提供了日志信息,我可以使用这些信息在单元测试期间验证负面案例,而不是解析日志文件。
- 将日志记录与业务逻辑分开。
- 我可以将日志记录作为一个单独的功能来实现,我可以根据实现以不同的格式登录(HTML、JSON 等)
缺点
- 这将导致代码重复,因为我最终会得到与计算结果集相同的日志循环。
- 在记录阶段,parent 必须获取 child 信息。存储所有这些信息使其变得复杂且不可读。
内部化日志记录
我是否应该在执行业务逻辑的同时进行日志记录
优势
- 不存储任何信息并简化解决方案并有效地将 parent object 的上下文传递给 child object、
- 发生异常时记录。
缺点
- 但无法将 logging/reporting 与业务逻辑分开。
- 我不会得到日志信息来验证 unit-tests 的负面案例。所以我需要解析日志文件来验证。
更多上下文如下:
我正在构建此工具以比较两种资源的属性,这些资源的类型可以是 - JSON、属性、VM、REST API 等 Python。
该工具读取具有如下结构的元数据json:
{
"run-name": "Run Tests"
"tests": [
{
"name": "Test 1",
"checks":[
{
"name": "Dynamic Multiple",
"type": "COMPARE",
"dynamic": [
{
"file": "source.json",
"type": "JSON",
"property": "topology.wlsClusters.[].clusterName"
}
],
"source": {
"file": "source.json",
"type": "JSON",
"property": "topology.wlsClusters.[clusterName == ].Xms"
},
"target": {
"file": "target.properties",
"type": "PROPERTY",
"property": "fusion.FADomain..default.minmaxmemory.main",
"format": "-Xms{}?"
}
},
]
}
]
}
以上 JSON 告诉我的工具:
- 从 topology.wlsClusters 中的每个 wlsCluster object 中获取 'clusterName'。这给出了 'clusterNames'.
的列表
- 从 'source.json' 从每个 wlsCluster object 获取 Xms 值,其中 'clusterName' 属于上述列表。
- 同样使用上面的列表从 target.properties 文件中获取所有 Xms 值。
- 比较源 Xms 列表和目标 Xmx 列表中的每个值。
- 如果全部匹配则成功,否则失败。
直观上上面的JSON可以映射到对应的object为:
- 测试
- 检查
- 资源
现在理想情况下,我知道我应该执行以下步骤:
- 运行 所有测试,以及每个测试中的所有检查。
- 对于每个测试,如果类型是比较
- 读取并计算 'dynamic' 个值
- 读取'source'并替换属性字段中的动态值并获取相应的属性
- 同样读取'target'并获取相应的属性
- 比较 return 'PASSED' 或 'FAILED'
大体上我有这些步骤:
- 获取并存储值。
- 比较值
我也想按以下格式打印日志。
[<TIMESTAMP> <RUN-NAME> <TEST-NAME> <CHECK-NAME> <ERROR-LEVEL> <MESSAGE-TYPE> <RESOURCE-NAME>] custom-msg
其中
ERROR-TYPE: INFO DEBUG etc
MESSAGE-TYPE: COMPARE, SYNATAX-ERROR, MISSING-PROPERTY etc
现在如果我遵循上面的 object 模型,并且每个 object 负责处理它自己的日志记录,它就不会拥有所有这些信息。所以我需要:
- 将此信息传递给 child object,
- 或让parent读取childobject的信息。
我更喜欢第二种方法,因为这样我就可以存储获取的结果并将日志记录(如果有的话)延迟到比较之后。通过这种方式,我还可以 运行 验证(unit-tests),因为我也验证错误消息(负面情况)。
但这就是我的解决方案变得复杂的地方。
- 我需要在每个object中存放fetch的结果,可以是找到的值,也可以是没有找到值的'None'。现在我还需要在找不到值时存储错误类型和错误消息。让我们称之为 class 值。
- 每个 属性 都可以产生一个这样的值的列表。
- 每个资源都可以生成这样的列表 属性。
- 每个检查都可以生成此类资源的列表。
注意:这是在 Python 中开发的。 (如果这对你很重要。)
每个 class 都应该对自己的状态负责。当您让 classes 根据其他 classes 中的属性做出决定时,您最终会得到意大利面条代码。
类似 if (test.check.resource.AProperty == aValue)
的代码清楚地表明您的意大利面已经开始烹饪了。
在这种情况下,您希望在 classes 中完全登录。您想要确定一系列操作是否成功完成。 因此,您想记录结果。
考虑到这一点,根本不要让 classes 记录,而只报告他们 tested/checked 的内容及其结果。
一种常见的方法是提供用于接收结果的上下文对象。
这里有一些 C# 代码来说明(我不太了解 python):
interface VerifierContext
{
void AddSuccess(string checkName, string resourceName, string message);
void AddFailure(string checkName, string resourceName, SomeEnum failureType, string message);
}
public class SomeChecker
{
public void Validate(VerifierContext context)
{
context.AddFailure("CompanyNameLength", "cluster.Company", SomeEnum.LengthRestriction, "Company name was 30chars, can only be 10");
}
}
这将为您提供一个简单的验证列表。如果你想嵌套,你可以添加 Enter/Exit 方法:
public class SomeChecker
{
public void Validate(VerifierContext context)
{
context.Enter("CompanyValidations");
foreach (var validator in _childValidators)
validator.Validate(context);
context.Exit("CompanyValidations");
}
}
你当然可以用很多不同的方式来设计它。我的主要观点是,您 check/parser 中的每个 class 都应该决定一切是否正常。它不应该决定应该如何记录事情。
触发工作的 class 然后可以遍历所有结果并根据错误类型等选择日志级别
所有 class 也很容易测试,因为它们仅取决于上下文。
我需要验证日志信息(错误消息)以及结果集。这里logging在我这里也可以理解为report generation
外部化日志记录
我是否应该将日志消息(对于任何错误)与结果一起存储并在业务逻辑步骤之后进行日志记录
优点:
- 这为我提供了日志信息,我可以使用这些信息在单元测试期间验证负面案例,而不是解析日志文件。
- 将日志记录与业务逻辑分开。
- 我可以将日志记录作为一个单独的功能来实现,我可以根据实现以不同的格式登录(HTML、JSON 等)
缺点
- 这将导致代码重复,因为我最终会得到与计算结果集相同的日志循环。
- 在记录阶段,parent 必须获取 child 信息。存储所有这些信息使其变得复杂且不可读。
内部化日志记录
我是否应该在执行业务逻辑的同时进行日志记录
优势
- 不存储任何信息并简化解决方案并有效地将 parent object 的上下文传递给 child object、
- 发生异常时记录。
缺点
- 但无法将 logging/reporting 与业务逻辑分开。
- 我不会得到日志信息来验证 unit-tests 的负面案例。所以我需要解析日志文件来验证。
更多上下文如下:
我正在构建此工具以比较两种资源的属性,这些资源的类型可以是 - JSON、属性、VM、REST API 等 Python。
该工具读取具有如下结构的元数据json:
{
"run-name": "Run Tests"
"tests": [
{
"name": "Test 1",
"checks":[
{
"name": "Dynamic Multiple",
"type": "COMPARE",
"dynamic": [
{
"file": "source.json",
"type": "JSON",
"property": "topology.wlsClusters.[].clusterName"
}
],
"source": {
"file": "source.json",
"type": "JSON",
"property": "topology.wlsClusters.[clusterName == ].Xms"
},
"target": {
"file": "target.properties",
"type": "PROPERTY",
"property": "fusion.FADomain..default.minmaxmemory.main",
"format": "-Xms{}?"
}
},
]
}
]
}
以上 JSON 告诉我的工具:
- 从 topology.wlsClusters 中的每个 wlsCluster object 中获取 'clusterName'。这给出了 'clusterNames'. 的列表
- 从 'source.json' 从每个 wlsCluster object 获取 Xms 值,其中 'clusterName' 属于上述列表。
- 同样使用上面的列表从 target.properties 文件中获取所有 Xms 值。
- 比较源 Xms 列表和目标 Xmx 列表中的每个值。
- 如果全部匹配则成功,否则失败。
直观上上面的JSON可以映射到对应的object为:
- 测试
- 检查
- 资源
现在理想情况下,我知道我应该执行以下步骤:
- 运行 所有测试,以及每个测试中的所有检查。
- 对于每个测试,如果类型是比较
- 读取并计算 'dynamic' 个值
- 读取'source'并替换属性字段中的动态值并获取相应的属性
- 同样读取'target'并获取相应的属性
- 比较 return 'PASSED' 或 'FAILED'
大体上我有这些步骤:
- 获取并存储值。
- 比较值
我也想按以下格式打印日志。
[<TIMESTAMP> <RUN-NAME> <TEST-NAME> <CHECK-NAME> <ERROR-LEVEL> <MESSAGE-TYPE> <RESOURCE-NAME>] custom-msg
其中
ERROR-TYPE: INFO DEBUG etc
MESSAGE-TYPE: COMPARE, SYNATAX-ERROR, MISSING-PROPERTY etc
现在如果我遵循上面的 object 模型,并且每个 object 负责处理它自己的日志记录,它就不会拥有所有这些信息。所以我需要:
- 将此信息传递给 child object,
- 或让parent读取childobject的信息。
我更喜欢第二种方法,因为这样我就可以存储获取的结果并将日志记录(如果有的话)延迟到比较之后。通过这种方式,我还可以 运行 验证(unit-tests),因为我也验证错误消息(负面情况)。
但这就是我的解决方案变得复杂的地方。
- 我需要在每个object中存放fetch的结果,可以是找到的值,也可以是没有找到值的'None'。现在我还需要在找不到值时存储错误类型和错误消息。让我们称之为 class 值。
- 每个 属性 都可以产生一个这样的值的列表。
- 每个资源都可以生成这样的列表 属性。
- 每个检查都可以生成此类资源的列表。
注意:这是在 Python 中开发的。 (如果这对你很重要。)
每个 class 都应该对自己的状态负责。当您让 classes 根据其他 classes 中的属性做出决定时,您最终会得到意大利面条代码。
类似 if (test.check.resource.AProperty == aValue)
的代码清楚地表明您的意大利面已经开始烹饪了。
在这种情况下,您希望在 classes 中完全登录。您想要确定一系列操作是否成功完成。 因此,您想记录结果。
考虑到这一点,根本不要让 classes 记录,而只报告他们 tested/checked 的内容及其结果。
一种常见的方法是提供用于接收结果的上下文对象。
这里有一些 C# 代码来说明(我不太了解 python):
interface VerifierContext
{
void AddSuccess(string checkName, string resourceName, string message);
void AddFailure(string checkName, string resourceName, SomeEnum failureType, string message);
}
public class SomeChecker
{
public void Validate(VerifierContext context)
{
context.AddFailure("CompanyNameLength", "cluster.Company", SomeEnum.LengthRestriction, "Company name was 30chars, can only be 10");
}
}
这将为您提供一个简单的验证列表。如果你想嵌套,你可以添加 Enter/Exit 方法:
public class SomeChecker
{
public void Validate(VerifierContext context)
{
context.Enter("CompanyValidations");
foreach (var validator in _childValidators)
validator.Validate(context);
context.Exit("CompanyValidations");
}
}
你当然可以用很多不同的方式来设计它。我的主要观点是,您 check/parser 中的每个 class 都应该决定一切是否正常。它不应该决定应该如何记录事情。
触发工作的 class 然后可以遍历所有结果并根据错误类型等选择日志级别
所有 class 也很容易测试,因为它们仅取决于上下文。