Nginx is awesome, but it’s missing some common features. For instance, a common thing to add to access logs is a unique ID per request, so that you can track the flow of a single request through multiple services. Another thing it’s missing is the ability to log request_time in milliseconds, rather than seconds with a millisecond granularity. Using Lua, we can add these features ourselves.

I’ll show the whole solution, then I’ll break it down into parts:

http {
... map $host $request_time_ms {
default '';
}
map $host $uuid {
default '';
} lua_package_path '/etc/nginx/uuid4.lua';
init_by_lua '
uuid4 = require "uuid4"
math = require "math"
'; log_by_lua '
ngx.var.request_time_ms = math.floor(tonumber(ngx.var.request_time) * 1000)
'; log_format mycustomformat '[$time_local] "$request" $status $request_length $bytes_sent $request_time_ms $uuid';
access_log /var/log/nginx/access.log mycustomformat; ...
} server {
... set_by_lua $uuid '
if ngx.var.http_x_request_id == nil then
return uuid4.getUUID()
else
return ngx.var.http_x_request_id
end
'; ...
}

It’s necessary to set variables before we use them in Lua. Using map is a trick to set variables in the http context (you can’t use set $variable ” in http). For the case of uuid, we are going to set it in the server section (during the rewrite context), but in case it’s not set, we want to avoid throwing errors. Here’s how we set these variables:

        map $host $request_time_ms {
default '';
}
map $host $uuid {
default '';
}

Next we add a uuid4 library to our path, and include the libraries into our context:

        lua_package_path '/etc/nginx/uuid4.lua';
init_by_lua '
uuid4 = require "uuid4"
math = require "math"
';

Using the log_by_lua function, we’ll set the request_time_ms variable we’ll use in the log_format config. This Lua function is called in the log context, before logs are written, allowing us to make the variables available to it:

        log_by_lua '
ngx.var.request_time_ms = math.floor(tonumber(ngx.var.request_time) * 1000)
';

Next we set the log format, and use it for the access log:

        log_format mycustomformat '[$time_local] "$request" $status $request_length $bytes_sent $request_time_ms $uuid';
access_log /var/log/nginx/access.log mycustomformat;

Lastly, we set the uuid during the rewrite context in the server section, using set_by_lua. To facilitate following a request across services, we’ll reuse the header if it’s already set. If the header isn’t set, then this request didn’t come from another service, so we’ll generate a UUID:

server {
... set_by_lua $uuid '
if ngx.var.http_x_request_id == nil then
return uuid4.getUUID()
else
return ngx.var.http_x_request_id
end
' ...
}

If you’re trusting this header data in any way, you should be sure to filter/restrict that header appropriately so that the client can’t change it.

Update (Thursday December 11 2014): Edited the post to move the uuid generation into the server section and using set_by_lua, so that the uuid can be set to/from the header to flow through the stacks properly. Shout out to Asher Feldman for working out a better solution with me.

参考资料:

Using Lua in Nginx for unique request IDs and millisecond times in logs:http://ryandlane.com/blog/2014/12/11/using-lua-in-nginx-for-unique-request-ids-and-millisecond-times-in-logs/

Simple nginx lua script to add UUID to each request for end to end request tracking:https://gist.github.com/erikcw/e999e1fb438dbbb91533

Is there a way to log a per request unique id for nginx?:http://serverfault.com/questions/580394/is-there-a-way-to-log-a-per-request-unique-id-for-nginx

http://stackoverflow.com/questions/17748735/setting-a-trace-id-in-nginx-load-balancer

https://github.com/kali/nginx-operationid

【架构】Nginx如何设置X-Request-ID请求头,记录请求时间:毫秒?的更多相关文章

  1. request获取请求头和请求数据

    package cn.itcast.request; import java.io.IOException; import java.io.InputStream; import java.io.Pr ...

  2. HTTP 请求头与请求体 - 某熊的全栈之路 - SegmentFault

    本文从属于笔者的HTTP 理解与实践系列文章,对于HTTP的学习主要包含HTTP 基础.HTTP 请求头与请求体.HTTP 响应头与状态码.HTTP 缓存这四个部分,而对于HTTP相关的扩展与引申,我 ...

  3. 【转载】HTTP 请求头与请求体

    原文地址: https://segmentfault.com/a/1190000006689767 HTTP Request HTTP 的请求报文分为三个部分 请求行.请求头和请求体,格式如图:一个典 ...

  4. HttpServletRequest对象,请求行、请求头、请求体

    HttpServletRequest 公共接口类HttpServletRequest继承自ServletRequest.客户端浏览器发出的请求被封装成为一个HttpServletRequest对象.对 ...

  5. Django中获取参数(路径,查询,请求头,请求体)

    一.通常HTTP协议向服务器传参有几种途径 : 提取URL的特定部分,如/weather/shanghai/2018,可以在服务器端的路由中用正则表达式截取: 查询字符串(query string), ...

  6. HTTP请求报文(请求行、请求头、请求体)

    HTTP协议 1.简介 HTTP协议(Hyper Text Transfer Protocol,超文本传输协议),是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的 ...

  7. iOS开发——网络篇——文件下载(NSMutableData、NSFileHandle、NSOutputStream)和上传、压缩和解压(三方框架ZipArchive),请求头和请求体格式,断点续传Range

    一.小文件下载 NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion ...

  8. HTTP请求行、请求头、请求体详解

    HTTP 请求头各参数具体含义 Header 解释 示例Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/htmlAccept-Charset 浏览器可以接 ...

  9. HTTP请求行、请求头、请求体详解(转)

    转自 https://blog.csdn.net/u010256388/article/details/68491509/     HTTP请求报文解剖 HTTP请求报文由3部分组成(请求行+请求头+ ...

  10. 【校招面试 之 网络】第3题 HTTP请求行、请求头、请求体详解

    1.HTTP请求报文解剖 HTTP请求报文由3部分组成(请求行+请求头+请求体): 下面是一个实际的请求报文: ①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE.HEA ...

随机推荐

  1. lr手工添加关联函数的步骤:

    点击“确定”后: 如何修改已经创建好的关联规则:

  2. oracle 优化方案小记

    1. 目前状况 1.1 表空间未合理规划,导致所有的用户下的所有表都创建在默认的表空间下 oracle 使用过程中未针对特定数据表进行特定的表空间规划,导致目前实例中所有的数据库表都存储中默认的表空间 ...

  3. Ubuntu下各种环境变量设置

    1.用户目录下的 .bashrc 文件在用户主目录下,有一个 .bashrc 文件,编辑该文件:$gedit ~/.bashrc 在最后边加入需要设置变量的shell语句,例如:export PATH ...

  4. HttpClient(转载)

    Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我 们再讨论),它不仅是客户端发送Http请求变得容易,而 ...

  5. 洛谷——P1194 买礼物

    P1194 买礼物 题目描述 又到了一年一度的明明生日了,明明想要买B样东西,巧的是,这B样东西价格都是A元. 但是,商店老板说最近有促销活动,也就是: 如果你买了第I样东西,再买第J样,那么就可以只 ...

  6. 【BZOJ 4567】【SCOI 2016】背单词

    http://www.lydsy.com/JudgeOnline/problem.php?id=4567 贪心. 任何不用第一种情况的方案吃的泡椒数都小于\(n^2\),所以最小泡椒数的方案一定不包含 ...

  7. BZOJ 1221 [HNOI2001] 软件开发(费用流)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1221 [题目大意] 每天对毛巾都有一定的需求ni,每天可以花f价值每条购买毛巾, 当天 ...

  8. [Luogu2656]采蘑菇

    题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: ...

  9. Uncaught SyntaxError: Invalid shorthand property initializer

    $.ajax({ url : '../../collateralQuery/getCollateralQueryDetail', type : 'POST', data : {}, dataType ...

  10. 推荐几个对象映射(Object-Object Map)的库

    在进行一些MIS相关的项目开发中,我们经常会涉及到一些数据对象和视图模型之间的互相转换, public class Customer        //mapped from db    {      ...