Web-ChromeLogger/lib/Web/ChromeLogger.pm
package Web::ChromeLogger;
use 5.008005;
use strict;
use warnings;
our $VERSION = "0.06";
use JSON::XS qw//;
use MIME::Base64 qw//;
sub new {
my $class = shift;
my %args = @_==1 ? %{$_[0]} : @_;
my $self = bless {
%args
}, $class;
# allow_unknown: Should not throw an exception if when it encounters values it cannot represent in JSON.
$self->{'json_encoder'} ||= JSON::XS->new()->ascii(1)->convert_blessed->allow_unknown;
$self->{'logs'} = [];
return $self;
}
sub json_encoder { $_[0]->{json_encoder} }
sub group {
my $self = shift;
$self->push_log('group', @_);
}
sub groupf {
my $self = shift;
my $format = shift;
$self->group(sprintf $format, @_);
}
sub group_end {
my $self = shift;
$self->push_log('groupEnd', @_);
}
sub group_endf {
my $self = shift;
my $format = shift;
$self->group_end(sprintf $format, @_);
}
sub group_collapsed {
my $self = shift;
$self->push_log('groupCollapsed', @_);
}
sub group_collapsedf {
my $self = shift;
my $format = shift;
$self->group_collapsed(sprintf $format, @_);
}
sub info {
my $self = shift;
$self->push_log('info', @_);
}
sub infof {
my $self = shift;
my $format = shift;
$self->info(sprintf $format, @_);
}
sub warn {
my $self = shift;
$self->push_log('warn', @_);
}
sub warnf {
my $self = shift;
my $format = shift;
$self->warn(sprintf $format, @_);
}
sub error {
my $self = shift;
$self->push_log('error', @_);
}
sub errorf {
my $self = shift;
my $format = shift;
$self->error(sprintf $format, @_);
}
# User can overwrite this method in child class.
sub to_json {
my ($self, $stuff) = @_;
"$stuff"
}
sub encode {
my ($self, $rows) = @_;
no warnings 'once';
local *UNIVERSAL::TO_JSON = sub { $self->to_json(@_) };
my $json_data = $self->json_encoder->encode(
{
"version" => "0.2",
"columns" => [ "log", "backtrace", "type" ],
"rows" => $rows,
},
);
my $mime_data = MIME::Base64::encode_base64($json_data);
$mime_data =~ s/\n//g;
return $mime_data;
}
sub wrap_by_group {
my ($self, $title) = @_;
$self->unshift_log('group', $title);
$self->push_log('groupEnd', $title);
}
sub wrap_by_groupf {
my $self = shift;
my $format = shift;
$self->wrap_by_group(sprintf $format, @_);
}
sub push_log {
my $self = shift;
push @{ $self->{logs} }, [ [ $_[1] ], $_[2], $_[0] ];
}
sub unshift_log {
my $self = shift;
unshift @{ $self->{logs} }, [ [ $_[1] ], $_[2], $_[0] ];
}
sub finalize {
my ($self) = @_;
$self->encode($self->{logs});
}
1;
__END__
=encoding utf-8
=head1 NAME
Web::ChromeLogger - ChromeLogger for Perl
=head1 SYNOPSIS
use Web::ChromeLogger;
get '/', sub {
my $logger = Web::ChromeLogger->new();
$logger->info('hey!');
$logger->infof('Hello, %s!', 'John');
my $html = render_html();
return [
200,
['X-ChromeLogger-Data' => $logger->finalize()],
$html,
];
};
=head1 DESCRIPTION
Web::ChromeLogger is a ChromeLogger library for Perl5.
Chrome Logger is a Google Chrome extension for debugging server side applications in the Chrome console.
=head1 HOW IT WORKS
This module generates the string for ChromeLogger. You can send the string in 'X-ChromeLogger-Data' header in HTTP response.
For more details, please see L<ChromeLogger's Technical Specification|http://craig.is/writing/chrome-logger/techspecs>
=head1 LARGE RESPONSE HEADER
=head2 NGINX PROXY
If you are using nginx as reverse proxy, you may need to set following parameters in your configuration file:
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
=head2 Maximum Data Size
Chrome has a limit of C<250kb> across all headers for a single request so that is the maximum amount of encoded data you can send.
=head1 METHODS
=over 4
=item C<< my $logger = Web::ChromeLogger->new(%args) >>
Create new instance with following parameters:
=over 4
=item json_encoder (Default: C<< JSON::XS->new()->ascii(1)->convert_blessed >> )
JSON encoder object. You can use JSON::XS or JSON::PP for this.
I guess you don't need to set this parameter.
=back
=item C<< $logger->group($title: Str) >>
=item C<< $logger->groupf($format: Str, @list) >>
Push C<group>.
=item C<< $logger->group_end($title: Str) >>
=item C<< $logger->group_endf($format: Str, @list) >>
Push C<groupEnd>.
=item C<< $logger->group_collapsed($title: Str) >>
=item C<< $logger->group_collapsedf($format: Str, @list) >>
Push C<groupCollapsed>.
=item C<< $logger->info($title: Str) >>
=item C<< $logger->infof($format: Str, @list) >>
Push C<info>.
=item C<< $logger->warn($title: Str) >>
=item C<< $logger->warnf($format: Str, @list) >>
Push C<warn>.
=item C<< $logger->error($title: Str) >>
=item C<< $logger->errorf($format: Str, @list) >>
Push C<error>.
=item C<< $logger->wrap_by_group($title: Str) >>
=item C<< $logger->wrap_by_groupf($format: Str, @list) >>
Wrap current logging data by C<$title> group.
=item C<< $logger->finalize() >>
Generate header string.
=back
=head1 LICENSE
Copyright (C) Tokuhiro Matsuno.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=head1 AUTHOR
Tokuhiro Matsuno E<lt>tokuhirom@gmail.comE<gt>
moznion
=head1 SEE ALSO
L<ChromeLogger|http://craig.is/writing/chrome-logger>
=cut