1# <@LICENSE>
2# Licensed to the Apache Software Foundation (ASF) under one or more
3# contributor license agreements.  See the NOTICE file distributed with
4# this work for additional information regarding copyright ownership.
5# The ASF licenses this file to you under the Apache License, Version 2.0
6# (the "License"); you may not use this file except in compliance with
7# the License.  You may obtain a copy of the License at:
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16# </@LICENSE>
17
18=head1 NAME
19
20Mail::SpamAssassin::Logger::Stderr - log to standard error
21
22=head1 SYNOPSIS
23
24  loadplugin     Mail::SpamAssassin::Logger::Stderr
25
26=head1 DESCRIPTION
27
28=cut
29
30package Mail::SpamAssassin::Logger::Stderr;
31
32use strict;
33use warnings;
34# use bytes;
35use re 'taint';
36
37use POSIX ();
38use Time::HiRes ();
39use Mail::SpamAssassin::Logger;
40
41our @ISA = ();
42
43# ADDING OS-DEPENDENT LINE TERMINATOR - BUG 6456
44
45# Using Mail::SpamAssassin::Util::am_running_on_windows() leads to circular
46# dependencies. So, we are duplicating the code instead.
47use constant RUNNING_ON_WINDOWS => ($^O =~ /^(?:mswin|dos|os2)/oi);
48
49my $eol = "\n";
50if (RUNNING_ON_WINDOWS) {
51  $eol = "\r\n";
52}
53
54sub new {
55  my $class = shift;
56
57  $class = ref($class) || $class;
58  my $self = { };
59  bless ($self, $class);
60
61  my %params = @_;
62  $self->{timestamp_fmt} = $params{timestamp_fmt};
63  $self->{escape} = $params{escape} if exists $params{escape};
64
65  return($self);
66}
67
68sub log_message {
69  my ($self, $level, $msg, $ts) = @_;
70
71  my $timestamp;
72  my $fmt = $self->{timestamp_fmt};
73  my $now = defined $ts ? $ts : Time::HiRes::time;
74  if (!defined $fmt) {
75    # default since 3.3.0
76    my $datetime = POSIX::strftime("%b %d %H:%M", localtime($now));
77    utf8::encode($datetime)  if utf8::is_utf8($datetime);  # Bug 7305
78    $timestamp = sprintf("%s:%06.3f", $datetime, $now-int($now/60)*60);
79    # Bug 6329: %e is not in a POSIX standard, use %d instead and edit
80    local $1; $timestamp =~ s/^(\S+\s+)0/$1 /;
81  } elsif ($fmt eq '') {
82    $timestamp = '';
83  } else {
84    $timestamp = POSIX::strftime($fmt, localtime($now));
85  }
86  $timestamp .= ' '  if $timestamp ne '';
87
88  if ($self->{escape}) {
89    # Bug 6583, escape
90    Mail::SpamAssassin::Logger::escape_str($msg);
91  } elsif (!exists $self->{escape}) {
92    # Backwards compatible pre-4.0 escaping, if $escape not given.
93    # replace control characters with "_", tabs and spaces get
94    # replaced with a single space.
95    $msg =~ tr/\x09\x20\x00-\x1f/  _/s;
96  }
97
98  my($nwrite) = syswrite(STDERR, sprintf("%s[%d] %s: %s%s",
99                                         $timestamp, $$, $level, $msg, $eol));
100  defined $nwrite  or warn "error writing to log file: $!";
101}
102
103sub close_log {
104  my ($self) = @_;
105}
106
1071;
108