File Coverage

blib/lib/Log/Radis.pm
Criterion Covered Total %
statement 48 52 92.3
branch 17 20 85.0
condition 4 6 66.6
subroutine 10 11 90.9
pod 2 2 100.0
total 81 91 89.0


line stmt bran cond sub pod time code
1 1     1   77477 use strictures 2;
  1         6  
  1         34  
2              
3             package Log::Radis;
4              
5             # ABSTRACT: Radis is a graylog logging radio through a redis database
6              
7 1     1   636 use Moo 2;
  1         6009  
  1         4  
8 1     1   1551 use Redis 1.980;
  1         32631  
  1         34  
9 1     1   6 use JSON 2.90 qw(encode_json);
  1         16  
  1         5  
10 1     1   111 use Time::HiRes 1.9726;
  1         14  
  1         6  
11 1     1   485 use Sys::Hostname ;
  1         744  
  1         49  
12 1     1   4 use Carp qw(croak carp);
  1         2  
  1         39  
13 1     1   485 use Types::Standard 1 qw(HasMethods);
  1         46496  
  1         9  
14              
15             our $GELF_SPEC_VERSION = '1.1';
16             our $HOSTNAME = hostname();
17              
18             our $VERSION = '0.001'; # VERSION
19              
20              
21              
22             has server => (
23             is => 'ro',
24             default => 'localhost:6379',
25             );
26              
27              
28             has reconnect => (
29             is => 'ro',
30             default => 5,
31             );
32              
33              
34             has every => (
35             is => 'ro',
36             default => 1,
37             );
38              
39              
40             has queue => (
41             is => 'ro',
42             default => 'graylog-radis:queue',
43             );
44              
45              
46             has redis => (
47             is => 'lazy',
48             isa => HasMethods[qw[ lpush ]],
49             builder => sub {
50 0     0   0 my $self = shift;
51 0         0 return Radis->new(
52             server => $self->server,
53             reconnect => $self->reconnect,
54             every => $self->every,
55             );
56             }
57             );
58              
59              
60             my %levels = (
61             fatal => 1,
62             emerg => 1,
63             emergency => 1,
64              
65             alert => 2,
66              
67             crit => 2,
68             critical => 3,
69              
70             error => 4,
71             err => 4,
72              
73             warn => 5,
74             warning => 5,
75              
76             note => 6,
77             notice => 6,
78              
79             info => 7,
80              
81             debug => 8,
82              
83             trace => 9,
84             core => 9,
85             );
86              
87              
88             sub log {
89 25     25 1 106454 my $self = shift;
90 25         41 my ($level, $message, %gelf) = @_;
91              
92 25 100       55 croak "log message without level" unless defined $level;
93 24 100       38 croak "log message without message" unless defined $message;
94              
95             # replace level with numeric code, if needed
96 23 50       68 $level = $levels{lc($level)} unless $level =~ m{^\d$};
97              
98             # addiotional field are only allowed with a prefixed underscore
99             # and strip off all unallowed chars
100             %gelf = map {
101             m{^_[\w\.\-]+$}i
102             ?
103             (
104             lc($_)
105             ,
106             $gelf{$_}
107             )
108             :
109             (
110             '_'.s{[^\w\.\-]+}{}gr
111             ,
112 5 50       27 $gelf{$_}
113             )
114 23         46 } grep { defined $gelf{$_} } keys %gelf;
  5         9  
115              
116             # graylog omit the id field automatically
117 23 50       33 if (exists $gelf{_id}) {
118 0         0 carp "log message with id is not allowed";
119 0         0 delete $gelf{_id};
120             }
121              
122             # preserve params, which are allowed by client
123             # including some mispelled ones
124 23 100       32 $gelf{host} = delete $gelf{_hostname} if defined $gelf{_hostname};
125 23 100       55 $gelf{host} = delete $gelf{_host} if defined $gelf{_host};
126 23 100       32 $gelf{timestamp} = delete $gelf{_time} if defined $gelf{_time};
127 23 100       28 $gelf{timestamp} = delete $gelf{_timestamp} if defined $gelf{_timestamp};
128              
129             # hostname defaults to system hostname...
130 23   66     64 $gelf{host} //= $HOSTNAME;
131              
132             # ...and timestamp with milliseconds by default
133 23   66     66 $gelf{timestamp} //= Time::HiRes::time();
134              
135             # graylog seems to have problems with float values in json
136             # so force string, which works fine
137 23         125 $gelf{timestamp} = ''.$gelf{timestamp};
138              
139 23         20 $gelf{short_message} = $message;
140 23         19 $gelf{version} = $GELF_SPEC_VERSION;
141 23         22 $gelf{level} = $level;
142              
143 23         43 $self->push(\%gelf);
144             }
145              
146              
147             sub push {
148 24     24 1 1920 my ($self, $gelf) = @_;
149 24 100       42 if (ref $gelf eq 'HASH') {
150 23         94 $gelf = encode_json($gelf);
151             }
152 24         409 $self->redis->lpush($self->queue, $gelf);
153             }
154              
155             1;
156              
157             __END__