/
Pipeline.pm6
113 lines (87 loc) · 2.91 KB
/
Pipeline.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
use v6.c;
use Log::Any::Adapter;
use Log::Any::Filter;
use Log::Any::Formatter;
=begin pod
=head1 Log::Any::Pipeline
A pipeline have to choose which Adapter will handle the log, depending on the
Log's attributes (category, severity, size of the message, etc.).
A pipeline is composed of elements, which contains an Adapter and possibly
a Filter, a Formatter and/or a Proxy.
=end pod
class Log::Any::Pipeline {
has @!adapters;
has $.asynchronous = False;
has Channel $!channel; # Channel used for asynchronicity
method TWEAK {
if $!asynchronous {
$!channel = Channel.new;
$!channel.Supply.tap( -> %params {
self!dispatch-synchronous( |%params );
} );
}
}
method add( Log::Any::Adapter $a, Log::Any::Filter :$filter, Log::Any::Formatter :$formatter, :$continue-on-match = False ) {
#note "{now} adding adapter $a.WHAT().^name()";
my %elem = adapter => $a;
if $filter.defined {
%elem{'filter'} = $filter;
}
if $formatter.defined {
%elem{'formatter'} = $formatter;
}
if $continue-on-match {
%elem{'continue-on-match'} = True ;
}
push @!adapters, %elem;
}
=begin pod
=head2 get-available-adapters
This method returns the next element of the pipeline wich is matching
the filter.
=end pod
method !get-available-adapters( :$msg, :$severity, :$category, :%extra-fields ) {
return gather for @!adapters -> %elem {
# Filter : check if the adapter meets the requirements
with %elem{'filter'} {
next unless %elem{'filter'}.filter( :$msg, :$severity, :$category, :%extra-fields );
}
# Without filter, it's ok
take %elem;
}
}
method dispatch( DateTime :$date-time!, :$msg!, :$severity!, :$category!, :%extra-fields ) {
# note "Dispatching $msg, adapter count : @!adapters.elems(), asynchronicity $!asynchronous.perl() at {now}";
if $!asynchronous {
# note "async dispatch";
$!channel.send( { :$date-time, :$msg, :$severity, :$category } );
} else {
# note "sync dispatch";
return self!dispatch-synchronous( :$date-time, :$msg, :$severity, :$category, :%extra-fields );
}
}
method !dispatch-synchronous( :$date-time!, :$msg! is copy, :$severity!, :$category!, :%extra-fields ) {
for self!get-available-adapters( :$msg, :$severity, :$category ) -> %elem {
if %elem {
# Escape newlines caracters in message
$msg ~~ s:g/ \n /\\n/;
# Formatter
my $msgToHandle = $msg;
if %elem{'formatter'} {
$msgToHandle = %elem{'formatter'}.format( :$date-time, :$msg, :$category, :$severity, :%extra-fields );
}
# Proxies
# Handling
%elem{'adapter'}.handle( $msgToHandle );
}
last unless %elem{'continue-on-match'};
}
}
method will-dispatch( :$severity, :$category, :%extra-fields ) returns Bool {
return self!get-available-adapters( :$severity, :$category, :%extra-fields ).so;
}
# Dump the adapters
multi method gist( Log::Any::Pipeline:D: ) {
return 'Log::Any::Pipeline.new(adapters => ' ~ @!adapters.gist ~ ')';
}
}