feat: add full Zonemaster stack with Docker and Spanish UI
- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI) - Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend - Dockerfile.gui: Astro static build served via nginx - docker-compose.yml: backend (internal) + frontend (port 5353) - nginx.conf: root redirects to /es/, /api/ proxied to backend - zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
263
zonemaster-engine/lib/Zonemaster/Engine/Logger/Entry.pm
Normal file
263
zonemaster-engine/lib/Zonemaster/Engine/Logger/Entry.pm
Normal file
@@ -0,0 +1,263 @@
|
||||
package Zonemaster::Engine::Logger::Entry;
|
||||
|
||||
use v5.16.0;
|
||||
use warnings;
|
||||
|
||||
use version; our $VERSION = version->declare("v1.1.8");
|
||||
|
||||
use Carp qw( confess );
|
||||
use Time::HiRes qw[time];
|
||||
use JSON::PP;
|
||||
use Class::Accessor;
|
||||
|
||||
use Zonemaster::Engine::Profile;
|
||||
|
||||
use base qw(Class::Accessor);
|
||||
|
||||
use overload '""' => \&string;
|
||||
|
||||
our %numeric = (
|
||||
DEBUG3 => -2,
|
||||
DEBUG2 => -1,
|
||||
DEBUG => 0,
|
||||
INFO => 1,
|
||||
NOTICE => 2,
|
||||
WARNING => 3,
|
||||
ERROR => 4,
|
||||
CRITICAL => 5,
|
||||
);
|
||||
|
||||
our $start_time = time();
|
||||
|
||||
my $json = JSON::PP->new->allow_blessed->convert_blessed->canonical;
|
||||
my $test_levels_config;
|
||||
|
||||
__PACKAGE__->mk_ro_accessors(qw(tag args timestamp testcase module));
|
||||
|
||||
|
||||
sub new {
|
||||
my ( $proto, $attrs ) = @_;
|
||||
# tag, testcase and module required, args optional, other built
|
||||
|
||||
confess "Attribute \(tag\) is required"
|
||||
if !exists $attrs->{tag};
|
||||
|
||||
confess "Attribute \(testcase\) is required"
|
||||
if !exists $attrs->{testcase};
|
||||
|
||||
confess "Attribute \(module\) is required"
|
||||
if !exists $attrs->{module};
|
||||
|
||||
confess "Argument must be a HASHREF: args"
|
||||
if exists $attrs->{args}
|
||||
&& ref $attrs->{args} ne 'HASH';
|
||||
|
||||
my $time = time() - $start_time;
|
||||
$time =~ s/,/\./;
|
||||
$attrs->{timestamp} = $time;
|
||||
|
||||
# lazy attributes
|
||||
$attrs->{_level} = delete $attrs->{level} if exists $attrs->{level};
|
||||
|
||||
my $class = ref $proto || $proto;
|
||||
return Class::Accessor::new( $class, $attrs );
|
||||
}
|
||||
|
||||
sub level {
|
||||
my $self = shift;
|
||||
|
||||
# Lazy default value
|
||||
if ( !exists $self->{_level} ) {
|
||||
$self->{_level} = $self->_build_level();
|
||||
}
|
||||
|
||||
return $self->{_level}
|
||||
}
|
||||
|
||||
sub _build_level {
|
||||
my ( $self ) = @_;
|
||||
my $string;
|
||||
|
||||
if ( !defined $test_levels_config ) {
|
||||
$test_levels_config = Zonemaster::Engine::Profile->effective->get( q{test_levels} );
|
||||
}
|
||||
|
||||
if ( exists $test_levels_config->{ uc $self->module }{ $self->tag } ) {
|
||||
$string = uc $test_levels_config->{ uc $self->module }{ $self->tag };
|
||||
}
|
||||
else {
|
||||
$string = 'DEBUG';
|
||||
}
|
||||
|
||||
if ( defined $numeric{$string} ) {
|
||||
return $string;
|
||||
}
|
||||
else {
|
||||
die "Unknown level string: $string";
|
||||
}
|
||||
}
|
||||
|
||||
sub _set_level {
|
||||
my ( $self, $level ) = @_;
|
||||
|
||||
$self->{_level} = $level
|
||||
}
|
||||
|
||||
|
||||
sub numeric_level {
|
||||
my ( $self ) = @_;
|
||||
|
||||
return $numeric{ $self->level };
|
||||
}
|
||||
|
||||
sub levels {
|
||||
return %numeric;
|
||||
}
|
||||
|
||||
sub string {
|
||||
my ( $self ) = @_;
|
||||
|
||||
return sprintf( '%s%s:%s %s', $self->module, $self->testcase ? q{:} . $self->testcase : q{}, $self->tag, $self->argstr );
|
||||
}
|
||||
|
||||
sub argstr {
|
||||
my ( $self ) = @_;
|
||||
|
||||
my $argstr = q{};
|
||||
## no critic (TestingAndDebugging::ProhibitNoWarnings)
|
||||
no warnings 'uninitialized';
|
||||
|
||||
if ( $self->args ) {
|
||||
my $p_args = $self->printable_args;
|
||||
$argstr = join( q{; },
|
||||
map { $_ . q{=} . ( ref( $p_args->{$_} ) ? $json->encode( $p_args->{$_} ) : $p_args->{$_} ) }
|
||||
sort keys %{$p_args} );
|
||||
}
|
||||
|
||||
return $argstr;
|
||||
}
|
||||
|
||||
sub printable_args {
|
||||
my ( $self ) = @_;
|
||||
|
||||
if ( $self->args ) {
|
||||
my %p_args;
|
||||
foreach my $key_arg ( keys %{ $self->args } ) {
|
||||
if ( not ref( $self->args->{$key_arg} ) ) {
|
||||
$p_args{$key_arg} = $self->args->{$key_arg};
|
||||
}
|
||||
elsif ( $key_arg eq q{asn} and ref( $self->args->{$key_arg} ) eq q{ARRAY} ) {
|
||||
$p_args{q{asn}} = join( q{,}, @{ $self->args->{$key_arg} } );
|
||||
}
|
||||
else {
|
||||
$p_args{$key_arg} = $self->args->{$key_arg};
|
||||
}
|
||||
}
|
||||
return \%p_args;
|
||||
}
|
||||
|
||||
return;
|
||||
} ## end sub printable_args
|
||||
|
||||
###
|
||||
### Class method
|
||||
###
|
||||
|
||||
sub start_time_now {
|
||||
$start_time = time();
|
||||
return;
|
||||
}
|
||||
|
||||
sub reset_config {
|
||||
undef $test_levels_config;
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Zonemaster::Engine::Logger::Entry - module for single log entries
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Zonemaster::Engine->logger->add( TAG => { some => 'arguments' });
|
||||
|
||||
There should never be a need to create a log entry object in isolation. They should always be associated with and created via a logger object.
|
||||
|
||||
=head1 CLASS METHODS
|
||||
|
||||
=over
|
||||
|
||||
=item new
|
||||
|
||||
Construct a new object.
|
||||
|
||||
=item levels
|
||||
|
||||
Returns a hash where the keys are log levels as strings and the corresponding values their numeric value.
|
||||
|
||||
=item start_time_now()
|
||||
|
||||
Set the logger's start time to the current time.
|
||||
|
||||
=item reset_config()
|
||||
|
||||
Clear the test level cached configuration.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
=over
|
||||
|
||||
=item module
|
||||
|
||||
The name of the module associated to the entry, or "System".
|
||||
|
||||
=item testcase
|
||||
|
||||
The name of the test case which generated the entry, or "Unspecified".
|
||||
|
||||
=item tag
|
||||
|
||||
The tag that was set when the entry was created.
|
||||
|
||||
=item args
|
||||
|
||||
The argument hash reference that was provided when the entry was created.
|
||||
|
||||
=item timestamp
|
||||
|
||||
The time after the current program started running when this entry was created. This is a floating-point value with the precision provided by
|
||||
L<Time::HiRes>.
|
||||
|
||||
=item level
|
||||
|
||||
The log level associated to this log entry.
|
||||
|
||||
=back
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over
|
||||
|
||||
=item string
|
||||
|
||||
Simple method to generate a string representation of the log entry. Overloaded to the stringification operator.
|
||||
|
||||
=item argstr
|
||||
|
||||
Returns the string representation of the message arguments.
|
||||
|
||||
=item printable_args
|
||||
|
||||
Used to transform data from an internal/JSON representation to a "user friendly" representation one.
|
||||
|
||||
=item numeric_level
|
||||
|
||||
Returns the log level of the entry in numeric form.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user