手机版

将节点框架连接到ELK的实践总结

时间:2021-08-27 来源:互联网 编辑:宝哥软件园 浏览:

我们都有用机器检查日志的经验。当集群数量增加时,这种原始操作带来的低效率不仅给我们定位现有网络带来了巨大的挑战,而且我们无法对服务框架的指标进行有效的量化诊断,更不用说对其进行优化和改进了。此时,构建一个具有信息搜索、服务诊断、数据分析等功能的实时日志监控系统就显得尤为重要。

Elk (elkstack : elastic search,log stash,kibana,beats)是成熟的日志解决方案,其开源性和高性能在各大公司得到广泛应用。我们业务使用的服务框架如何访问ELK系统?

工作经历

我们的业务框架背景:

业务框架是基于NodeJs的WebServer服务,使用winston日志模块将日志本地化服务生成的日志存储在各自机器的磁盘上。这些服务部署在不同地区的多台机器上。我们简单地将整个框架总结为如下步骤:

日志结构设计:将传统的纯文本日志改为结构化对象,输出为JSON。日志收集:在框架请求生命周期的一些关键节点输出日志es索引模板定义:建立从JSON到ES实际存储的映射一、日志结构设计

传统上,当我们进行日志输出时,我们直接输出日志级别和日志内容字符串。但是,我们不仅要关注什么时候发生了什么,还要关注类似的日志发生了多少次,日志的细节和上下文,以及关联的日志。因此,我们不仅简单地将日志构造为一个对象,而且提取日志的关键字段。

1.将日志抽象成事件

我们将每个日志的出现视为一个事件。事件包括:

事件元字段

事件发生时间:datetime,timestamp事件级别:level,例如: ERROR,INFO,WARNING,DEBUG事件名称3360event,例如client-request事件发生的相对时间(单位:纳秒):reqLife,此字段是事件相对于请求开始发生的时间(间隔),事件的位置是3360line,代码位置;服务器,服务器的位置请求元字段

请求唯一id是:req id。此字段贯穿整个请求链接上发生的所有事件,并请求用户ID: reqUid。此字段是用户id,可以跟踪用户的访问或请求链接数据字段。

不同类型的事件有不同的输出细节,所以我们把这些细节(非元字段)放在d - data中。它使我们的事件结构更加清晰,同时可以避免数据字段污染元字段。

例如client-init事件,每次服务器收到用户的请求时都会打印出来,我们将用户的ip、url和其他事件的唯一统一分类为数据字段,并将它们放在d对象中

举一个完整的例子

{ ' datetime ' : ' 2018-11-07 21:38336009.271 ',' timestamp':1541597889271,' level':'INFO ',' event':'client-init ',' reqId':'rJtT5we6Q ',' reqLife ' :5874,' reqUid ' : '英特尔Mac OS X 10 _ 14 _ 0)applebwebkit/537.36(KHTML,像Gecko)Chrome/70 . 0 . 3538 . 77 Safari/537.36 ',' headers':'* ',' browser ' : ' { name ' : ' Chrome ',' version ' : ' 70 . 3538 . 77 ',' major':'70'},' engine ' :在实际输出中,我们将深度大于1的值作为字符串输出。有时候有些对象字段是我们关心的,所以我们把这些特殊的字段放在外层,保证输出深度不大于2。一般我们打印日志的时候,只需要注意事件名称和数据字段。此外,我们可以通过统一访问上下文来获取、计算和输出日志。

2.日志转换输出

我们之前提到了如何定义一个日志事件,那么如何在现有日志方案的基础上进行升级,同时兼容旧代码的日志调用方式呢?

关键节点升级日志

//转换前的logger . info(' client-init=' JSON . stringfiy({ URL,IP,浏览器,//.}));//修改了logger . info({ event : ' client-init ',URL,IP,浏览器,//.});与旧的日志调用方法兼容

logger . debug(' checklog in ');Winston的log方法本身支持字符串或对象的传入模式,因此格式化程序实际上接收{level:' debug '、message3360' checklogin'}用于字符串的旧传入写入。Formatter是在winston的日志输出之前调整日志格式的一个过程,它让我们有机会将这个调用模式输出的日志转换为纯输出事件--我们称之为原始日志事件,而不修改调用模式。

转换日志输出格式

如前所述,winston将在输出日志之前通过我们预定义的格式化程序,因此除了处理兼容的逻辑之外,我们还可以在这里放置一些通用的逻辑进行处理。打电话的时候,我们只关注场本身。

元字段提取和处理字段长度控制如何通过兼容的逻辑处理提取元字段,这涉及到上下文的创建和使用。这里,我们简单介绍一下域的创建和使用。

//-middleware/http-context . jsconst domain=require(' domain ');const short id=require(' short id ');module.exports=(req,res,next)={ const d=domain . create();d . id=short id . generate();//ReQid;d.req=req//.res.on('finish ',()=process . nexttick(()={ d . id=null;d.req=nulld . exit();});d . run()=next());}///-app . jsapp . use(require('。/middleware/http-context . js’);//-formatter . jsif(process . domain){ ReQid=process . domain . id;}这样,我们就可以将reqId输出到一个请求中的所有事件,从而达到关联事件的目的。

二、日志收集

既然我们知道了如何输出事件,我们应该在下一步考虑两个问题:

我们在哪里输出事件?事件应该输出哪些细节?换句话说,整个请求链路中哪些节点是我们关心的,如果出现问题,可以利用哪些节点信息快速定位问题?另外,我们可以通过哪些节点的数据做统计分析?

结合常见的请求链接(用户请求、服务端接收请求、服务请求下游服务器/数据库(*多次)、数据聚合渲染、服务响应),如下流程图所示

流程图

然后,我们可以定义我们的事件如下:

用户请求

Client-init:打印框架收到的请求(未解析),包括:请求地址、请求头、Http版本和方法、用户IP和浏览器client-request:打印框架收到的请求(已解析),包括:请求地址、请求头、Cookie、请求包client-response:打印框架中的返回请求,包括:请求地址、响应。

Http-start:打印在请求的下游:请求地址、请求数据包正文、模块别名(便于名称聚合和域名)http-success:打印在请求返回200:请求地址、请求数据包正文、响应数据包正文(代码msg data),耗时http-error:打印在请求返回non-200,即连接到服务器失败:请求地址、请求。Http-timeout:打印在请求连接超时:请求地址、请求数据包正文、响应数据包正文(代码msg stack)上,这需要时间。领域这么多,怎么选?总之,事件输出的字段原理就是输出你关注的字段,方便检索和后期聚合。一些建议

请求体和请求下游的返回体具有固定格式,例如输入:{action:' getuserinfo ',有效负载3360 {}}输出: {code3360 0,msg: ' ',data: {}}我们可以输出操作、代码等。以便我们可以在以后通过操作检索特定的模块。

一些原则

确保输出字段的类型一致。由于所有事件都存储在同一个ES索引中,因此无论是同一事件还是不同事件,同一个字段都应该是一致的。例如,代码不应该既是数字又是字符串,这可能会导致字段冲突,导致一些文档无法被冲突的字段检索到。es存储类型为关键字,不应超过ES映射设置的ignore _ above中指定的字节数(默认为4096字节)。否则,也可能无法检索。3.专家系统索引模板定义

本文介绍了专家系统的两个概念:映射和模板。

首先,es的基本存储类型如下

字符串:关键字文本数字:长整型双日期:日期布尔值:布尔值。通常,我们不需要为每个事件字段显示与ES对应的存储类型。ES将根据该字段在文档中第一次出现的值,自动确定该字段在该索引中的存储类型。但有时,我们需要显示某些字段的存储类型。此时,我们需要定义这个索引的Mapping来告诉ES如何存储和索引这个字段。

例如

还记得事件元字段之一是时间戳吗?实际上,当我们输出时,时间戳的值是一个数字,它指示从1970/01/01 00:00:00的毫秒数,并且我们期望当es存储类型是date时,它方便以后的检索和可视化,所以当我们创建索引时,我们指定我们的Mapping。

putmy _ logs { ' mappings ' : { ' _ doc ' : { ' properties ' : { ' title ' : { ' type ' : ' date ',' format' :' epoch _ millis'},}}我们可能会按日期自动生成我们的日志索引,假设我们的索引名称的格式是my _ logs _ yyyymmdd(例如my _ logs _ 20181030)。然后我们需要定义一个模板,当创建(匹配的)索引时,它将自动应用预设的映射。

PUT _ template/my _ logs _ template { ' index _ patterns ' : ' my _ logs * ',Mapping ' : { ' _ doc ' : { ' properties ' : { ' title ' : { ' type ' : ' date ',' format' :' epoch _ millis'},}}提示:在所有日期生成的日志将为Summary

至此,日志修改和访问的准备工作已经完成,我们只需要在机器上安装一个轻量级的文件日志代理FileBeat,负责将日志文件中的日志传输给ELK。接下来,我们可以使用基巴纳快速检索我们的日志。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:将节点框架连接到ELK的实践总结是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。