Net-Prometheus-ServerStatusLiteCollector

 view release on metacpan or  search on metacpan

lib/Net/Prometheus/ServerStatusLiteCollector.pm  view on Meta::CPAN

    }
    if (! scalar %$stats) {
        $self->warn("There is no status file in scoreboard directory. Maybe all processes are idle state and do not serve any request yet.");
        return ();
    }

    # Check counter file
    my $counter_fh;
    if ($self->counter_file) {
        unless (open($counter_fh, '<:unix', $self->counter_file)) {
            $self->error("Could not open counter file: $!");
            return ();
        }
    }

    # Check scoreboard stats is valid
    my @all_workers = keys %$stats;
    my $pstatus = eval {
        $JSON->decode($stats->{$all_workers[0]} || '{}');
    };
    if (!$pstatus->{ppid} || !$pstatus->{uptime} || !$pstatus->{ppid}) {
        $self->error("Status file does not have some necessary variables");
        return ();
    }
    my $parent_pid = $pstatus->{ppid};

    # Begin compiling stats
    my @samples = ();
    push @samples,
        MetricSamples('plack_uptime', gauge => 'Uptime of Plack server',
            [Sample('plack_uptime', $self->labels, (time - $pstatus->{uptime}))]);

    # Compile request counter stats
    if ($counter_fh) {
        seek $counter_fh, 10, 0;
        sysread $counter_fh, my $counter, 20;
        sysread $counter_fh, my $total_bytes, 20;
        no warnings;
        $counter += 0;
        $total_bytes += 0;
        my $total_kbytes = int($total_bytes / 1_000);
        push @samples,
            MetricSamples('plack_number_served_requests', gauge => 'Number of requests served by Plack process',
                [Sample('plack_number_served_requests', $self->labels, $counter)]);
        push @samples,
            MetricSamples('plack_total_kbytes_served', gauge => 'Total Kilobytes served by Plack process',
                [Sample('plack_total_kbytes_served', $self->labels, $total_kbytes)]);
    }

    # Obtain all worker process IDs
    @all_workers = ();
    my $psopt = $^O =~ m/bsd$/ ? '-ax' : '-e';
    my $ps = `LC_ALL=C command ps $psopt -o ppid,pid`;
    $ps =~ s/^\s+//mg;
    for my $line (split /\n/, $ps) {
        next if $line =~ m/^\D/;
        my ($ppid, $pid) = split /\s+/, $line, 2;
        push @all_workers, $pid if $ppid == $parent_pid;
    }

    # Count busy and idle workers
    my $idle = 0;
    my $busy = 0;
    my @process_status;
    for my $pid (@all_workers) {
        my $json = $stats->{$pid};
        $pstatus = eval {
            $JSON->decode($json || '{}');
        };
        $pstatus ||= {};
        if ($pstatus->{status} && $pstatus->{status} eq 'A') {
            $busy++;
        }
        else {
            $idle++;
        }

        if (defined $pstatus->{time}) {
            $pstatus->{ss} = time - $pstatus->{time};
        }
        $pstatus->{pid} ||= $pid;
        delete $pstatus->{time};
        delete $pstatus->{ppid};
        delete $pstatus->{uptime};
        push @process_status, $pstatus;
    }
    push @samples,
        MetricSamples('plack_busy_workers', gauge => 'Number of busy Plack workers',
            [Sample('plack_busy_workers', $self->labels, $busy)]);
    push @samples,
        MetricSamples('plack_idle_workers', gauge => 'Number of idle Plack workers',
            [Sample('plack_idle_workers', $self->labels, $idle)]);

    $stats = {};
    foreach my $pstatus (@process_status) {
        foreach my $stat (qw(method uri remote_addr protocol)) {
            $stats->{$stat}{$pstatus->{$stat}}++ if $pstatus->{$stat};
        }
    }
    foreach my $stat (qw(method uri remote_addr protocol)) {
        my $stat_counts = $stats->{$stat};
        push @samples,
            MetricSamples("plack_sample_$stat", gauge => "Count of $stat for sample of requests",
                [
                    map {
                        Sample(
                            "plack_sample_$stat",
                            [@{$self->labels}, $stat => $_],
                            $stat_counts->{$_}
                        )
                    }
                    (keys %$stat_counts)
                ]
            );
    }

    return @samples;
}

1;
__END__

=encoding utf-8

=head1 SYNOPSIS

    use Net::Prometheus::ServerStatusLiteCollector;

=head1 DESCRIPTION

Net::Prometheus::ServerStatusLiteCollector is ...

=head1 AUTHOR

Steven Leung E<lt>stvleung@gmail.comE<gt>

=cut



( run in 0.775 second using v1.01-cache-2.11-cpan-39bf76dae61 )