openresty+mysql+乱码_openresty记录响应body乱码问题

问题背景

最近新上了一个功能,openresty通过syslog记录请求日志,然后由logstash推送至ES。测试上线时未发现这个问题,在日常查看日志的过程中,发现logstash推送有错误日志,错误内容为:Error parsing json,导致此条请求日志丢失。

排查过程

1、在syslog中查找出现rror parsing json的日志,日志内容为:

{"request": {},"api": {},"upstream_uri": "","response": {"body": " \b }Ϋٰ ȿ¢³H K>-¤ZŨw c¸±H½񨻴¥𼰮ѝ:h٥lQ¶܊ 𩥹\/𢦫A骩£𐵽I§Heƣ J¥ª y\bYHɬ 晲̼.^¢~&Ԗ< Ŝu0004³P v߯𜱽2򣹩9 §𛳰004YRL0Üse񛳰018yׂ򉛵000f ÿ D\b\\ì蛵0006ƞ󛳰018Ġ`OEѐ𶛵001d㐵 y´§ ꨜu0017~~И雿쮺]-¨ 򛛲LH󿶌kl ࢇcL\n{¦ G~׮gy Keą±؜u0002L3\bG@¨#U¾ :Ŧ ,QL¹(=»{ӓ{mm¶[\/7!&c?ժ łcH vxXLu Ǚ¹_ǃ̢򣹽g>U¶سL-Pò𤦡¾Мu001c2¸\f¿OnGŧ⠑矸 I0k̾lЇ¶.龧d0븳 q 򶪰 K7d\t׬ō ^­A±%ͨ G¥J]a˜u0016 ƹ�g 擁E5®4[*-¨£\f傜u0012T©+̖៊8r¬iEivn\r»噠 ±ቃྊ;󳮰07¨;_n% ","headers": {"content-type": "text\/plain;charset=UTF-8","date": "Wed, 02 Jan 2019 05:34:43 GMT","connection": "close","x-ratelimit-limit-second": "700","vary": "Accept-Encoding","content-encoding": "gzip","via": "kong\/0.14.0","x-kong-proxy-latency": "4","x-ratelimit-remaining-second": "699","transfer-encoding": "chunked","x-kong-upstream-latency": "2","x-kong-upstream-status": "200","server": "nginx"},"status": 200,"size": "1012"},"started_at": 1546407283066}

大家可以看到response.body是乱码,response.body记录的是请求相应的内容把这一段json进行json校验,也会发现有问题。

2、尝试调用该接口,发现返回的是正常内容,但是记录的确是乱码,所以确定应该是openresty记录日志的时候出现了问题。目前我们是在openresty的log阶段进行日志记录,且针对chunked编码进行了处理(如果body大于1k则不进行记录)。日志记录的代码如下:

functionbody_filter()local headers =ngx.resp.get_headers()if headers['content-type'] and then

if string.find(headers['content-type'], "application/json") or string.find(headers['content-type'], "text/plain") then

local chunk = ngx.arg[1] or ""

if string.len(ngx.ctx.response_temp or "") < max_body_size thenngx.ctx.response_temp= (ngx.ctx.response_temp or "").. chunk

ngx.ctx.response_body=ngx.ctx.response_tempelsengx.ctx.response_body= ""

end

end

end

end

3、想通过在测试环境加一些日志,然后调用线上的接口进行排查问题,由于线上的接口做了IP限制,测试环境调不通,此方法作罢。

4、让接口方把线上的数据拷贝至测试环境,然后调用此接口,但是日志记录也是正常的,没有出现乱码。

5、由于不能重现问题,在测试环境排查很难继续下去。最后没办法,只能献出终极武器,抓包。

6、通过tcpdump -Xvvenn -iany -w /tmp/20181228.pcap net [ip] and net [ip] and port [port]在线上服务器上抓包,然后下载pcap文件用wireshark进行分析,找到出问题的请求,如下图:

a1034069cd0732a95f04fa3010b07989.png

通过我标红的地方可以很清楚的看到,响应数据是通过gzip压缩的,而我们日志记录中没有任何解压缩的处理,所以日志记录的时候就会出现上述的情况。

问题总结

最后解决方式是如果响应body如果进行了压缩,我们默认不记录响应body。

这个问题从出现到最终解决前前后后经历了两三天,解决完了会发现这个问题其实很简单,从最早的日志里其实也有蛛丝马迹(如第一个代码片段中标红的地方),但你其实想不到。所以也给了我很深的感悟:

1、一定要想方设法的重现问题,不然很多时候你可能就无从下手。

2、网络这一门技术确实太重要了,如果这次不进行抓包分析,可能还得绞尽脑汁想别的方法。记得上一次nginx的问题也是通过抓包分析问题的,所以这一利器一定要掌握。

写这篇文章的主要目的是记录一下自己的排查过程(很多细节可能描述的不是很清楚),通过这种方式让自己不断优化自己解决问题的思路,让以后的日子里没有难解的bug。^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312269.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Azure学习.01】先从账号注册开始

本文部分内容配套视频&#xff1a;https://www.bilibili.com/video/av82898957马上要放假了&#xff0c;决定在家里简单了解一下Azure云服务&#xff0c;虽然公司其他部分用到了这个Azure&#xff0c;但是我还是没有接触到&#xff0c;只是听说很贵&#xff0c;好几千每天&…

C++vector容器-插入和删除

vector插入和删除 功能描述&#xff1a; 对vector容器进行插入&#xff0c;删除操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector> //vector插入和删除void printVector(vector<int > &v…

C++vector容器-数据存取

vector数据存取 功能描述&#xff1a; 对vector中的数据的存取操作 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <vector>//vector容器 数据存取 void test01() {vector<int >v1;for (int i 0; i &l…

如何快速融入团队(四)

作者&#xff1a;邹溪源&#xff0c;长沙资深互联网从业者&#xff0c;架构师社区特邀嘉宾&#xff01;01不知不觉这个系列已经开始第四篇的&#xff0c;其实我的原始意图只是思考一下如果有幸加入一个新团队&#xff0c;我们在思想和行动上该做哪些准备呢。不过随着内容的逐渐…

C++vector容器-互换容器

vector容器互换 功能描述&#xff1a; 实现两个容器内元素进行互换 函数原型&#xff1a; swap(vec);//将vec与本身的元素互换 1.基本使用 代码如下: #include <iostream> using namespace std; //vector容器互换 #include <vector> //1.基本使用void printVect…

.NET 状态机Automatonymous快速入门

介绍 Automatonymous是.NET开发人员的状态机库。它提供了一种流畅的语法来声明状态机&#xff0c;包括状态&#xff0c;事件&#xff08;支持触发器和数据事件&#xff09;以及状态/事件活动。尽管Automatonymous在简单的状态机上非常容易使用&#xff0c;但它具有许多高级功能…

BeetleX实现HTTP协议详解

在传统网络服务中扩展中需要处理Bytes来进行协议的读写&#xff0c;这种原始的处理方式让工作变得相当繁琐复杂&#xff0c;出错和调试的工作量都非常大&#xff1b;组件为了解决这一问题引用Stream读写方式&#xff0c;这种方式可以极大的简化网络协议读写的工作量&#xff0c…

euclidea4攻略_Euclidea几何构建11.4通关攻略

Euclidea几何构建10.2通关攻略Euclidea游戏10.2怎么过&#xff1f;下面小编为大家带来Euclidea几何构建10.2通关攻略&#xff1a;更多攻略不断更新中——Euclidea游戏全关卡通关攻略大全分两次做图第一次&#xff0c;画圆就成了&#xff0c;具体看图应该能懂。第二次&#xff0…

C++set容器-构造和赋值

set基本概念 简介&#xff1a; 所有元素都会自动在插入时自动被排序&#xff0c;set容器也叫集合容器 本质&#xff1a; set/multiset属于关联式容器&#xff0c;底层结构是用二叉树排序 set和multiset区别&#xff1a; 1.set不允许容器中有重复的元素 2.multiset允许容器中有…

(1)解锁MongoDB replica set核心姿势

本文倒腾目前大热的MongoDB Replica Set集群&#xff0c;在倒腾的同时串讲一些 MongoDB特性。 副本集Replica Set是一个术语&#xff0c;定义具有多节点的数据库集群&#xff0c;这些节点具有主从复制(master-slave replication) 且节点之间实现了自动故障转移。 这样的结构通常…

java写dnf外掛_dnf卡盟_Java的泛型详解(一)

Java实现DDD中UnitOfWorkdnf卡盟Java的泛型详解泛型的利益编写的代码可以被差别类型的工具所重用。由于上面的一个优点&#xff0c;泛型也可以削减代码的编写。泛型的使用简朴泛型类public class Pair {private T first;private T second;public Pair() {first null;second n…

C++set容器-大小和交换

set大小和交换 功能描述&#xff1a; 统计set容器大小以及交换set容器 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <set> //set容器 大小和容器void printSet(set<int > &s) {for (set<int …

Asp.Net Core下的开源任务调度平台ScheduleMaster—快速上手

概述ScheduleMaster是一个开源的分布式任务调度系统&#xff0c;它基于Asp.Net Core平台构建&#xff0c;支持跨平台多节点部署运行。它的项目主页在这里&#xff1a;https://github.com/hey-hoho/ScheduleMasterCore关于它的简单介绍可以看这里&#xff1a;https://www.cnblog…

C++set容器-插入和删除

set插入和删除 功能描述&#xff1a; set容器进行插入数据和删除数据 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <set>void printSet(set<int > &s) {for (set<int >::iterator it s.be…

基于Jenkins的持续交付全流程设计与实践

1 从理论开始什么是DevOps?近年来&#xff0c;随着DevOps理念的逐渐深入人心&#xff0c;企业逐渐意识到从看似重复的手工劳动中实现自动化流程处理&#xff0c;对于提高企业劳动生产力已经非常重要&#xff0c;尤其是面向互联网的开发者&#xff0c;往往每次上线时&#xff0…

C++set容器-查找和统计

set查找和统计 功能描述&#xff1a; 对set容器进行查找数据以及统计数据 函数原型&#xff1a; 代码如下: #include <iostream> using namespace std; #include <set>//set查找和统计void test01() {//查找set<int >s1;//插入数据s1.insert(10);s1.inse…

C++set和multiset区别

区别&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <set>//set容器 和multiset容器的区别 void test01() {set<int >s;pair<set<int >::iterator, bool> ret s.insert(10);if (ret.second) {cout &…

.NET CORE(C#) WPF简单菜单MVVM绑定

阅读导航 本文背景 代码实现 本文参考 源码 1. 本文背景 WPF中垂直导航菜单大家应该都常用&#xff0c;本文介绍使用MVVM的方式怎么绑定菜单&#xff0c;真的很简单。 2. 代码实现 使用 .Net Core 3.1 创建名为 “MenuMVVM” 的WPF模板项目&#xff0c;添加两个Nuget库&…

C++pair对组的创建

pair对组创建 功能描述&#xff1a; 成对出现的数据&#xff0c;利用对组可以返回两个数据 两种创建方式&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>void test01() {//第一种方式pair<string, int>…

避免在 ASP.NET Core 3.0 中为启动类注入服务

本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇。 Part 1 - 将.NET Standard 2.0 类库转换为.NET Core 3.0 类库 Part 2 - IHostingEnvironment VS IHostEnvironent - .NET Core 3.0 中的废弃类型 Part 3 - 避免在 ASP.NET Core 3.0 中为启动类注入服务&#xff08;本篇&…