最后更新于2021年12月20日(星期一)18:51:36 GMT

仔细想想,日志条目实际上只不过是描述事件的消息. 因此,利用消息传递技术采用基于消息的方法进行日志记录是有意义的. 消息传递创建了松耦合,使日志系统能够适应当前的需求并随着时间的推移进行扩展.

理解标准日志体系结构

通常,日志记录是在应用程序中使用 logger. 日志记录器是将日志条目数据发送到目标目的地的对象或组件. 将记录器绑定到一个或多个目标是通过记录器配置完成的. The target can be a file, database, logging service, or depending on the logger technology, all of the above. Log4J是Java编程中最流行的日志记录器,它允许您配置多个日志 appenders 到记录器,每个附加程序专用于一个特定的目标. The same is true of Winston, a popular logger for Node.JS.

图1:大多数记录器允许应用程序向多个目标发送日志条目.

在基于应用程序的日志记录方面,需要理解的重要一点是,应用程序向日志记录器提交日志条目,然后日志记录器将其转发到一个或多个目标. 每个目标如何处理日志条目是它自己关心的问题.

日志记录器是一种可靠的、众所周知的日志记录方式. However, there is a drawback. 假设您必须向记录器添加一个额外的目标, 例如,使用SMS将日志条目发送到移动电话的目标.

添加新目标意味着必须部署appender以及更新和重新部署日志记录器配置文件, at the very least. 您可能需要让整个应用程序脱机才能部署新的日志记录功能.

Is there a way to avoid the problem? 是的,使用基于消息的方法进行日志记录.

采用基于消息的方法进行日志记录

正如本文开头所提到的,日志条目基本上是一条消息. 在使用基于目标的日志程序(如Log4J)的情况下, 应用程序将日志条目发送给日志记录器,日志记录器有必要格式化该日志条目并将其发送到不同的目标. However, 这种场景的局限性在于,记录器需要在开始时就知道正在运行的各种目标. 部署logger后,添加目标器比较困难.

By taking a message-based approach, 您可以避免在添加新目标时摆弄应用程序的日志记录器. 事实上,“目标”的概念完全消失了,取而代之的是订阅者的概念.

图2显示了一个简单的基于消息的日志记录体系结构 pub-sub pattern.

图2:将日志消息发送到中央交换机允许使用者根据需要连接到日志流.

In a message-based approach, 日志记录器将日志条目作为消息发送给单个目标, a Message Broker. 消息代理发布一个入口点,通常是一个HTTP URL,该URL将消息作为对象接受 POST request. 从概念上讲,端点是一个交换, 收集消息并将其分发给感兴趣的各方的地方. Amazon Simple Notification Services对交换使用的术语是a topic. RabbitMQ另一种流行的通讯技术使用了这个词 exchange.

使用交换的好处是一个或多个订阅者可以绑定到它并接收发送的任何消息的副本. This is the basis of the publish-subscribe pattern or pub-sub, for short. 使用“发布-订阅”体系结构意味着稍后上线的订阅者可以绑定到交换机.k.发布者,并获取可用于其自身目的的消息.

Thus, 回到前面描述的晚绑定SMS功能场景, 要支持接受日志条目并将其作为SMS转发,所需要做的就是创建一个知道如何将日志消息转换为SMS格式然后发送它们的订阅者. 创建订阅者后,将其绑定到发布者. 绑定后,订阅者将收到发送给发布者的消息的副本. 大多数发布者技术都能够将消息持续发送给订阅者一定次数,直到消息被接受为止. 无法传递的消息会被发布者注意到.

是否应该在以后确定不再需要SMS用户, 停用订阅服务器只需将其与发布者断开连接即可. 不需要调整发布器中的代码. 日志记录继续在应用程序中畅通无阻地进行.

消息驱动的日志架构的好处是它提供了很大的灵活性. 您可以让订阅者将消息转发到标准日志服务,例如 InsightOps, to database services such as AWS DynamoDB, or to a file out on Azure. 您的应用程序不需要知道最终目标. 应用程序只知道它将日志条目发送到一个目标,即发布者.

基于消息的日志记录对你的公司有意义吗?

实现基于消息的日志记录方法并不适合所有人. First, 如果您的公司还没有适当的消息传递体系结构, 它需要有实施这一计划的专门知识和能力. You can use a cloud service such as AWS SNS/SQS, Azure Service Bus, or Google Pub-Sub. 此外,您还可以采用基于服务器的方法,使用行业标准消息传递产品,例如 RabbitMQ or Apache’s Kafka. Regardless of the approach you take, 您的公司需要投入精力和资源来实现和支持消息传递框架.

其次,发送给发布者的所有物理消息都需要遵循常规格式. As the name implies, 实现基于消息的体系结构的核心是理解所有发出的日志数据都采用消息的形式. Any message can end up anywhere. Thus, 您不希望发送需要大量预定义知识才能破译的消息. 你需要有一个常规的信息格式, self-describing, and extensible.

下面的清单1显示了一个非自描述的消息示例.

"My Cool App","ip: "10.1.241.116”、“log_event”、“信息”、“保存数据”、“{“名称”:\“鲍勃\”,\“\”,\“酷\“}”

上面显示的消息的语义是未知的. 你需要一个外界的参考来破译它. As a result, 编写解析算法来理解消息是一项耗时的工作, 特定于给定的消息格式. 而不是使用自定义消息格式, it’s better to use a conventional, self-describing format such as JSON, XML, or YAML. 自描述消息易于理解和解析. Using a conventional, 自描述格式避免了在设计订阅者时需要“部落知识”来弄清楚日志条目语义的危险, 特别是当消费消息的订阅者在发布者投入使用几个月后绑定到发布者时.

清单2显示了一个自描述的消息. 它是JSON格式,因此可以按照惯例清楚地理解.

{
    "source": "My Cool App",
    "ip": "10.1.241.116",
    "time": "星期五Feb 28 07:25:25 UTC 2016",
    "type": "log_event",
    "body": {
        "level": "INFO",
        "message": "Saving data",
        "data": {"name": "Bob", "status": "cool"}
    }
}

具有使用基于消息的体系结构的历史的组织理解使用常规格式构造消息的价值. 您希望拥有一个可以在任何时间使用任何消息的环境, by any subscriber, 以一种标准化和准确的方式. 企业并非生来就具备这种能力. They need to develop them. 如果你的公司愿意承担这样的任务,你会做得很好. 如果没有,最好还是坚持使用当前的日志记录方法.

Putting It All Together

采用基于消息的方法进行日志记录具有明确的好处. 您可以在应用程序生命周期的任何时间向任何感兴趣的使用者提供日志信息. Also, 当给定的使用者不再需要日志数据时, 它可以很容易地从日志消息流断开连接.

However, 使用基于消息的方法进行日志记录要求企业有意愿和必要的资金来支持消息传递体系结构. 然而,仅仅有一个消息传递体系结构是不够的. 一旦采用了消息传递体系结构, 从发布者传递到消费者的消息应该遵循易于解析和处理的常规格式.

基于消息的日志记录提供了很大的灵活性. 这种灵活性在需要快速适应不断变化的日志记录需求的动态组织中特别有用. 实现基于消息的日志记录方法可能需要公司对其系统进行日志记录的方式进行一些根本性的更改. 然而,消息传递带来的长期好处使这种努力值得投资.