一、文档说明
随着业务发展,IT系统的规模和复杂度不断上升,elk逐渐显露出性能瓶颈。为了增强elk的可靠性,更好地满足开发分析排障的需求,此次架构改造中,会将ELK整体搬迁至公有云。因此,为配合上云涉及的性能优化和安全合规工作,EC base包进行了日志JSON化及字段脱敏功能的改造。
本文档由运维团队和开发团队共同制定,描述了所有收录至ELK中的应用日志需要遵守的格式规范。该规范旨在:
- 规范日志脱敏相关字段。
- 规范日志的输出信息,统一字段名称,方便日常分析排障。
- 防止日志收录过程中由于格式和字段名冲突等引起的收录问题。
- 规范应用日志字段的变更动作,防止由于日志字段的变化导致日志收录失败。
二、日志字段标准
2.1 日志格式
标准应用日志,应采用JSON格式。具体要求如下:
- 每一行日志均为一个完整的JSON体,符合JSON标准;
- 单条日志内容不跨行。对于多行文本(如Java错误堆栈信息等),应使用
\n编码为单行string后,作为特定JSON字段的值 - 每个应用日志的字段应尽可能保持统一,不随意增减字段,尤其是不随意变换字段的类型;
- 除某些事先约定的JSON字段(如msg)外,每个字段存储的长度不超过256个字符;
- 某个字段出现嵌套json,非特殊原因不做解析拆分,统一按照字符串收录。
2.2 固定字段
日志中的标准字段,及用途说明
| 字段名 | 是否必需 | JSON字段类型 | ES收录字段类型 | 用途 | 格式或要求 |
|---|---|---|---|---|---|
| timestamp | 是 | string | date | 记录该行日志的生成时间 | 格式见“注1” |
| msg | 是 | string | text | 存储通用日志明细内容,可使用ES分词查询,推荐使用text类型。 | 要求见“注2” |
| message | 否 | json | 按json格式拆分后,该字段就删除 | ||
| mid-uh的 currentTime | 当@timestamp字段不存在时,如 mid-uh topic)里的时间来决定写入哪天的 index | - currentTime |
- 类似`yyyy-MM-dd HH:mm:ss,SSS` 格式(默认)- 类似`2023-12-18T14:25:09,361+0800`格式(需要配置 secondary.new.date.format 为 true) |
注1:
timestamp,格式应符合ISO 8601规范。完整格式为:yyyy-MM-ddTHH:mm:ss.SSSZ
例:北京时间2021年6月1日8点整,以下表述均符合规范:
-
"``2021-06-01T08:00:00.000+0``800"# 北京时区(+8) -
"``2021-06-01T00:00:00.000+00``00"# UTC(+0) -
"``2021-06-01T00:00:00.000Z``"# 另一种UTC表示方式
注2:
msg字段和 msg.xxx 字段不能同时出现,因为msg.xxx 会被ES认为是msg字段的子字段。
同时出现会导致msg字段直接被拆分,并且msg在字段不能再有数据写入,否则写入失败。
同样这条规则使用其他字段。二者不可共存。
2.3 脱敏字段
日志中的消费者敏感数据(电话、住址等),应输出至特定字段,方便脱敏模块统一进行脱敏。
| 字段名 | 字段类型 | 描述 |
|---|---|---|
2.4 保留字段名
以下为ELK中的保留字段名称,不得在应用日志中使用,以免影响日志收录
| 字段名 | 字段类型 | 用途 |
|---|---|---|
| message | string | filebeat收集时自带字段名,index按json拆分后,改字段就删除 |
| type | string | 日志采集附加字段 |
| tags | string | logstash附加字段 |
| source | string | 原始日志文件名 |
| offset | long | filebeat采集日志偏移量 |
| fields | object | 应用主机IP、所在单元等信息 |
| level | string | 日志级别 |
| @timestamp | date | Filebeat module 打的时间戳 |
2.5 字段个数限制
为了规避超宽表的问题。对json化的日志,fields字段数量限制在900个以内,多余的字段能整合的先整合。超过900个字段直接被截断丢弃,不会存入ELK。
2.6 日志级别限制
日志优先级别一共分为7等级:
ALL< DEBUG(调试) < INFO(消息) < WARN(警告) < ERROR(错误) < FATAL <OFF 。
为了减轻ELK收集日志的压力,只收录 INFO 级别(包含)以上的日志(如上面标红的字体)。
三、示例
3.1 符合json化的日志用例
{"timestamp":"2022-09-27T15:22:21.514+0800", "module":"menu.service.query", "trace":"8dc8d3cbfbdfed07", "span":" 8dc8d3cbfbdfed07", "thread":"main", "level":"INFO ", "logger":"data", "msg":"拼接的sql: select wordLinkId, brand, tenant, envType, versionId, textCn, textEn, relationType, linkedClassId, linkedUrl, descCn, descEn, textType, parentClassId, startTime, endTime, channelIds, dayOfWeek, holiday, validFrom, validTo, updateTime, menuVersion, iconText, sort, city, market, storeCodes from t_basic_wordlink where brand = 'PHDI_CO' and tenant = '02043'", "secFieldaddress":"晖苑***************", "secFielduserPhone":"182****2060"}
3.2 多行日志样例(\n转义)
ELK收集日志时按行收录,一行日志必须为完整的json。如果出现换行,需要使用\n进行转义。
{"time_local":"13/Apr/2022:21:50:26+0800","http_host":"kfc-vgoldtrade.prd.yumc.local","body_bytes_sent":"93","request_time":0.081,"status":"511","request":"POST/reward/api/rule/reverseHTTP/1.0","request_method":"POST","request_body":"{userCode\n:\n16033618070632131814\n,\nruleCode\n:\n48092f76e07a4eef9ae55951a9999831\n,\norderId\n:\nVG10022089338640830189730\n,\noriginalOrderId\n:\n1649820941555003243\n,\noriginalOrderTime\n:1649821437000,\nscene\n:\nKFC_D\n,\nbrandInfo\n:{\ncorpCode\n:\n210010\n,\nbrandCode\n:\n002\n},\nchannel\n:\n210082\n,\ntimestamp\n:1649857826398,\nsignature\n:\n5063bf54b968f9db07d07ecdd339b114\n"}
3.3 不合规的应用日志举例
{"@timestamp":"2023-08-16T07:29:52.642Z","beat":{"hostname":"kfcp-ordering-api-75f56d6d8b-tszf4","name":"kfcp-ordering-api-75f56d6d8b-tszf4","version":"5.6.16"},"extField":{"sessionId":"9qdKobUrd4bNazuuRGBGJ4svysJKsTWL"},"fields":{"env":"wga","ip":"10.98.58.215"},"input_type":"log","level":"INFO","logger":"Portal","module":"main.portal","msg":"[15:29:52.035]req_url: POST http://172.21.43.241/core.service/v2/menu/menuData host(cache 30):kfcp-api-nsf.prd.yumc.local req_body: {"brand":"KFC_PRE","channelName":"WECHATMINI","channelId":"13_5","clientVersion":"v3.802(7fed8919)","deviceId":"874bc5a7-0ab9-43f8-3ad0-630beb3fbfc1","sessionId":"9qdKobUrd4bNazuuRGBGJ4svysJKsTWL","mylng":"120.15613579644098","mylat":"35.98738145616319","userId":"5c38b2fd-9fb8-433a-8b8c-67d62d46f367_0","store":{"deliveryTime":0,"storecode":"QG1133","storename":"五台山路餐厅 TEL 86720396","address":"青岛市黄岛区五台山路1677号","starttime":"06:00","endtime":"21:00","storeBusinessTime":["06:00-21:00"],"lat":"35.98717","lng":"120.156034","distance":25.214776559676892,"marketcode":"087","cityName":"青岛","gbCityCode":"370200","citycode":"00289","districtcode":"02553","asCity":0,"status":1,"boolBusyStop":false,"takeMealPlace":"店内柜台","typeCode":"H","merchantType":1,"stype":"007","tolerant":0,"shutmaptime":0,"dayParts":[{"dayPartCode":"4","daypart_from":"14:00","daypart_to":"17:00","name":"下午茶"},{"dayPartCode":"2","daypart_from":"10:00","daypart_to":"11:00","name":"正餐"},{"dayPartCode":"1","daypart_from":"06:00","daypart_to":"09:30","name":"早餐"},{"dayPartCode":"8","daypart_from":"09:30","daypart_to":"10:00","name":"早正餐"},{"dayPartCode":"9","daypart_from":"20:00","daypart_to":"21:00","name":"夜宵0"},{"dayPartCode":"5","daypart_from":"17:00","daypart_to":"20:00","name":"晚餐"},{"dayPartCode":"3","daypart_from":"11:00","daypart_to":"14:00","name":"午餐"}]},"openId":"ojBv60LKc8iAUGsIaOrGRawNHSnU","bookingDate":null,"curTime":1692170991949,"callScene":"4","business":"preorder","clientIp":"112.224.154.98"}","offset":73203042,"source":"/opt/log/kfc_pre/main-portal-portal.log","thread":"39","timestamp":"2023-08-16T15:29:52.035","trace":"031985c099f4481b","type":"ec-kfc-preorder-server"}
说明: 从kafka中取出来的message信息,msg中为原始日志,格式为字符串,非json格式。
四、日志脱敏与安全
日志中的消费者敏感数据(电话、住址等),应输出至特定字段,方便脱敏模块统一进行脱敏。
- 脱敏的形式如:
· 手机号:182****2060
· 地址:晖苑***************
- starter包针对如下结构体中的日志进行脱敏:
请求地址:{"secField":{"address":"晖苑***************", "userPhone":"182****2060"}} {},请求体:{"secField":{"address":"晖苑***************", "userPhone":"182****2060"}}
注意点:
- 脱敏针对消费者用户的电话和住址;
- 门店等信息,不在强制范围中;
- 敏感数据应该放入以上结构体中才能实现脱敏。
- 手机号和地址中只要有一个项出现
*作为脱敏标记,就算验证通过。
五、日志字段格式整理
为统一两站ELK的查询逻辑,将开发等用户们关注的字段整理到如下表格中,并且提前设置数据格式(日志采集之前),特定的数据格式有对应的检索方式。如果表格中涉及的字段由于数据格式冲突导致日志收录缺失,需要走工单处理。
略 注意:
不允许应用或者开发私自修改应用日志字段。不论是增加字段、还是删除字段、或者是修改字段的数据格式,都是不允许私自修改,所有的日志字段修改必须通知到DBA。
由于未通知给DBA的私自修改导致日志收录失败,请提交工单说明情况。
六、flink的逻辑处理与API文档
略
七、日志接入方式
-
starters包 略
-
VM部署的应用,通过采集器
-
应用自己直推kafka
八、日志检索的时间排序问题
对接starter包的应用,关于日志生成时间的字段timestamp:
- 如果默认使用starter默认的pattern,则是会自动打上timestamp字段作为日志生成时间;
- 开发选择自定义pattern,starter的标准中只是建议开发自己增加该字段,实际中开发自己增加。