应用输出日志格式规范

93 阅读9分钟

一、文档说明

随着业务发展,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收录字段类型用途格式或要求
timestampstringdate记录该行日志的生成时间格式见“注1”
msgstringtext存储通用日志明细内容,可使用ES分词查询,推荐使用text类型。要求见“注2”
messagejson按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中的保留字段名称,不得在应用日志中使用,以免影响日志收录

字段名字段类型用途
messagestringfilebeat收集时自带字段名,index按json拆分后,改字段就删除
typestring日志采集附加字段
tagsstringlogstash附加字段
sourcestring原始日志文件名
offsetlongfilebeat采集日志偏移量
fieldsobject应用主机IP、所在单元等信息
levelstring日志级别
@timestampdateFilebeat 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"}}

注意点:

  1. 脱敏针对消费者用户的电话和住址;
  2. 门店等信息,不在强制范围中;
  3. 敏感数据应该放入以上结构体中才能实现脱敏。
  4. 手机号和地址中只要有一个项出现 * 作为脱敏标记,就算验证通过。



五、日志字段格式整理

为统一两站ELK的查询逻辑,将开发等用户们关注的字段整理到如下表格中,并且提前设置数据格式(日志采集之前),特定的数据格式有对应的检索方式。如果表格中涉及的字段由于数据格式冲突导致日志收录缺失,需要走工单处理。

注意:

不允许应用或者开发私自修改应用日志字段。不论是增加字段、还是删除字段、或者是修改字段的数据格式,都是不允许私自修改,所有的日志字段修改必须通知到DBA。

由于未通知给DBA的私自修改导致日志收录失败,请提交工单说明情况。




六、flink的逻辑处理与API文档




七、日志接入方式

  1. starters包 略

  2. VM部署的应用,通过采集器

  3. 应用自己直推kafka




八、日志检索的时间排序问题

对接starter包的应用,关于日志生成时间的字段timestamp

  1. 如果默认使用starter默认的pattern,则是会自动打上timestamp字段作为日志生成时间;
  2. 开发选择自定义pattern,starter的标准中只是建议开发自己增加该字段,实际中开发自己增加。