circle-be

 view release on metacpan or  search on metacpan

lib/Circle/Loggable.pm  view on Meta::CPAN

);

__PACKAGE__->APPLY_Inheritable_Setting( log_path =>
   description => "Path template for log file name",
   type        => 'str',
);

use Struct::Dumb qw( readonly_struct );

# Data about the log file itself
readonly_struct LogId => [qw(
   path time_start time_until itempath line_timestamp_fmt
)];

# Data about logging from a particular item
readonly_struct LogCtx => [qw(
   path_residue
)];

our $NO_LOG = 0;

sub push_log
{
   my $self = shift;
   my ( $event, $time, $args ) = @_;

   return unless $self->setting_log_enabled;
   return if $NO_LOG;

   # Best-effort
   eval {
      my $logger = $self->logger( $time );

      my $ctx = $self->{logctx};

      $logger->log( $ctx, $time, $event, $args );
      1;
   } and return;

   {
      local $NO_LOG = 1;
      warn "Unable to log - $@";
   }
}

my %time_format_to_idx = (
   Y => 5,
   m => 4,
   d => 3,
   H => 2,
   M => 1,
   S => 0,
);

# Returns a LogId and a LogCtx
sub split_logpath
{
   my $self = shift;
   my ( $time ) = @_;

   my @pcs = split m{/}, $self->enumerable_path;
   shift @pcs; # trim leading /
   @pcs or @pcs = ( "Global" );
   my $path_used = 0;
   my %ts_used = map { $_ => 0 } qw( Y m d H M );

   my @timestamp = localtime $time;

   my %formats = (
      # Specific kinds of time format so we can track the granulity being used
      ( map {
         my $format = $_;
         $format => sub {
            $ts_used{$format}++;
            strftime( "%$format", @timestamp )
         };
        } qw( Y m d H M ) ),
      P => sub {
         my ( $limit ) = @_;
         defined $limit or $limit = @pcs;

         my $path_lower = $path_used;
         my $path_upper = $limit;

         $path_used = $path_upper if $path_upper > $path_used;

         return join '/', map { $_ // "" } @pcs[$path_lower..$path_upper-1];
      },
   );

   my $path = $self->setting_log_path;
   $path =~ s<%(?:{([^}]*)})?(.)>
             {exists $formats{$2} ? $formats{$2}->($1)
                                  : die "Unrecognised escape '%$2"}eg;

   # Reset to zero all the fields that aren't used
   $ts_used{$_} or $timestamp[$time_format_to_idx{$_}] = 0 for qw( Y m d H M S );
   $timestamp[3] or $timestamp[3] = 1; # mday is 1-based

   my $time_start = strftime( "%Y/%m/%d %H:%M:%S", @timestamp );

   # Increment the last timestamp field before a field not used in the file
   # path
   $ts_used{$_} or $timestamp[$time_format_to_idx{$_}+1]++, last for qw( m d H M S );
   my $time_until = mktime @timestamp;

   my $time_fmt_day = join "/", map { $ts_used{$_} ? () : ( "\%$_" ) } qw( Y m d );
   my $time_fmt_sec = join ":", map { $ts_used{$_} ? () : ( "\%$_" ) } qw( H M S );

   my $logid = LogId(
      $path,
      $time_start,
      $time_until,
      join( '/', grep { defined } @pcs[0..$path_used-1] ),
      join( " ", grep { length } $time_fmt_day, $time_fmt_sec ),
   );

   my $logctx = LogCtx(
      join( '/', grep { defined } @pcs[$path_used..$#pcs] ),
   );



( run in 1.167 second using v1.01-cache-2.11-cpan-71847e10f99 )