diff --git a/.gitignore b/.gitignore index 26254c2..73f735d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ nginx *.svg *.bt *.cbt +.idea/* diff --git a/accessed-files b/accessed-files index a89639b..1e662c8 100755 --- a/accessed-files +++ b/accessed-files @@ -77,9 +77,9 @@ probe end { printf("\\n=== Top $limit file $operation ===\\n") i = 0 - foreach (path in stats- limit $limit) { + foreach (pathname in stats- limit $limit) { printf("#%d: %d times, %d bytes $operation in file %s.\\n", - ++i, \@count(stats[path]), \@sum(stats[path]), path) + ++i, \@count(stats[pathname]), \@sum(stats[pathname]), pathname) } } } @@ -114,9 +114,7 @@ $preamble probe $probes { if (pid() == target() && \$return > 0) { - path = __file_filename(file) - //println(path) - stats[path] <<< \$return + stats[pathname] <<< \$return found++; } } diff --git a/check-debug-info b/check-debug-info index 2208f3d..e2fbfee 100755 --- a/check-debug-info +++ b/check-debug-info @@ -14,6 +14,7 @@ my $pid = $opts{p} or die "No -p option specified.\n"; my $exec_file = "/proc/$pid/exe"; + if (!-f $exec_file) { die "User process $pid is not running or ", "you do not have enough permissions.\n"; @@ -41,6 +42,7 @@ my %files = ($path => 1); } for my $file (sort keys %files) { + $file = "/proc/$pid/root" . $file; my $lines = `objdump --dwarf=str $file|wc -l`; if ($? != 0) { warn "Failed to check file $file: $?\n"; diff --git a/ngx-active-reqs b/ngx-active-reqs index 1b83987..07d263d 100755 --- a/ngx-active-reqs +++ b/ngx-active-reqs @@ -52,7 +52,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { @@ -96,10 +96,26 @@ my $p = '@cast(p, "ngx_event_pipe_t")'; my $need_blank_line; -my ($check_upstream_code, $check_pool_init_code, $check_pool_code); +my ($check_upstream_code, $check_pool_init_code, $check_pool_code, $keep_waiting_code); my $fin_code = ''; +if ($keep_waiting) { + $keep_waiting_code = <<_EOC_; +_EOC_ + +}else{ + + $keep_waiting_code = <<_EOC_; + if (nreqs) { + exit() + } +_EOC_ + +} + +chop $keep_waiting_code; + if ($check_upstreams) { $need_blank_line = 1; @@ -428,9 +444,8 @@ $fin_code elapsed = local_clock_us() - begin printf("%d microseconds elapsed in the probe handler.\\n", elapsed) - if (nreqs || !$keep_waiting) { - exit() - } +$keep_waiting_code + } /* $condition */ } _EOC_ diff --git a/ngx-backtrace b/ngx-backtrace index 8c777f8..f6a301e 100755 --- a/ngx-backtrace +++ b/ngx-backtrace @@ -35,8 +35,6 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; - exec 'addr2line', '-e', $exec_file, '-f', @ARGV; sub usage { diff --git a/ngx-body-filters b/ngx-body-filters index 5476f57..7980799 100755 --- a/ngx-body-filters +++ b/ngx-body-filters @@ -37,7 +37,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { diff --git a/ngx-cycle-pool b/ngx-cycle-pool index 84a0ff8..7dd40cb 100755 --- a/ngx-cycle-pool +++ b/ngx-cycle-pool @@ -37,7 +37,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { diff --git a/ngx-header-filters b/ngx-header-filters index cee9328..cf1e222 100755 --- a/ngx-header-filters +++ b/ngx-header-filters @@ -37,7 +37,8 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; + +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { diff --git a/ngx-leaked-pools b/ngx-leaked-pools index ec39086..eaafa7b 100755 --- a/ngx-leaked-pools +++ b/ngx-leaked-pools @@ -37,7 +37,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { diff --git a/ngx-pcrejit b/ngx-pcrejit index cf1c994..16a60f2 100755 --- a/ngx-pcrejit +++ b/ngx-pcrejit @@ -39,7 +39,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; my $maps_file = "/proc/$pid/maps"; if (!-f $maps_file) { diff --git a/ngx-req-distr b/ngx-req-distr index f7bd5e9..145b2cf 100755 --- a/ngx-req-distr +++ b/ngx-req-distr @@ -39,7 +39,7 @@ if (!-f $exec_file) { "you do not have enough permissions.\n"; } -my $nginx_path = readlink $exec_file; +my $nginx_path = "/proc/$master_pid/root" . readlink $exec_file; my $ver = `stap --version 2>&1`; if (!defined $ver) { diff --git a/ngx-req-watch b/ngx-req-watch new file mode 100755 index 0000000..180ece7 --- /dev/null +++ b/ngx-req-watch @@ -0,0 +1,256 @@ +#! /usr/bin/env perl + +# Copyright (C) YangBingwu (detailyang) + +use 5.006001; +use strict; +use warnings; +use Getopt::Std qw( getopts ); + +sub usage(); + + +my %opts; + +getopts("ht:p:dt:s:c:T:u:", \%opts) or die usage(); + +if ($opts{h}) { + print usage(); + exit; +} + +my $count = $opts{c} || 100; +if ($count !~ /^\d+$/) { + die "Bad -t option value \"$count\": not look like count\n"; +} + +my $count_condition = ""; +if ($count > 0) { + $count_condition = <<_EOS_; + if (nreqs > $count) { + warn("up to max requests:$count") + exit(); + } +_EOS_ +} + +my $uri = $opts{u} || ""; +my $uri_codition = ""; +if ($uri) { + $uri_codition = <<_EOS_; + if (user_string_n(uri_data, uri_len) !~ "$uri") next +_EOS_ +} + +my $time = $opts{t} || 0; +if ($time !~ /^\d+$/) { + die "Bad -t option value \"$time\": not look like time\n"; +} + +my $slowtime = $opts{T} || 0; +if ($slowtime !~ /^\d+$/) { + die "Bad -T option value \"$slowtime\": not look like time\n"; +} + +my $pid = $opts{p} + or die "No nginx process pid specified by the -p option\n"; +if ($pid !~ /^\d+$/) { + die "Bad -p option value \"$pid\": not look like a pid\n"; +} + +my $exec_file = "/proc/$pid/exe"; + +if (!-f $exec_file) { + die "Nginx process $pid is not running or ", + "you do not have enough permissions.\n"; +} + +my $nginx_path = "/proc/$pid/root" . readlink $exec_file; +my $stap_args = $opts{a} || ''; + +my $child_pids = get_child_processes($pid); +if (!@$child_pids) { + push @$child_pids, $pid; +} + +my $status_rv = 1; +my @function_status_tmp; +my @status = split ",", ($opts{s} or ""); + +if ( $#status + 1 > 0) { + $status_rv = 0; +} + +for my $code (@status) { + if ($code =~ /(\d)0x/) { + push @function_status_tmp, " if (status >= $1*100 && status <= $1*100+99) return 1" + } else { + push @function_status_tmp, " if (status == $code) return 1" + } +} + +my $function_status_coditions = join "\r\n", @function_status_tmp; +my $function_status_preamble = <<_EOS_; +function filter_status:long(status:long) +{ + $function_status_coditions + return $status_rv +} +_EOS_ + +my $c = '@cast(c, "ngx_connection_t")'; +my $r = '@cast(r, "ngx_http_request_t")'; + +my $preamble = <<_EOS_; +global nreqs; + +probe begin { + warn(sprintf("watching $nginx_path(@$child_pids) requests")) +} + +$function_status_preamble + +_EOS_ +chomp($preamble); + +my $stap_src = <<_EOS_; +$preamble + +probe process("$nginx_path").function("ngx_http_log_request") { + r = \$r + + cached_sec = \@var("ngx_cached_time")->sec + cached_msec = \@var("ngx_cached_time")->msec + + start_sec = $r->start_sec + start_msec = $r->start_msec + + ms = (cached_sec - start_sec) * 1000 + (cached_msec - start_msec) + if (ms < 0) { + ms = 0 + } + + if (ms < $slowtime) next + + nreqs++ + $count_condition + + status = $r->headers_out->status + if (!filter_status(status)) next + + c = $r->connection + addr_text = &$c->addr_text + addr_text_data = \@cast(addr_text, "ngx_str_t")->data + addr_text_len = \@cast(addr_text, "ngx_str_t")->len + + fd = $c->fd + + uri = &$r->uri + uri_data = \@cast(uri, "ngx_str_t")->data + uri_len = \@cast(uri, "ngx_str_t")->len + + $uri_codition + + method = &$r->method_name + method_data = \@cast(method, "ngx_str_t")->data + method_len = \@cast(method, "ngx_str_t")->len + + args = &$r->args + args_data = \@cast(args, "ngx_str_t")->data + args_len = \@cast(args, "ngx_str_t")->len + + host = &$r->headers_in->server + host_data = \@cast(host, "ngx_str_t")->data + host_len = \@cast(host, "ngx_str_t")->len + + printf("%s(%d) %s URI:%s%s HOST:%s STATUS:%d FROM %s FD:%d RT: %dms\\n", + execname(), pid(), + user_string_n(method_data, method_len), + user_string_n(uri_data, uri_len), args_data ? sprintf("?%s", user_string_n(args_data, args_len)) : "", + host_data ? user_string_n(host_data, host_len) : "", + status, + addr_text_data ? user_string_n(addr_text_data, addr_text_len) : "", + fd, ms + ) +} +%( +$time > 0 +%? +probe timer.ms($time) { + warn("Time Ending....") + exit(); +} +%: +probe end { + exit() +} +%) +_EOS_ + +if ($opts{d}) { + print $stap_src; + exit; +} + +my @opts; +if (@$child_pids == 1) { + push @opts, '-x', $child_pids->[0]; +} + +open my $in, "|stap --skip-badvars @opts $stap_args -" + or die "Cannot run stap: $!\n"; + +print $in $stap_src; + +close $in; + +if ($opts{d}) { + print $stap_src; + exit; +} + +sub get_child_processes { + my $pid = shift; + # iterate /proc/pid is more compatible with /proc/pid/children with high kernel + my @files = glob "/proc/[0-9]*/stat"; + my @children; + + for my $file (@files) { + #print "file: $file\n"; + if ($file =~ m{^/proc/$pid/}) { + next; + } + + open my $in, $file or next; + my $line = <$in>; + close $in; + if ($line =~ /^(\d+) \S+ \S+ (\d+)/) { + my ($child, $parent) = ($1, $2); + if ($parent eq $pid) { + push @children, $child; + } + } + } + + @children = sort { $a <=> $b } @children; + return \@children; +} + +sub usage() { + return <<'_EOC_'; +Usage: + ngx-req-watch [optoins] +Options: + -a Pass extra arguments to the stap utility. + -c Specify the max requests default 100. + -t