Files
scripts/Perl OTRS/Kernel/Modules/AdminPerformanceLog.pm
2024-10-14 00:08:40 +02:00

443 lines
15 KiB
Perl

# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::Modules::AdminPerformanceLog;
use strict;
use warnings;
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {%Param};
bless( $Self, $Type );
return $Self;
}
sub Run {
my ( $Self, %Param ) = @_;
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
# is performance log disabled?
if ( !$ConfigObject->Get('PerformanceLog') ) {
$LayoutObject->Block(
Name => 'Disabled',
Data => { %Param, },
);
# create & return output
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminPerformanceLog',
Data => \%Param,
);
$Output .= $LayoutObject->Footer();
return $Output;
}
$LayoutObject->Block(
Name => 'Enabled',
Data => { %Param, },
);
# reset log file
if ( $Self->{Subaction} eq 'Reset' ) {
# challenge token check for write action
$LayoutObject->ChallengeTokenCheck();
if ( !$Self->_DatabaseReset() ) {
$LayoutObject->FatalError();
}
else {
# redirect
return $LayoutObject->Redirect(
OP => "Action=$Self->{Action}",
);
}
}
# show detail view
elsif ( $Self->{Subaction} eq 'View' ) {
$LayoutObject->Block( Name => 'ActionList' );
$LayoutObject->Block( Name => 'ActionOverview' );
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
my %Action = ();
my $MaxRequest = 0;
my $Slot = 60;
my $MinuteSlot = $ParamObject->GetParam( Param => 'Minute' );
$Param{Minute} = $MinuteSlot;
my $Interface = $ParamObject->GetParam( Param => 'Interface' );
my $Module = $ParamObject->GetParam( Param => 'Module' );
if ( $MinuteSlot < 31 ) {
$Slot = 1;
}
elsif ( $MinuteSlot < 61 ) {
$Slot = 2;
}
elsif ( $MinuteSlot < 121 ) {
$Slot = 5;
}
elsif ( $MinuteSlot < 1141 ) {
$Slot = 30;
}
my $Data = $Self->_DatabaseRead();
$LayoutObject->Block(
Name => 'View',
Data => {
Age => $LayoutObject->CustomerAge(
Age => $MinuteSlot * 60,
Space => ' '
),
Interface => $Interface || '-',
Module => $Module || '-',
Period => $Slot,
},
);
$Param{Age} = $LayoutObject->CustomerAge(
Age => $MinuteSlot * 60,
Space => ' '
);
$Param{Interface} = $Interface;
$Param{Module} = $Module;
my $Minute = 0;
my $Count = 1;
while ( $Count <= $MinuteSlot ) {
ROW:
for my $Row ( reverse @{$Data} ) {
if (
$Row->[0] < ( time() - ( 60 * $Minute ) )
&& $Row->[0] > ( time() - ( 60 * ( $Minute + $Slot ) ) )
)
{
# for each action
my $ModuleCurrent = '';
if ( $Row->[4] =~ /^(.+?|)Action=(.+?)(&.*|)$/ ) {
$ModuleCurrent = $2;
if ( $Row->[4] =~ /Subaction=(.+?)(&.*|)$/ ) {
$ModuleCurrent .= '&' . $1;
}
if ($Interface) {
if ( !$Module && $Row->[1] ne $Interface ) {
next ROW;
}
if ( $Module && $Module ne $ModuleCurrent ) {
next ROW;
}
}
$Action{$Minute}->{Count}++;
if ( $MaxRequest < $Action{$Minute}->{Count} ) {
$MaxRequest = $Action{$Minute}->{Count};
}
if ( $Action{$Minute}->{Sum} ) {
$Action{$Minute}->{Sum} = $Action{$Minute}->{Sum} + $Row->[2];
}
else {
$Action{$Minute}->{Sum} = $Row->[2];
}
if ( !defined( $Action{$Minute}->{Max} ) ) {
$Action{$Minute}->{Max} = $Row->[2];
}
elsif ( $Action{$Minute}->{Max} < $Row->[2] ) {
$Action{$Minute}->{Max} = $Row->[2];
}
if ( !defined( $Action{$Minute}->{Min} ) ) {
$Action{$Minute}->{Min} = $Row->[2];
}
elsif ( $Action{$Minute}->{Min} > $Row->[2] ) {
$Action{$Minute}->{Min} = $Row->[2];
}
}
}
elsif ( $Row->[0] < ( time() - ( 60 * $Minute ) ) ) {
last ROW;
}
}
$Minute = $Minute + $Slot;
$Count = $Count + $Slot;
}
$Minute = 0;
$Count = 1;
while ( $Count <= $MinuteSlot ) {
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
$DateTimeObject->Subtract( Minutes => $Minute * 60 );
# set output class
if ( $Action{$Minute} ) {
my $Average = $Action{$Minute}->{Sum} / $Action{$Minute}->{Count};
$Average =~ s/^(.*\.\d\d).+?$/$1/g;
my $I = 100 / $MaxRequest;
my $W = $Action{$Minute}->{Count} * $I || 1;
$LayoutObject->Block(
Name => 'ViewRow',
Data => {
%{ $Action{$Minute} },
Average => $Average,
Date => $DateTimeObject->ToString(),
Width => $W . "%",
},
);
}
else {
$LayoutObject->Block(
Name => 'ViewRow',
Data => {
Min => 0,
Max => 0,
Count => $Action{$Minute}->{Count} || '0',
Average => 0,
Date => $DateTimeObject->ToString(),
Width => '0%',
},
);
}
$Minute = $Minute + $Slot;
$Count = $Count + $Slot;
}
# create & return output
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminPerformanceLog',
Data => \%Param,
);
$Output .= $LayoutObject->Footer();
return $Output;
}
# show overview
else {
# get avarage times
my $Data = [];
if ( $ConfigObject->Get('PerformanceLog') ) {
# check file size
if ( $Self->_DatabaseCheck() ) {
$LayoutObject->Block(
Name => 'Reset',
Data => {
Size => sprintf "%.1f MB",
( $Self->_DatabaseCheck() / ( 1024 * 1024 ) ),
},
);
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminPerformanceLog',
Data => \%Param,
);
$Output .= $LayoutObject->Footer();
return $Output;
}
else {
$Data = $Self->_DatabaseRead();
}
}
$LayoutObject->Block(
Name => 'Overview',
);
for my $Minute ( 5, 30, 60, 2 * 60, 24 * 60, 2 * 24 * 60 ) {
my %Count = ();
my %Action = ();
my %Sum = ();
my %Max = ();
my %Min = ();
ROW:
for my $Row ( reverse @{$Data} ) {
if ( $Row->[0] > time() - ( 60 * $Minute ) ) {
# whole
$Count{ $Row->[1] }++;
if ( $Sum{ $Row->[1] } ) {
$Sum{ $Row->[1] } = $Sum{ $Row->[1] } + $Row->[2];
}
else {
$Sum{ $Row->[1] } = $Row->[2];
}
if ( !defined( $Max{ $Row->[1] } ) ) {
$Max{ $Row->[1] } = $Row->[2];
}
elsif ( $Max{ $Row->[1] } < $Row->[2] ) {
$Max{ $Row->[1] } = $Row->[2];
}
if ( !defined( $Min{ $Row->[1] } ) ) {
$Min{ $Row->[1] } = $Row->[2];
}
elsif ( $Min{ $Row->[1] } > $Row->[2] ) {
$Min{ $Row->[1] } = $Row->[2];
}
# for each action
if ( $Row->[4] =~ /^(.+?|)Action=(.+?)(&.*|)$/ ) {
my $Module = $2;
if ( $Row->[4] =~ /Subaction=(.+?)(&.*|)$/ ) {
$Module .= '&' . $1;
}
$Action{$Module}->{Count}->{ $Row->[1] }++;
if ( $Action{$Module}->{Sum}->{ $Row->[1] } ) {
$Action{$Module}->{Sum}->{ $Row->[1] } = $Action{$Module}->{Sum}->{ $Row->[1] } + $Row->[2];
}
else {
$Action{$Module}->{Sum}->{ $Row->[1] } = $Row->[2];
}
if ( !defined( $Action{$Module}->{Max}->{ $Row->[1] } ) ) {
$Action{$Module}->{Max}->{ $Row->[1] } = $Row->[2];
}
elsif ( $Action{$Module}->{Max}->{ $Row->[1] } < $Row->[2] ) {
$Action{$Module}->{Max}->{ $Row->[1] } = $Row->[2];
}
if ( !defined( $Action{$Module}->{Min}->{ $Row->[1] } ) ) {
$Action{$Module}->{Min}->{ $Row->[1] } = $Row->[2];
}
elsif ( $Action{$Module}->{Min}->{ $Row->[1] } > $Row->[2] ) {
$Action{$Module}->{Min}->{ $Row->[1] } = $Row->[2];
}
}
}
else {
last ROW;
}
}
if (%Sum) {
$LayoutObject->Block(
Name => 'OverviewTable',
Data => {
Age =>
$LayoutObject->CustomerAge(
Age => $Minute * 60,
Space => ' '
),
},
);
}
for my $Interface (qw(Agent Customer Public)) {
if ( defined $Sum{$Interface} ) {
my $Average = $Sum{$Interface} / $Count{$Interface};
$Average =~ s/^(.*\.\d\d).+?$/$1/g;
$LayoutObject->Block(
Name => 'OverviewInterface',
Data => {
Interface => $Interface,
Average => $Average,
Count => $Count{$Interface} || 0,
Minute => $Minute,
Sum => $Sum{$Interface} || '0',
Max => $Max{$Interface} || '0',
Min => $Min{$Interface} || '0',
},
);
for my $Module ( sort keys %Action ) {
if ( defined $Action{$Module}->{Sum}->{$Interface} ) {
my $Average = $Action{$Module}->{Sum}->{$Interface}
/ $Action{$Module}->{Count}->{$Interface};
$Average =~ s/^(.*\.\d\d).+?$/$1/g;
$LayoutObject->Block(
Name => 'OverviewRow',
Data => {
Interface => $Interface,
Module => $Module,
Average => $Average,
Minute => $Minute,
Count => $Action{$Module}->{Count}->{$Interface} || '0',
Sum => $Action{$Module}->{Sum}->{$Interface} || '0',
Max => $Action{$Module}->{Max}->{$Interface} || '0',
Min => $Action{$Module}->{Min}->{$Interface} || '0',
},
);
}
}
}
}
}
# create & return output
my $Output = $LayoutObject->Header();
$Output .= $LayoutObject->NavigationBar();
$Output .= $LayoutObject->Output(
TemplateFile => 'AdminPerformanceLog',
Data => \%Param,
);
$Output .= $LayoutObject->Footer();
return $Output;
}
return;
}
sub _DatabaseCheck {
my ( $Self, %Param ) = @_;
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
my $File = $ConfigObject->Get('PerformanceLog::File');
# check file size
my $FileSize = -s $File;
if ( $FileSize > ( 1024 * 1024 * $ConfigObject->Get('PerformanceLog::FileMax') ) ) {
return $FileSize;
}
else {
return;
}
}
sub _DatabaseReset {
my ( $Self, %Param ) = @_;
my $File = $Kernel::OM->Get('Kernel::Config')->Get('PerformanceLog::File');
if ( !$Kernel::OM->Get('Kernel::System::Main')->FileDelete( Location => $File ) ) {
return;
}
else {
return 1;
}
}
sub _DatabaseRead {
my ( $Self, %Param ) = @_;
my @Data = ();
my $File = $Kernel::OM->Get('Kernel::Config')->Get('PerformanceLog::File');
my $ArrayRef = $Kernel::OM->Get('Kernel::System::Main')->FileRead(
Location => $File,
Mode => 'utf8', # optional - binmode|utf8
Result => 'ARRAY', # optional - SCALAR|ARRAY
);
if ($ArrayRef) {
for ( @{$ArrayRef} ) {
my $Line = $_;
my @Row = split( /::/, $Line );
push( @Data, \@Row );
}
}
return \@Data;
}
1;