No description
This repository has been archived on 2026-08-22. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
  • Perl 89.4%
  • Raku 10.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jan Henning Thorsen 5a63e08f4c Wrote documentation
2018-04-16 06:22:26 -07:00
lib/Mojolicious/Plugin Wrote documentation 2018-04-16 06:22:26 -07:00
t Wrote documentation 2018-04-16 06:22:26 -07:00
.gitignore git ship start 2018-04-09 15:56:55 -07:00
.perltidyrc Add basic repo files 2018-04-09 16:10:55 -07:00
.ship.conf Renamed from ServerStatus to StatusForServer 2018-04-09 16:37:24 -07:00
.travis.yml Add basic repo files 2018-04-09 16:10:55 -07:00
Changes Renamed from ServerStatus to StatusForServer 2018-04-09 16:37:24 -07:00
cpanfile Renamed from ServerStatus to StatusForServer 2018-04-09 16:37:24 -07:00
MANIFEST.SKIP git ship start 2018-04-09 15:56:55 -07:00
README.pod Add README.pod 2018-04-09 16:38:43 -07:00

package Mojolicious::Plugin::StatusForServer;
use Mojo::Base 'Mojolicious::Plugin';

sub register {
  my ($self, $app, $config) = @_;

  my $app_class = ref $app;
  $app_class = 'Lite app' if $app_class eq 'Mojolicious::Lite';

  $config->{cache_module} ||= 'Cache::FastMmap';
  eval "require $config->{cache_module}";
  my $shared = $config->{cache_module}->new(%{$config->{cache_config}});

  $app->defaults(
    status_for_server => {
      app_name => $config->{app_name} // $app_class,
      os       => $^O,
      time     => {now => -1, restart => Mojo::Date->new($^T)},
      total    => $shared,
      version  => {
        app         => $config->{app_version} // $app_class->VERSION // undef,
        ev          => eval { require Mojo::Reactor::EV; 1 } ? $EV::VERSION : undef,
        mojolicious => $Mojolicious::VERSION,
        nnr => Mojo::IOLoop::Client->can_nnr ? $Net::DNS::Native::VERSION : undef,
        perl  => $^V,
        roles => Mojo::Base->ROLES ? $Role::Tiny::VERSION : undef,
        socks => Mojo::IOLoop::Client->can_socks ? $IO::Socket::Socks::VERSION : undef,
        tls   => Mojo::IOLoop::TLS->can_tls ? $IO::Socket::SSL::VERSION : undef,
      },
    }
  );

  push @{$app->renderer->classes}, __PACKAGE__;
  $app->routes->get($config->{route} || '/status' => \&_get_status);

  Mojo::IOLoop->next_tick(
    sub {
      my $worker = {start => Mojo::Date->new(time)->to_datetime};
      $shared->set("worker:$$", $worker);
      $app->hook(before_dispatch => $self->_before_dispatch_cb($shared, $worker));
    }
  );
}

sub _before_dispatch_cb {
  my ($self, $shared, $worker) = @_;

  return sub {
    my $c      = shift;
    my $method = lc $c->req->method;

    $shared->get_and_set("total:$method" => sub { ++$_[1] });
    $worker->{$method}++;

    $c->tx->on(
      finish => sub {
        my $tx = shift;
        my $code = $tx->res->code || '000';

        $worker->{$code}++;
        $shared->set("worker:$$", $worker);
        $shared->get_and_set("total:$code" => sub { ++$_[1] });
      }
    );
  };
}

sub _get_status {
  my $c      = shift;
  my $json   = $c->stash('status_for_server');
  my $shared = $json->{total};

  local $json->{time}{now} = Mojo::Date->new(time);
  local $json->{total}     = {};
  local $json->{workers}   = {};

  for my $shared_key ($shared->get_keys(0)) {
    my ($group, $key) = split /:/, $shared_key;

    if ($group eq 'worker') {
      if (kill 0, $key) {
        $json->{workers}{$key} = $shared->get($shared_key);
      }
      else {
        $shared->remove($shared_key);
      }
    }
    elsif ($group eq 'total') {
      $json->{total}{$key} = $shared->get($shared_key);
    }
  }

  if (($c->stash('format') || '') eq 'json') {
    local $json->{time}{now}     = $json->{time}{now}->to_datetime;
    local $json->{time}{restart} = $json->{time}{restart}->to_datetime;
    $c->render(json => $json);
  }
  else {
    $c->render(status_for_server => %$json);
  }
}

1;

=encoding utf8

=head1 NAME

Mojolicious::Plugin::StatusForServer - Get statistics from your mojolicious application

=head1 SYNOPSIS

  use Mojolicious::Lite;
  plugin status_for_server => {app_name => 'My cool app'};
  # ...
  app->start;

=head1 DESCRIPTION

L<Mojolicious::Plugin::StatusForServer> is a L<Mojolicious> plugin that will
track requests and responses, and render those statistics as either JSON or in
a plain text format.

It will also return information about the application and the system it is
running on. Example plain text response:

                      Mojolicious Server Status

  Application Version:       My cool app/4.2
  Mojolicious Version:       Mojolicious/7.71
  Perl Version:              v5.26.1/darwin
  EV Version:                4.22
  IO::Socket::Socks Version: 0.74
  IO::Socket::SSL Version:   2.051
  Net::DNS::Native Version:  n/a
  --------------------------------------------------------------------------
  Current Time: Mon, 16 Apr 2018 13:10:51 GMT
  Restart Time: Mon, 16 Apr 2018 13:10:50 GMT
  Server uptime: 9438s
  Workers: 4
  --------------------------------------------------------------------------
  Requests:  73
  Responses: 72

See the test suite for information about the JSON structure.

=head1 METHODS

=head2 register

  $self->register($app, \%config);

Called when registering this plugin in your L<Mojolicious> application.
C<%config> can have:

=over 2

=item * app_name

Default value is the class name of your application or "Lite app" if it is a
L<Mojolicious::Lite> application.

=item * app_version

Default value is C<$VERSION> in the application class or C<undef> if no version
has been provided.

=item * cache_config

EXPERIMENTAL.

=item * cache_module

EXPERIMENTAL.

=item * route

The resource path to get status for the server. Default value is "/status".

=back

=head1 AUTHOR

Jan Henning Thorsen

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2018, Jan Henning Thorsen

This program is free software, you can redistribute it and/or modify it under
the terms of the Artistic License version 2.0.

=cut

__DATA__
@@ status_for_server.html.ep
% use List::Util 'sum';
                    Mojolicious Server Status

Application Version:       <%= $app_name %>/<%= $version->{app} // '0.01' %>
Mojolicious Version:       Mojolicious/<%= $version->{mojolicious} %>
Perl Version:              <%= $version->{perl} %>/<%= $^O %>
EV Version:                <%= $version->{ev} // 'n/a' %>
IO::Socket::Socks Version: <%= $version->{socks} // 'n/a' %>
IO::Socket::SSL Version:   <%= $version->{tls} // 'n/a' %>
Net::DNS::Native Version:  <%= $version->{nnr} // 'n/a' %>
--------------------------------------------------------------------------
Current Time: <%= $time->{now} %>
Restart Time: <%= $time->{restart} %>
Server uptime: <%= $time->{now}->epoch - $time->{restart}->epoch %>s
Workers: <%= int keys %$workers %>
--------------------------------------------------------------------------
Requests:  <%= sum map { $total->{$_} } grep { /^[a-z]/ } keys %$total %>
Responses: <%= sum map { $total->{$_} } grep { /^[0-9]/ } keys %$total %>