/
AccessLog.pm6
121 lines (87 loc) · 2.98 KB
/
AccessLog.pm6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use v6;
use Apache::LogFormat;
use Crust::Middleware;
unit class Crust::Middleware::AccessLog is Crust::Middleware;
has $.formatter;
has &.logger;
method new(Callable $app, *%opts) {
my Apache::LogFormat::Formatter $formatter;
given %opts<format> {
when any(!.Bool, "combined")
{ $formatter = Apache::LogFormat.combined }
when "common" { $formatter = Apache::LogFormat.common }
when Apache::LogFormat::Compiler {
$formatter = %opts<format>;
}
default {
my $c = Apache::LogFormat::Compiler.new();
$formatter = $c.compile(%opts<format>);
}
}
%opts<format>:delete;
%opts<formatter> = $formatter;
callwith($app, |%opts);
}
my sub content-length(@res) {
for @(@res[1]) -> $pair {
if $pair.key.lc eq 'content-length' {
return $pair.value;
}
}
return "-";
}
method CALL-ME(%env) {
start {
my $t0 = DateTime.now.Instant;
my @res = await $.app()(%env);
# '%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"'
my $logger = $.logger;
if !$logger.defined {
$logger = sub ($s) { %env<p6w.errors>.emit($s) };
}
my $cl = content-length(@res);
my $now = DateTime.now;
my $line = $.formatter().format(%env, @res, $cl, $now.Instant - $t0, $now);
$logger($line);
@res;
};
}
=begin pod
=head1 NAME
Crust::Middleware::AccessLog - Middleware To Generate Access Logs
=head1 SYNOPSIS
my &app = sub(%env) { ... };
my $code = Crust::Middleware::AccessLog.new(
&app,
:format('combined'),
:logger(-> $s { $io.print($s) }),
}
Or use with builder
enable 'AccessLog', :format('combined'), :logger(-> $log-line { ... });
=head1 DESCRIPTION
Crust::Middleware::AccessLog forwards the request to the given app and
logs request and response details to the logger callback. The format
can be specified using Apache-like format strings (or C<combined> or
C<common> for the default formats). If none is specified C<combined> is
used.
This middleware is enabled by default when you run L<crustup> as a
default C<development> environment.
=head1 CONFIGURATION
=item format :Str
enable "AccessLog", :format('combined');
enable "AccessLog", :format('common');
enable "AccessLog", :format('%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"');
Takes a format string (or a preset template C<combined> or C<custom>)
to specify the log format. This middleware uses L<Apache::LogFormat::Compiler> to
generate access_log lines. See more details on perldoc L<Apache::LogFormat::Compiler>
=item logger :Callable
my $logger = ...; # some logging tool
enable "AccessLog",
:logger(-> sub ($s) { $logger->log($s ... ) };
Sets a callback to print log message to. It prints to the C<p6w.errors>
output stream by default.
=head1 AUTHORS
Daisuke Maki
=head1 SEE ALSO
L<Apache::LogFormat::Compiler>, L<http://httpd.apache.org/docs/2.2/mod/mod_log_config.html>
=end pod