How To Graph Nginx Statistics

Sometimes, we prefer to view statistics in graphical form rather than numerical values​​, which is not too attractive to be displayed. Nginx supports stub_status directive module, which we can use to print:

  • Active connections
  • Server accepts handled requests
  • Reading
  • Writing
  • Waiting

For example:

Active connections: 6
server accepts handled requests
 15561 15561 26602
Reading: 4 Writing: 2 Waiting: 0

However, This module is not compiled by default and must be specified using this argument when compiling nginx.

--with-http_stub_status_module

First, to get statistics like the above example, you should modify nginx config file and add location directive this

server {
....
....
	location /nginx_status {
		stub_status on;
		access_log   off;
		allow 1.2.3.4;
		allow 5.6.7.8;
		deny all;
	}
}

perl scripts used to generate statistical images can be downloaded here:

http://kovyrin.net/files/mrtg/rrd_nginx.pl.txt

Rename rrd_nginx.pl.txt to rrd_nginx.pl and make it executable

Or you can simply copy and paste from here

#!/usr/bin/perl
use RRDs;
use LWP::UserAgent;

# define location of rrdtool databases
my $rrd = '/opt/rrd';
# define location of images
my $img = '/var/www/html/rrd';
# define your nginx stats URL
my $URL = "http://www.example.com/nginx_status";

my $ua = LWP::UserAgent->new(timeout => 30);
my $response = $ua->request(HTTP::Request->new('GET', $URL));

my $requests = 0;
my $total =  0;
my $reading = 0;
my $writing = 0;
my $waiting = 0;

foreach (split(/\n/, $response->content)) {
$total = $1 if (/^Active connections:\s+(\d+)/);
	if (/^Reading:\s+(\d+).*Writing:\s+(\d+).*Waiting:\s+(\d+)/) {
		$reading = $1;
		$writing = $2;
		$waiting = $3;
	}
	$requests = $3 if (/^\s+(\d+)\s+(\d+)\s+(\d+)/);
}

#print "RQ:$requests; TT:$total; RD:$reading; WR:$writing; WA:$waiting\n";

# if rrdtool database doesn't exist, create it
if (! -e "$rrd/nginx.rrd") {
RRDs::create "$rrd/nginx.rrd",
        "-s 60",
        "DS:requests:COUNTER:120:0:100000000",
        "DS:total:ABSOLUTE:120:0:60000",
        "DS:reading:ABSOLUTE:120:0:60000",
        "DS:writing:ABSOLUTE:120:0:60000",
        "DS:waiting:ABSOLUTE:120:0:60000",
        "RRA:AVERAGE:0.5:1:2880",
        "RRA:AVERAGE:0.5:30:672",
        "RRA:AVERAGE:0.5:120:732",
        "RRA:AVERAGE:0.5:720:1460";
}

# insert values into rrd database
RRDs::update "$rrd/nginx.rrd",
  "-t", "requests:total:reading:writing:waiting",
  "N:$requests:$total:$reading:$writing:$waiting";

# Generate graphs
CreateGraphs("day");
CreateGraphs("week");
CreateGraphs("month");
CreateGraphs("year");

#------------------------------------------------------------------------------
sub CreateGraphs($){
my $period = shift;

  RRDs::graph "$img/requests-$period.png",
                "-s -1$period",
                "-t Requests on nginx",
                "--lazy",
                "-h", "150", "-w", "700",
                "-l 0",
                "-a", "PNG",
                "-v requests/sec",
                "DEF:requests=$rrd/nginx.rrd:requests:AVERAGE",
                "LINE2:requests#336600:Requests",
                "GPRINT:requests:MAX:  Max\\: %5.1lf %S",
                "GPRINT:requests:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:requests:LAST: Current\\: %5.1lf %Sreq/sec",
                "HRULE:0#000000";
  if ($ERROR = RRDs::error) {
    print "$0: unable to generate $period graph: $ERROR\n";
  }

  RRDs::graph "$img/connections-$period.png",
                "-s -1$period",
                "-t Requests on nginx",
                "--lazy",
                "-h", "150", "-w", "700",
                "-l 0",
                "-a", "PNG",
                "-v requests/sec",
                "DEF:total=$rrd/nginx.rrd:total:AVERAGE",
                "DEF:reading=$rrd/nginx.rrd:reading:AVERAGE",
                "DEF:writing=$rrd/nginx.rrd:writing:AVERAGE",
                "DEF:waiting=$rrd/nginx.rrd:waiting:AVERAGE",

                "LINE2:total#22FF22:Total",
                "GPRINT:total:LAST:   Current\\: %5.1lf %S",
                "GPRINT:total:MIN:  Min\\: %5.1lf %S",
                "GPRINT:total:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:total:MAX:  Max\\: %5.1lf %S\\n",

                "LINE2:reading#0022FF:Reading",
                "GPRINT:reading:LAST: Current\\: %5.1lf %S",
                "GPRINT:reading:MIN:  Min\\: %5.1lf %S",
                "GPRINT:reading:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:reading:MAX:  Max\\: %5.1lf %S\\n",

                "LINE2:writing#FF0000:Writing",
                "GPRINT:writing:LAST: Current\\: %5.1lf %S",
                "GPRINT:writing:MIN:  Min\\: %5.1lf %S",
                "GPRINT:writing:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:writing:MAX:  Max\\: %5.1lf %S\\n",

                "LINE2:waiting#00AAAA:Waiting",
                "GPRINT:waiting:LAST: Current\\: %5.1lf %S",
                "GPRINT:waiting:MIN:  Min\\: %5.1lf %S",
                "GPRINT:waiting:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:waiting:MAX:  Max\\: %5.1lf %S\\n",

                "HRULE:0#000000";
  if ($ERROR = RRDs::error) {
    print "$0: unable to generate $period graph: $ERROR\n";
  }
}

Some settings that can be adjusted:

  • my $rrd = ‘/opt/rrd’;
    Roundrobin database file will be placed in /opt/rrd as nginx.rrd
  • my $img = ‘/var/www/html/rrd’;
    All image generated by the script will be placed in /var/www/html/rrd

Ie:

connections-day.png
connections-week.png
requests-month.png
requests-year.png
connections-month.png
connections-year.png
requests-day.png
requests-week.png

  • my $URL = “http://www.example.com/nginx_status”;
    my $URL should be adjusted according to your nginx configuration, $URL value required by LWP::UserAgent grab statistic values from nginx.

Run the script periodically using crontab

*    * * * * root /path/to/rrd_nginx.pl

Some example graph results:

You can find original article here:
http://kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *