{"id":10725,"date":"2016-09-28T04:47:11","date_gmt":"2016-09-27T19:47:11","guid":{"rendered":"https:\/\/jirak.net\/wp\/application-tracing-with-nginx-and-nginx-plus\/"},"modified":"2016-09-28T05:37:37","modified_gmt":"2016-09-27T20:37:37","slug":"application-tracing-with-nginx-and-nginx-plus","status":"publish","type":"post","link":"https:\/\/jirak.net\/wp\/application-tracing-with-nginx-and-nginx-plus\/","title":{"rendered":"Application Tracing with NGINX and NGINX\u00a0Plus"},"content":{"rendered":"<p>Application Tracing with NGINX and NGINX\u00a0Plus<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/jirak.net\/wp\/wp-content\/uploads\/2016\/09\/breadcrumb-trail.png\" width=\"975\" height=\"317\"><\/p>\n<figure id=\"attachment_46249\" style=\"width: 975px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/breadcrumb-trail.png\" alt=\"The $request_id variable introduced in NGINX Plus R10 enables you to trace request processing end-to-end, like a trail of breadcrumbs\" width=\"975\" height=\"317\" class=\"size-full wp-image-46249\" \/><figcaption class=\"wp-caption-text\">Photo: <a target=\"_blank\" href=\"https:\/\/wordpress.org\/plugins\/instant-breadcrumbs\/?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">WordPress.org<\/a><\/figcaption><\/figure>\n<h3><em>Using variables for application performance management<\/em><\/h3>\n<p>Variables are an important and sometimes overlooked aspect of NGINX configuration. With approximately <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/varindex.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">150 variables<\/a> available, there are variables to enhance every part of your configuration. In this blog post we discuss how to use NGINX variables for application tracing and application performance management (APM), with a focus on uncovering performance bottlenecks in your application. This post applies to both the open source NGINX software and NGINX&nbsp;Plus. For brevity we&#8217;ll refer to NGINX Plus throughout except when there is a difference between the two products.<\/p>\n<h2>The Application Delivery Environment<\/h2>\n<p>In our sample application delivery environment, NGINX&nbsp;Plus is working as a reverse proxy for our application. The application itself is comprised of a web frontend behind which sit a number of microservices.<\/p>\n<figure id=\"attachment_46251\" style=\"width: 1024px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/assets.wp.nginx.com\/wp-content\/uploads\/2016\/09\/nginx-proxies-app-with-frontend-and-microservices.png\" alt=\"In a common deployment scenario, NGINX or NGINX Plus proxies requests from clients to an application that consists of a web frontend and supporting microservices\" width=\"1024\" height=\"490\" class=\"size-full wp-image-46251\" \/><figcaption class=\"wp-caption-text\">Sample application delivery environment<\/figcaption><\/figure>\n<h2>Tracing Requests End&#8209;to&#8209;End<\/h2>\n<p>NGINX&nbsp;Plus&nbsp;R10 (and NGINX&nbsp;1.11.0) introduces the <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#var_request_id\"><code>$request_id<\/code><\/a> variable, which is a randomly generated string of 32&nbsp;hexadecimal characters automatically assigned to each HTTP request as it arrives (for example, <code>444535f9378a3dfa1b8604bc9e05a303<\/code>). This deceptively simple mechanism unlocks a powerful tool for tracing and troubleshooting. By configuring NGINX&nbsp;Plus and all backend services to pass the <code>$request_id<\/code> value, you can trace every request end&#8209;to&#8209;end. This sample config is for our frontend NGINX&nbsp;Plus server.<\/p>\n<pre><code class=\"config\">upstream app_server {<br \/>\n    server 10.0.0.1:80;<br \/>\n}<\/p>\n<p>server {<br \/>\n    listen 80;<br \/>\n    add_header X-Request-ID $request_id; # Return to client<br \/>\n    location \/ {<br \/>\n        proxy_pass http:\/\/app_server;<br \/>\n        proxy_set_header X-Request-ID $request_id; # Pass to app server<br \/>\n    }<br \/>\n}<\/pre>\n<p><\/code><\/p>\n<p>To configure NGINX&nbsp;Plus for request tracing, we first define the network location of the application server in the <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#upstream\"><code>upstream<\/code><\/a> block. For simplicity we only show a single application <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#upstream\"><code>server<\/code><\/a> here, but we would normally use several, for high availability and load balancing purposes. <\/p>\n<p>The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#server\"><code>server<\/code><\/a> block defines how NGINX&nbsp;Plus handles incoming HTTP requests. The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#listen\"><code>listen<\/code><\/a> directive tells NGINX&nbsp;Plus to listen on port 80&nbsp;&ndash; the default for HTTP traffic, but a production configuration normally uses <a href=\"https:\/\/www.nginx.com\/blog\/nginx-ssl\/?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">use SSL\/TLS to protect data in transit<\/a>.<\/p>\n<p>The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_headers_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#add_header\"><code>add_header<\/code><\/a> directive sends the <code>$request_id<\/code> value back to the client as a custom header in the response. This is useful for testing and also for client applications that generate their own logs, such as mobile apps, so that a client&#8209;side error can be matched precisely to the server logs.<\/p>\n<p>Finally, the <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#location\"><code>location<\/code><\/a> block applies to the entire application space (<strong>\/<\/strong>) and the <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_proxy_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#proxy_pass\"><code>proxy_pass<\/code><\/a> directive simply proxies all requests to the application server. The <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_proxy_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#proxy_set_header\"><code>proxy_set_header<\/code> <\/a> directive modifies the proxied request by adding an HTTP header that is passed to the application. In this case we create a new header called <code>X&#8209;Request&#8209;ID<\/code>  and assign to it the value of the <code>$request_id<\/code>  variable. So our application receives the request ID that was generated by NGINX&nbsp;Plus.<\/p>\n<h2>Logging <code>$request_id<\/code> End&#8209;to&#8209;End<\/h2>\n<p>Our goal with application tracing is to identify performance bottlenecks in the request&#8209;processing lifecycle as part of application performance management. We do this by logging significant events during processing so we can analyze them later for unexpected or unreasonable delays.<\/p>\n<h3>Configuring NGINX&nbsp;Plus<\/h3>\n<p>We start by configuring the frontend NGINX&nbsp;Plus server to include <code>$request_id<\/code> in a custom logging format, <code>trace<\/code>, which is used for the <strong>access_trace.log<\/strong> file.<\/p>\n<pre><code class=\"config\"><strong>log_format trace<\/strong> '$remote_addr - $remote_user [$time_local] \"$request\" '<br \/>\n                 '$status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" '<br \/>\n                 '\"$http_x_forwarded_for\" <strong>$request_id<\/strong>';<\/p>\n<p>upstream app_server {<br \/>\n    server 10.0.0.1;<br \/>\n}<\/p>\n<p>server {<br \/>\n    listen 80;<br \/>\n    add_header X-Request-ID $request_id; # Return to client<br \/>\n    location \/ {<br \/>\n        proxy_pass http:\/\/app_server;<br \/>\n        proxy_set_header X-Request-ID $request_id;        # Pass to app server<br \/>\n        <strong>access_log \/var\/log\/nginx\/access_trace.log trace<\/strong>; # Log $request_id<br \/>\n    }<br \/>\n}<\/pre>\n<p><\/code><\/p>\n<h3>Configuring the Backend Application<\/h3>\n<p>Passing the Request ID to your application is all well and good, but does not actually help with application tracing unless the application does something with it. In this example we have a Python application managed by <a target=\"_blank\" href=\"https:\/\/uwsgi-docs.readthedocs.io\/en\/latest\/?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">uWSGI<\/a>. Let\u2019s modify the application entry point to grab the Request ID as a logging variable.<\/p>\n<pre><code class=\"config\"><span style=\"color:#0066ff\">from<\/span> <span style=\"color:#ff00cc\">uwsgi<\/span> <span style=\"color:#0066ff\">import<\/span> <span style=\"color:#ff00cc\">set_logvar<\/span><\/p>\n<p><span style=\"color:#0066ff\">def<\/span> <span style=\"color:#ff00cc\">main<\/span>(environ, start_response):<br \/>\n    <span style=\"color:#ff00cc\">set_logvar<\/span>(<span style=\"color:#cc9900\">'requestid'<\/span>, environ[<span style=\"color:#cc9900\">'X_REQUEST_ID'<\/span>])<\/pre>\n<p><\/code><\/p>\n<p>Then we can modify the uWSGI configuration to include the Request ID in the standard log file.<\/p>\n<pre><code class=\"config\">log-format = %(addr) - %(user) [%(ltime)] \"%(method) %(uri) %(proto)\" %(status)<br \/>\n%(size) \"%(referer)\" \"%(uagent)\" <strong>%(requestid)<\/strong><\/pre>\n<p><\/code><\/p>\n<p>With this configuration in place we are now producing log files which can be linked to a single request across numerous systems.<\/p>\n<p>Log entry from NGINX:<\/p>\n<pre><code class=\"config\">172.17.0.1 - - [02\/Aug\/2016:14:26:33 +0000] \"GET \/ HTTP\/1.1\" 200 90 \"-\" \"-\" \"-\" 5f222ae5938482c32a822dbf15e19f0f<\/pre>\n<p><\/code><\/p>\n<p>Log entry from application:<\/p>\n<pre><code class=\"config\">192.168.91.1 - - [02\/Aug\/2016:14:26:34 +0000] \"GET \/ HTTP\/1.0\" 200 123 \"-\" \"-\" 5f222ae5938482c32a822dbf15e19f0f<\/pre>\n<p><\/code><\/p>\n<p>By matching transactions against the Request ID fields, tools like <a target=\"_blank\" href=\"https:\/\/www.splunk.com\/?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">Splunk<\/a> and <a target=\"_blank\" href=\"https:\/\/www.elastic.co\/products\/kibana?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">Kibana<\/a> allow us to identify performance bottlenecks. For example, we can search for requests that took more than two&nbsp;seconds to complete. However, the default time resolution of one&nbsp;second in regular timestamps is insufficient for most real&#8209;world analysis.<\/p>\n<h2>High&#8209;Precision Timing<\/h2>\n<p>In order to accurately measure requests end&#8209;to&#8209;end we need timestamps with millisecond&#8209;level precision. By including the <code>$msec<\/code> variable in log entries, we get millisecond resolution on the timestamp for each entry. Adding millisecond timestamps to our application log allows us to look for requests that took more than 200&nbsp;milliseconds to complete rather than 2&nbsp;seconds. <\/p>\n<p>But even then we are not getting the full picture, because NGINX&nbsp;Plus writes the <code>$msec<\/code> timestamp only at the end of processing each request. Fortunately, there are several other NGINX&nbsp;Plus timing variables with millisecond precision that give us more insight into the processing itself:<\/p>\n<ul>\n<li><a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#var_request_time\"><code>$request_time<\/code><\/a>&nbsp;&ndash; Full request time, starting when NGINX&nbsp;Plus reads the first byte from the client and ending when NGINX&nbsp;Plus sends the last byte of the response body<\/li>\n<li><a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#var_upstream_connect_time\"><code>$upstream_connect_time<\/code><\/a>&nbsp;&ndash; Time spent establishing a connection with the upstream server<\/li>\n<li><a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#var_upstream_header_time\"><code>$upstream_header_time<\/code><\/a>&nbsp;&ndash; Time between establishing a connection to the upstream server and receiving the first byte of the response header<\/li>\n<li><a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_upstream_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#var_upstream_response_time\"><code>$upstream_response_time<\/code><\/a>&nbsp;&ndash; Time between establishing a connection to the upstream server and receiving the last byte of the response body<\/li>\n<\/ul>\n<p>For detailed information about these timing variables, see <a href=\"https:\/\/www.nginx.com\/blog\/using-nginx-logging-for-application-performance-monitoring\/?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog\">Using NGINX Logging for Application Performance Monitoring<\/a>.<\/p>\n<p>Let\u2019s extend our <a target=\"_blank\" href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_log_module.html?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#log_format\"><code>log_format<\/code><\/a> directive to include all of these high&#8209;precision timing variables in our <code>trace<\/code> log format.<\/p>\n<pre><code class=\"config\">log_format trace '$remote_addr - $remote_user [$time_local] \"$request\" $status '<br \/>\n                 '$body_bytes_sent \"$http_referer\" \"$http_user_agent\" '<br \/>\n                 '\"$http_x_forwarded_for\" $request_id <strong>$msec $request_time '<\/strong><br \/>\n                 <strong>'$upstream_connect_time $upstream_header_time $upstream_response_time'<\/strong>;<\/pre>\n<p><\/code><\/p>\n<p>Using our preferred log analysis tool, we can extract variable values and perform the following calculation to see how long NGINX&nbsp;Plus took to process the request before connecting to the application server:<\/p>\n<pre><code class=\"config\">NGINX Plus processing time = $request_time - $upstream_connect_time - $upstream_response_time<\/pre>\n<p><\/code><\/p>\n<p>We can also search for the highest values of <code>$upstream_response_time<\/code> to see if they are associated with particular URIs or upstream servers. And these can then be further checked against application log entries that have the same Request&nbsp;ID.<\/p>\n<h2>Conclusion<\/h2>\n<p>Utilizing the new <code>$request_id<\/code> variable and some or all of the millisecond&#8209;precision variables can provide great insight into the performance bottlenecks in your application, improving application performance management without having to resort to heavyweight agents and plug&#8209;ins.<\/p>\n<p>Try out application tracing with NGINX&nbsp;Plus for yourself: start your <span><a href=\"?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#\/free-trial\">free 30&#8209;day trial<\/a><\/span> today or <a href=\"?utm_source=application-tracing-nginx-plus&amp;utm_medium=blog#contact-us\">contact&nbsp;us<\/a> for a live demo.<\/p>\n<p>The post <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\/blog\/application-tracing-nginx-plus\/\">Application Tracing with NGINX and NGINX&nbsp;Plus<\/a> appeared first on <a rel=\"nofollow\" href=\"https:\/\/www.nginx.com\">NGINX<\/a>.<\/p>\n<p>Source: <a href=\"https:\/\/www.nginx.com\/blog\/application-tracing-nginx-plus\/\" target=\"_blank\">Application Tracing with NGINX and NGINX\u00a0Plus<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>Application Tracing with NGINX and NGINX\u00a0Plus Photo: WordPress.org Using variables for application performance management Variables are an important and sometimes overlooked aspect of NGINX configuration. With approximately 150 variables available, there are variables to enhance every part of your configuration. In this blog post we discuss how to use NGINX variables for application tracing and application performance management (APM), with a focus on uncovering performance bottlenecks in your application. This post applies to both the open source NGINX software and NGINX&nbsp;Plus. For brevity we&#8217;ll refer to NGINX Plus throughout except when there is a difference between the two products. The Application Delivery Environment In our sample application delivery environment, NGINX&nbsp;Plus is working as a reverse proxy for our application. The application itself is comprised of a web frontend behind which sit a number of microservices. Sample application delivery environment Tracing <a class=\"mh-excerpt-more\" href=\"https:\/\/jirak.net\/wp\/application-tracing-with-nginx-and-nginx-plus\/\" title=\"Application Tracing with NGINX and NGINX\u00a0Plus\">[ more&#8230; ]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":10726,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[169],"tags":[652],"class_list":["post-10725","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","tag-nginx"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10725","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/comments?post=10725"}],"version-history":[{"count":1,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10725\/revisions"}],"predecessor-version":[{"id":10727,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/posts\/10725\/revisions\/10727"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media\/10726"}],"wp:attachment":[{"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/media?parent=10725"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/categories?post=10725"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jirak.net\/wp\/wp-json\/wp\/v2\/tags?post=10725"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}