2017-10-20 04:19:32 +00:00
package Anvil::Tools::Alert ;
2017-05-02 04:41:12 +00:00
#
# This module contains methods used to handle alerts and errors.
#
use strict ;
use warnings ;
2017-08-17 21:16:45 +00:00
use Scalar::Util qw( weaken isweak ) ;
2017-05-02 04:41:12 +00:00
our $ VERSION = "3.0.0" ;
my $ THIS_FILE = "Alert.pm" ;
### Methods;
2017-07-20 06:00:40 +00:00
# check_alert_sent
2017-05-02 04:41:12 +00:00
# error
2018-12-29 08:23:58 +00:00
# register
2017-05-02 04:41:12 +00:00
= pod
= encoding utf8
= head1 NAME
2017-10-20 04:19:32 +00:00
Anvil::Tools:: Alert
2017-05-02 04:41:12 +00:00
2018-05-15 05:55:56 +00:00
Provides all methods related to warnings and alerts .
2017-05-02 04:41:12 +00:00
= head1 SYNOPSIS
2017-10-20 04:19:32 +00:00
use Anvil::Tools ;
2017-05-02 04:41:12 +00:00
2017-10-20 04:19:32 +00:00
# Get a common object handle on all Anvil::Tools modules.
my $ anvil = Anvil::Tools - > new ( ) ;
2017-05-02 04:41:12 +00:00
2017-10-20 04:19:32 +00:00
# Access to methods using '$anvil->Alert->X'. Example using 'find';
my $ foo_path = $ anvil - > Storage - > find ( { file = > "foo" } ) ;
2017-05-02 04:41:12 +00:00
= head1 METHODS
Methods in the core module ;
= cut
sub new
{
my $ class = shift ;
my $ self = { } ;
bless $ self , $ class ;
return ( $ self ) ;
}
2017-10-20 04:19:32 +00:00
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more
2017-05-02 04:41:12 +00:00
# sense in this case to think of it as a parent.
sub parent
{
my $ self = shift ;
my $ parent = shift ;
$ self - > { HANDLE } { TOOLS } = $ parent if $ parent ;
2017-08-17 21:16:45 +00:00
# Defend against memory leads. See Scalar::Util'.
if ( not isweak ( $ self - > { HANDLE } { TOOLS } ) )
{
2019-08-07 03:31:35 +00:00
weaken ( $ self - > { HANDLE } { TOOLS } ) ;
2017-08-17 21:16:45 +00:00
}
2017-05-02 04:41:12 +00:00
return ( $ self - > { HANDLE } { TOOLS } ) ;
}
#############################################################################################################
# Public methods #
#############################################################################################################
2017-07-20 06:00:40 +00:00
= head2 check_alert_sent
This is used by scan agents that need to track whether an alert was sent when a sensor dropped below / rose above a set alert threshold . For example , if a sensor alerts at 20 ° C and clears at 25 ° C , this will be called when either value is passed . When passing the warning threshold , the alert is registered and sent to the user . Once set , no further warning alerts are sent . When the value passes over the clear threshold , this is checked and if an alert was previously registered , it is removed and an "all clear" message is sent . In this way , multiple alerts will not go out if a sensor floats around the warning threshold and a "cleared" message won ' t be sent unless a "warning" message was previously sent .
2017-08-02 01:04:35 +00:00
If there is a problem , C << ! ! error ! ! >> is returned .
2017-07-20 06:00:40 +00:00
Parameters ;
2018-09-25 06:05:07 +00:00
= head3 modified_date ( optional )
2017-07-20 06:00:40 +00:00
2018-08-15 20:57:57 +00:00
By default , this is set to C << sys::database:: timestamp >> . If you want to force a different timestamp , you can do so with this parameter .
2017-07-20 06:00:40 +00:00
= head3 name ( required )
This is the name of the alert . So for an alert related to a critically high temperature , this might get set to C << temperature_high_critical >> . It is meant to compliment the C << record_locator >> parameter .
= head3 record_locator
This is a record locator , which generally allows a given alert to be tied to a given source . For example , an alert related to a temperature might use C << an - a01n01 . alteeve . com:cpu1_temperature >> .
= head3 set_by ( required )
This is a string , usually the name of the program , that set the alert . Usuall this is simple C << $ THIS_FILE >> or C << $ 0 >> .
= head3 type ( required )
This is set to C << set >> or C << clear >> .
If set to C << set >> , C << 1 >> will be returned if this is the first time we ' ve tried to set this alert . If the alert was set before , C << 0 >> is returned .
If set to C << clear >> , C << 1 >> will be returned if this is the alert existed and was cleared . If the alert didn 't exist (and thus didn' t need to be cleared ) , C << 0 >> is returned .
= cut
sub check_alert_sent
{
my $ self = shift ;
my $ parameter = shift ;
2018-03-07 08:11:55 +00:00
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self - > parent ;
2017-07-20 06:00:40 +00:00
2018-09-25 06:05:07 +00:00
my $ modified_date = defined $ parameter - > { modified_date } ? $ parameter - > { modified_date } : $ anvil - > data - > { sys } { database } { timestamp } ;
2017-12-27 17:01:58 +00:00
my $ name = defined $ parameter - > { name } ? $ parameter - > { name } : "" ;
my $ record_locator = defined $ parameter - > { record_locator } ? $ parameter - > { record_locator } : "" ;
my $ set_by = defined $ parameter - > { set_by } ? $ parameter - > { set_by } : "" ;
my $ type = defined $ parameter - > { type } ? $ parameter - > { type } : "" ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2018-09-25 06:05:07 +00:00
modified_date = > $ modified_date ,
2017-07-20 06:00:40 +00:00
name = > $ name ,
record_locator = > $ record_locator ,
set_by = > $ set_by ,
type = > $ type ,
} } ) ;
# Do we have a timestamp?
2018-09-25 06:05:07 +00:00
if ( not $ modified_date )
2017-07-20 06:00:40 +00:00
{
# Nope
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0093" } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
# Do we have an alert name?
if ( not $ name )
{
# Nope
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->check_alert_sent()" , parameter = > "name" } } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
# Do we have an record locator?
if ( not $ record_locator )
{
# Nope
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->check_alert_sent()" , parameter = > "record_locator" } } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
# Do we know who is setting this??
if ( not $ set_by )
{
# Nope
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->check_alert_sent()" , parameter = > "set_by" } } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
# Are we setting or clearing?
if ( not $ type )
{
# Neither...
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0097" } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
# This will get set to '1' if an alert is added or removed.
my $ set = 0 ;
my $ query = "
SELECT
2017-12-27 17:01:58 +00:00
alert_sent_uuid
2017-07-20 06:00:40 +00:00
FROM
alert_sent
WHERE
2019-03-06 06:49:59 +00:00
alert_sent_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})."
2017-07-20 06:00:40 +00:00
AND
2019-03-06 06:49:59 +00:00
alert_set_by = ".$anvil->Database->quote($set_by)."
2017-07-20 06:00:40 +00:00
AND
2019-03-06 06:49:59 +00:00
alert_record_locator = ".$anvil->Database->quote($record_locator)."
2017-07-20 06:00:40 +00:00
AND
2019-03-06 06:49:59 +00:00
alert_name = ".$anvil->Database->quote($name)."
2017-07-20 06:00:40 +00:00
; " ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { query = > $ query } } ) ;
2017-07-20 06:00:40 +00:00
2017-08-02 07:00:08 +00:00
# Now, if this is type=set, register the alert if it doesn't exist. If it is type=clear, remove the
# alert if it exists.
2017-12-27 17:01:58 +00:00
my $ alert_sent_uuid = $ anvil - > Database - > query ( { query = > $ query , source = > $ THIS_FILE , line = > __LINE__ } ) - > [ 0 ] - > [ 0 ] ;
$ alert_sent_uuid = "" if not defined $ alert_sent_uuid ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
type = > $ type ,
alert_sent_uuid = > $ alert_sent_uuid ,
2017-07-20 06:00:40 +00:00
} } ) ;
2017-12-27 17:01:58 +00:00
if ( ( $ type eq "set" ) && ( not $ alert_sent_uuid ) )
2017-07-20 06:00:40 +00:00
{
### New alert
# Make sure this host is in the database... It might not be on the very first run of ScanCore
# before the peer exists (tried to connect to the peer, fails, tries to send an alert, but
# this host hasn't been added because it is the very first attempt to connect...)
2017-10-20 04:19:32 +00:00
if ( not $ anvil - > data - > { sys } { host_is_in_db } )
2017-07-20 06:00:40 +00:00
{
my $ query = "
SELECT
COUNT ( * )
FROM
hosts
WHERE
2019-03-06 06:49:59 +00:00
host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})."
2017-07-20 06:00:40 +00:00
; " ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { query = > $ query } } ) ;
2017-07-20 06:00:40 +00:00
2017-10-20 04:19:32 +00:00
my $ count = $ anvil - > Database - > query ( { query = > $ query , source = > $ THIS_FILE , line = > __LINE__ } ) - > [ 0 ] - > [ 0 ] ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { count = > $ count } } ) ;
2017-07-20 06:00:40 +00:00
if ( not $ count )
{
# Too early, we can't set an alert.
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "alert" , key = > "log_0098" , variables = > {
2017-08-04 05:45:56 +00:00
type = > $ type ,
set_by = > $ set_by ,
record_locator = > $ record_locator ,
name = > $ name ,
2018-09-25 06:05:07 +00:00
modified_date = > $ modified_date ,
2017-07-20 06:00:40 +00:00
} } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
else
{
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { sys } { host_is_in_db } = 1 ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { 'sys::host_is_in_db' = > $ anvil - > data - > { sys } { host_is_in_db } } } ) ;
2017-07-20 06:00:40 +00:00
}
}
$ set = 1 ;
my $ query = "
INSERT INTO
alert_sent
(
2017-12-27 17:01:58 +00:00
alert_sent_uuid ,
2017-07-20 06:00:40 +00:00
alert_sent_host_uuid ,
alert_set_by ,
alert_record_locator ,
alert_name ,
2018-09-25 06:05:07 +00:00
modified_date
2017-07-20 06:00:40 +00:00
) VALUES (
2019-03-06 06:49:59 +00:00
".$anvil->Database->quote($anvil->Get->uuid)." ,
".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." ,
".$anvil->Database->quote($set_by)." ,
".$anvil->Database->quote($record_locator)." ,
".$anvil->Database->quote($name)." ,
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
2017-07-20 06:00:40 +00:00
) ;
" ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2017-07-20 06:00:40 +00:00
query = > $ query ,
set = > $ set ,
} } ) ;
2017-10-20 04:19:32 +00:00
$ anvil - > Database - > write ( { query = > $ query , source = > $ THIS_FILE , line = > __LINE__ } ) ;
2017-07-20 06:00:40 +00:00
}
2017-12-27 17:01:58 +00:00
elsif ( ( $ type eq "clear" ) && ( $ alert_sent_uuid ) )
2017-07-20 06:00:40 +00:00
{
# Alert previously existed, clear it.
$ set = 1 ;
my $ query = "
DELETE FROM
alert_sent
WHERE
2019-03-06 06:49:59 +00:00
alert_sent_uuid = ".$anvil->Database->quote($alert_sent_uuid)."
2017-07-20 06:00:40 +00:00
; " ;
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2017-07-20 06:00:40 +00:00
query = > $ query ,
set = > $ set ,
} } ) ;
2017-10-20 04:19:32 +00:00
$ anvil - > Database - > write ( { query = > $ query , source = > $ THIS_FILE , line = > __LINE__ } ) ;
2017-07-20 06:00:40 +00:00
}
2017-12-27 17:01:58 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { set = > $ set } } ) ;
2017-07-20 06:00:40 +00:00
return ( $ set ) ;
}
2018-12-29 08:23:58 +00:00
= head2 register
2017-07-20 06:00:40 +00:00
This registers an alert to be sent later .
2018-12-18 23:20:49 +00:00
The C << alert_uuid >> is returned on success . If anything goes wrong , C << ! ! error ! ! >> will be returned .
Parameters ;
= head3 alert_level ( required )
This assigns an severity level to the alert . Any recipient listening to this level or higher will receive this alert .
= head4 1 ( critical )
Alerts at this level will go to all recipients , except for those ignoring the source system entirely .
This is reserved for alerts that could lead to imminent service interruption or unexpected loss of redundancy .
Alerts at this level should trigger alarm systems for all administrators as well as management who may be impacted by service interruptions .
= head4 2 ( warning )
This is used for alerts that require attention from administrators . Examples include intentional loss of redundancy caused by load shedding , hardware in pre - failure , loss of input power , temperature anomalies , etc .
Alerts at this level should trigger alarm systems for administrative staff .
= head4 3 ( notice )
This is used for alerts that are generally safe to ignore , but might provide early warnings of developing issues or insight into system behaviour .
Alerts at this level should not trigger alarm systems . Periodic review is sufficient .
= head4 4 ( info )
This is used for alerts that are almost always safe to ignore , but may be useful in testing and debugging .
2018-12-29 08:23:58 +00:00
= head3 clear_alert ( optional , default '0' )
If set , this indicate that the alert has returned to an OK state . Alert level is still honoured for notification target delivery decisions , but some internal values are adjusted .
2018-12-18 23:20:49 +00:00
= head3 message ( required )
This is the message body of the alert . It is expected to be in the format C << <string_key> >> . If variables are to be injected into the C << string_key >> , a comma - separated list in the format C << ! ! variable_name1 ! value1 ! ! [ , ! ! variable_nameN ! valueN ! ! ] >> is used .
Example with a message alone ; C << foo_0001 >> .
Example with two variables ; C << foo_0002 , ! ! bar ! abc ! ! , ! ! baz ! 123 ! ! >> .
= head3 set_by ( required )
This is the name of the program that registered this alert . Usually this is simply the caller ' s C << $ THIS_FILE >> or C << $ 0 >> variable .
= head3 show_header ( optional , default '1' )
When set to C << 0 >> , only the alert message body is shown , and the title is omitted . This can be useful when a set of alerts are sorted under a common title .
= head3 sort_position ( optional , default '9999' )
This is used to keep a set of alerts in a certain order when converted to an message body . By default , all alerts have a default value of '9999' , so they will be sorted using their severity level , and then the time they were entered into the system . If this is set to a number lower than this , then the value here will sort /prioritize messages over the severity/ time values . If two or more alerts have the same sort position , then severity and then time stamps will be used .
In brief ; alert messages are sorted in this order ;
1 . C << sort_position >>
2 . c << alert_level >>
3 . C << timestamp >>
2019-01-06 01:57:44 +00:00
NOTE: All C << sort_position >> values are automatically zero - padded ( ie: C << 12 >> - > C << 0012 >> ) to ensure accurate sorting . If you plan to use values greater than C << 9999 >> , be sure to manually zero - pad your numbers . ( Or , better , find a way to make shorter alerts ... ) .
2018-12-18 23:20:49 +00:00
NOTE: The timestamp is generally set for a given program or agent run ( set when connecting to the database ) , NOT by the real time of the database insert . For this reason , relying on the timestamp alone will not generally give the desired results , and why C << sort_position >> exists .
= head3 title ( optional )
NOTE: This is required if C << show_header >> is set !
This is the title of the alert . It is expected to be in the format C << <string_key> >> . If variables are to be injected into the C << string_key >> , a comma - separated list in the format C << ! ! variable_name1 ! value1 ! ! [ , ! ! variable_nameN ! valueN ! ! ] >> is used .
Example with a message alone ; C << foo_0001 >> .
Example with two variables ; C << foo_0002 , ! ! bar ! abc ! ! , ! ! baz ! 123 ! ! >> .
2017-07-20 06:00:40 +00:00
= cut
2018-12-29 08:23:58 +00:00
sub register
2017-07-20 06:00:40 +00:00
{
my $ self = shift ;
my $ parameter = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self - > parent ;
2018-12-18 23:20:49 +00:00
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
2017-07-20 06:00:40 +00:00
2018-12-18 23:20:49 +00:00
my $ alert_level = defined $ parameter - > { alert_level } ? $ parameter - > { alert_level } : 0 ;
2018-12-29 08:23:58 +00:00
my $ clear_alert = defined $ parameter - > { clear_alert } ? $ parameter - > { clear_alert } : 0 ;
2018-12-18 23:20:49 +00:00
my $ message = defined $ parameter - > { message } ? $ parameter - > { message } : "" ;
my $ set_by = defined $ parameter - > { set_by } ? $ parameter - > { set_by } : "" ;
my $ show_header = defined $ parameter - > { show_header } ? $ parameter - > { show_header } : 1 ;
my $ sort_position = defined $ parameter - > { sort_position } ? $ parameter - > { sort_position } : 9999 ;
2018-12-29 08:23:58 +00:00
my $ title = defined $ parameter - > { title } ? $ parameter - > { title } : "" ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2018-12-18 23:20:49 +00:00
show_header = > $ show_header ,
2018-12-29 08:23:58 +00:00
clear_alert = > $ clear_alert ,
2018-12-18 23:20:49 +00:00
alert_level = > $ alert_level ,
message = > $ message ,
set_by = > $ set_by ,
sort_position = > $ sort_position ,
title = > $ title ,
2017-07-20 06:00:40 +00:00
} } ) ;
2018-12-18 23:20:49 +00:00
if ( not $ alert_level )
{
2018-12-29 08:23:58 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->register()" , parameter = > "alert_level" } } ) ;
2018-12-18 23:20:49 +00:00
return ( "!!error!!" ) ;
}
2017-07-20 06:00:40 +00:00
if ( not $ set_by )
{
2018-12-29 08:23:58 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->register()" , parameter = > "set_by" } } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
2018-12-18 23:20:49 +00:00
if ( not $ message )
2017-07-20 06:00:40 +00:00
{
2018-12-29 08:23:58 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Alert->register()" , parameter = > "message" } } ) ;
2017-08-02 01:04:35 +00:00
return ( "!!error!!" ) ;
2017-07-20 06:00:40 +00:00
}
2018-12-18 23:20:49 +00:00
if ( ( $ show_header ) && ( not $ title ) )
2017-07-20 06:00:40 +00:00
{
2018-12-29 08:23:58 +00:00
# Set it based on the alert_level.
if ( $ alert_level eq "1" ) { $ title = $ clear_alert ? "alert_title_0005" : "alert_title_0001" ; } # Critical (or Critical Cleared)
elsif ( $ alert_level eq "2" ) { $ title = $ clear_alert ? "alert_title_0006" : "alert_title_0002" ; } # Warning (or Warning Cleared)
elsif ( $ alert_level eq "3" ) { $ title = $ clear_alert ? "alert_title_0007" : "alert_title_0003" ; } # Notice (or Notice Cleared)
elsif ( $ alert_level eq "4" ) { $ title = $ clear_alert ? "alert_title_0008" : "alert_title_0004" ; } # Info (or Info Cleared)
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { title = > $ title } } ) ;
2017-07-20 06:00:40 +00:00
}
# zero-pad sort numbers so that they sort properly.
2018-12-18 23:20:49 +00:00
$ sort_position = sprintf ( "%04d" , $ sort_position ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { sort_position = > $ sort_position } } ) ;
2019-01-06 01:57:44 +00:00
# Before we actually record the alert, see if there are any recipients listening. For example, very
# rarely is anyone listening to alert level 4 (info), so skipping recording it saves unnecessary
# growth of the history.alerts table.
2017-07-20 06:00:40 +00:00
2018-12-18 23:20:49 +00:00
= cut
2017-07-20 06:00:40 +00:00
# In most cases, no one is listening to 'debug' or 'info' level alerts. If that is the case here,
# don't record the alert because it can cause the history.alerts table to grow needlessly. So find
# the lowest level log level actually being listened to and simply skip anything lower than that.
# 5 == debug
# 1 == critical
my $ lowest_log_level = 5 ;
2017-10-20 04:19:32 +00:00
foreach my $ integer ( sort { $ a cmp $ b } keys % { $ anvil - > data - > { alerts } { recipient } } )
2017-07-20 06:00:40 +00:00
{
# We want to know the alert level, regardless of whether the recipient is an email of file
# target.
my $ this_level ;
2017-10-20 04:19:32 +00:00
if ( $ anvil - > data - > { alerts } { recipient } { $ integer } { email } )
2017-07-20 06:00:40 +00:00
{
# Email recipient
2017-10-20 04:19:32 +00:00
$ this_level = ( $ anvil - > data - > { alerts } { recipient } { $ integer } { email } =~ /level="(.*?)"/ ) [ 0 ] ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { this_level = > $ this_level } } ) ;
2017-07-20 06:00:40 +00:00
}
2017-10-20 04:19:32 +00:00
elsif ( $ anvil - > data - > { alerts } { recipient } { $ integer } { file } )
2017-07-20 06:00:40 +00:00
{
# File target
2017-10-20 04:19:32 +00:00
$ this_level = ( $ anvil - > data - > { alerts } { recipient } { $ integer } { file } =~ /level="(.*?)"/ ) [ 0 ] ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { this_level = > $ this_level } } ) ;
2017-07-20 06:00:40 +00:00
}
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { this_level = > $ this_level } } ) ;
2017-07-20 06:00:40 +00:00
if ( $ this_level )
{
2017-10-20 04:19:32 +00:00
$ this_level = $ anvil - > Alert - > convert_level_name_to_number ( { level = > $ this_level } ) ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2017-07-20 06:00:40 +00:00
this_level = > $ this_level ,
lowest_log_level = > $ lowest_log_level ,
} } ) ;
if ( $ this_level < $ lowest_log_level )
{
$ lowest_log_level = $ this_level ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { lowest_log_level = > $ lowest_log_level } } ) ;
2017-07-20 06:00:40 +00:00
}
}
}
# Now get the numeric value of this alert and return if it is higher.
2017-10-20 04:19:32 +00:00
my $ this_level = $ anvil - > Alert - > convert_level_name_to_number ( { level = > $ level } ) ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
2017-07-24 06:28:11 +00:00
alert_level = > $ level ,
2017-07-20 06:00:40 +00:00
this_level = > $ this_level ,
lowest_log_level = > $ lowest_log_level ,
} } ) ;
if ( $ this_level > $ lowest_log_level )
{
# Return.
2018-12-18 23:20:49 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , key = > "log_0102" , variables = > { message = > $ message } } ) ;
2017-07-20 06:00:40 +00:00
return ( 0 ) ;
}
# Always INSERT. ScanCore removes them as they're acted on (copy is left in history.alerts).
my $ query = "
INSERT INTO
alerts
(
alert_uuid ,
alert_host_uuid ,
alert_set_by ,
alert_level ,
2018-12-18 23:20:49 +00:00
alert_title ,
alert_message ,
alert_sort_position ,
alert_show_header ,
2018-09-25 06:05:07 +00:00
modified_date
2017-07-20 06:00:40 +00:00
) VALUES (
2019-03-06 06:49:59 +00:00
".$anvil->Database->quote($anvil->Get->uuid())." ,
".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." ,
".$anvil->Database->quote($set_by)." ,
".$anvil->Database->quote($level)." ,
".$anvil->Database->quote($title)." ,
".$anvil->Database->quote($message)." ,
".$anvil->Database->quote($sort_position)." ,
".$anvil->Database->quote($show_header)." ,
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
2017-07-20 06:00:40 +00:00
) ;
" ;
2018-03-07 08:11:55 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { query = > $ query } } ) ;
2017-10-20 04:19:32 +00:00
$ anvil - > Database - > write ( { query = > $ query , source = > $ THIS_FILE , line = > __LINE__ } ) ;
2018-12-18 23:20:49 +00:00
= cut
2017-07-20 06:00:40 +00:00
return ( 0 ) ;
}
2019-09-03 18:07:39 +00:00
### TODO: Write this, maybe? Or remove it and ->warning()?
2017-05-02 04:41:12 +00:00
= head2 error
= cut
# Later, this will support all the translation and logging methods. For now, just print the error and exit.
sub error
{
my $ self = shift ;
my $ parameter = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self - > parent ;
2018-03-07 08:11:55 +00:00
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
2017-05-02 04:41:12 +00:00
}
1 ;