跨层收集数据以编写审计日志
Gather data across layers for writing audit logs
背景
有问题的应用程序是部署在 Tomcat 中的 Java 网络应用程序,并使用 Apache CXF 公开 REST 服务。我找到了 Spring 配置,但不确定它与 CXF 基础设施的连接情况。
每次发生重要事情时,例如更新或删除实体,我想记录的信息包括(但不限于):
- 发生了什么事
- 谁提出了请求
- 更改了什么实体
- 实体的新状态(如果适用)
- 有关发送的任何通知电子邮件的信息
- 等...
当前设置和挑战
我们有几个层,调用如下所示:Controller > Service > Data Layer > Utils(电子邮件、SMS 发送等...)。
问题是,我想要收集和记录的数据开始可用,并且仅在单独的层中可用。有时数据通过参数传递到下一层,但有时它们不会传递,因为其他层不需要数据。以下是一些示例:
- 一些与HTTP请求相关的数据仅用于一些验证,不会发送到服务层。
- 有时,核心实体数据仅在服务层和数据层可用,控制器不可用。
- Utils 的各个层生成一些其他层不知道的最终数据(如链接、代码、最终电子邮件内容)。
但我需要从所有层收集此类信息并将它们记录为单个日志行以供审计。
约束条件
- 代码在尊重层边界方面设计不佳。所以,有时事情会在不应该的地方传递。但是我不能继续这样做了。
- 我不能return所有需要的数据到控制器并最终将它们记录在那里,因为中间层的方法在很多地方被调用,并且重构它们是不切实际的。
- 我不能将它们分别记录在不同的地方,因为要求不允许这样做。如果没有任何其他方式,我可以推动这个策略并有一个共同的请求 ID 或其他东西和多个日志行,以关联它们。
我的问题是,我应该如何以及在哪里收集所有这些数据并将它们写入审计日志?在 Java 网络应用程序中执行上述操作的最佳做法是什么?
听起来你的应用程序一团糟。
不过,只要一切都是基于请求触发的,就应该仍然可以执行此操作。
这里有两种方法:
1) 使用日志框架(如 Logback)中的 MDC 对象。这个对象可以在请求的基础上用键填充,你可以在其中附加任意信息,这些信息可以在以后提取用于日志记录(或者它可以作为附加字段自动附加到你的日志消息中)。在这里阅读:https://logback.qos.ch/manual/mdc.html
这将是我推荐的解决方案,因为它非常符合您要实现的目标。如果那不可能,那么:
2) 创建一个可以静态访问 ThreadLocal 的对象,您可以使用该对象跟踪各个层的信息。请求完成时将其记录在 HTTP 过滤器中。并确保再次清除信息,以免与使用同一线程的下一个请求混淆。
如果您不想用审计日志记录污染您的代码,您可以考虑使用 Aspects(面向方面的编程)将此功能添加到您的 类。
背景
有问题的应用程序是部署在 Tomcat 中的 Java 网络应用程序,并使用 Apache CXF 公开 REST 服务。我找到了 Spring 配置,但不确定它与 CXF 基础设施的连接情况。
每次发生重要事情时,例如更新或删除实体,我想记录的信息包括(但不限于):
- 发生了什么事
- 谁提出了请求
- 更改了什么实体
- 实体的新状态(如果适用)
- 有关发送的任何通知电子邮件的信息
- 等...
当前设置和挑战
我们有几个层,调用如下所示:Controller > Service > Data Layer > Utils(电子邮件、SMS 发送等...)。
问题是,我想要收集和记录的数据开始可用,并且仅在单独的层中可用。有时数据通过参数传递到下一层,但有时它们不会传递,因为其他层不需要数据。以下是一些示例:
- 一些与HTTP请求相关的数据仅用于一些验证,不会发送到服务层。
- 有时,核心实体数据仅在服务层和数据层可用,控制器不可用。
- Utils 的各个层生成一些其他层不知道的最终数据(如链接、代码、最终电子邮件内容)。
但我需要从所有层收集此类信息并将它们记录为单个日志行以供审计。
约束条件
- 代码在尊重层边界方面设计不佳。所以,有时事情会在不应该的地方传递。但是我不能继续这样做了。
- 我不能return所有需要的数据到控制器并最终将它们记录在那里,因为中间层的方法在很多地方被调用,并且重构它们是不切实际的。
- 我不能将它们分别记录在不同的地方,因为要求不允许这样做。如果没有任何其他方式,我可以推动这个策略并有一个共同的请求 ID 或其他东西和多个日志行,以关联它们。
我的问题是,我应该如何以及在哪里收集所有这些数据并将它们写入审计日志?在 Java 网络应用程序中执行上述操作的最佳做法是什么?
听起来你的应用程序一团糟。
不过,只要一切都是基于请求触发的,就应该仍然可以执行此操作。
这里有两种方法:
1) 使用日志框架(如 Logback)中的 MDC 对象。这个对象可以在请求的基础上用键填充,你可以在其中附加任意信息,这些信息可以在以后提取用于日志记录(或者它可以作为附加字段自动附加到你的日志消息中)。在这里阅读:https://logback.qos.ch/manual/mdc.html
这将是我推荐的解决方案,因为它非常符合您要实现的目标。如果那不可能,那么:
2) 创建一个可以静态访问 ThreadLocal 的对象,您可以使用该对象跟踪各个层的信息。请求完成时将其记录在 HTTP 过滤器中。并确保再次清除信息,以免与使用同一线程的下一个请求混淆。
如果您不想用审计日志记录污染您的代码,您可以考虑使用 Aspects(面向方面的编程)将此功能添加到您的 类。