Reputation: 1
I have written a function, here it is:
use strict;
use warnings;
use feature 'say';
use JSON;
use utf8;
sub process {
my %IDs = ( "User awx01 logged in." => 1001 );
my %levels = ( INFO => 4 );
my $data = do { local $/; <DATA> };
# read in all the data, even though it looks
my $decoded = decode_json( $data );
$decoded->{Message} = decode_json( $decoded->{Message} );
say rec2msg($decoded);
sub rec2msg {
my $r = shift;
$r->{Message}{message} =~ /(\w+) (\w+) (.+)/;
my($user,$msg) = ($2,"$1 $3");
my $ID = $IDs{$r->{Message}{message}};
my $level = $levels{$r->{Message}{level}};
my $out = "$r->{Message}{'@timestamp'} host CEF:0|OpenSource|AWX|7.0.0|$ID|$msg|$level|src=127.0.0.1 dst=$r->{MessageSourceAddress} duser=$user";
return $out;
}
}
__DATA__
{"MessageSourceAddress":"192.168.81.20","EventReceivedTime":"2020-02-06 11:55:14","SourceModuleName":"udp","SourceModuleType":"im_udp","SyslogFacilityValue":1,"SyslogFacility":"USER","SyslogSeverityValue":5,"SyslogSeverity":"NOTICE","SeverityValue":2,"Severity":"INFO","EventTime":"2020-02-06 11:55:14","Hostname":"192.168.81.20","Message":"{\"@timestamp\": \"2020-02-06T08:55:52.907Z\", \"message\": \"User awx01 logged in.\", \"host\": \"awxweb\", \"level\": \"INFO\", \"logger_name\": \"awx.api.generics\", \"stack_info\": null, \"type\": \"other\", \"cluster_host_id\": \"awx-contr-01\", \"tower_uuid\": \"333b4131-495f-4460-8e4b-890241a9d73d\"}"}
Desired output after I run this code is:
2021-02-06T08:55:52.907Z host CEF:0|OpenSource|AWX|7.0.0|1001|User logged in.|4|src=127.0.0.1 dst=192.168.81.20 duser=awx01
However, when I run this code, I get this error:
Variable "%IDs" will not stay shared at /usr/libexec/nxlog/modules/extension/perl/event1.pl line 25. Variable "%levels" will not stay shared at /usr/libexec/nxlog/modules/extension/perl/event1.pl line 26.
How could i fix it? I really need it to be in one function
I tried this, but didn't work:
use strict;
use warnings;
use feature 'say';
use JSON;
use utf8;
sub process {
my %IDs = ( "User awx01 logged in." => 1001 );
my %levels = ( INFO => 4 );
my $data = do { local $/; <DATA> };
# read in all the data, even though it looks
my $decoded = decode_json( $data );
$decoded->{Message} = decode_json( $decoded->{Message} );
say rec2msg($decoded);
local *rec2msg = sub {
my $r = shift;
$r->{Message}{message} =~ /(\w+) (\w+) (.+)/;
my($user,$msg) = ($2,"$1 $3");
my $ID = $IDs{$r->{Message}{message}};
my $level = $levels{$r->{Message}{level}};
my $out = "$r->{Message}{'@timestamp'} host CEF:0|OpenSource|AWX|7.0.0|$ID|$msg|$level|src=127.0.0.1 dst=$r->{MessageSourceAddress} duser=$user";
return $out;
}
return rec2msg();
}
__DATA__
{"MessageSourceAddress":"192.168.81.20","EventReceivedTime":"2020-02-06 11:55:14","SourceModuleName":"udp","SourceModuleType":"im_udp","SyslogFacilityValue":1,"SyslogFacility":"USER","SyslogSeverityValue":5,"SyslogSeverity":"NOTICE","SeverityValue":2,"Severity":"INFO","EventTime":"2020-02-06 11:55:14","Hostname":"192.168.81.20","Message":"{\"@timestamp\": \"2020-02-06T08:55:52.907Z\", \"message\": \"User awx01 logged in.\", \"host\": \"awxweb\", \"level\": \"INFO\", \"logger_name\": \"awx.api.generics\", \"stack_info\": null, \"type\": \"other\", \"cluster_host_id\": \"awx-contr-01\", \"tower_uuid\": \"333b4131-495f-4460-8e4b-890241a9d73d\"}"}
Upvotes: 1
Views: 286
Reputation: 2589
Declare the below variables at the top of the code like,
my (%IDs,%levels) = ();
remove the declared variable here,
my %IDs = ( "User awx01 logged in." => 1001 ); #instead of my %IDs...
my %levels = ( INFO => 4 );
Move the inner function
rec2msg
to the outside from the parent functionprocess
.
Already you got the theoretical explanation from the shawn answer.
Upvotes: 0
Reputation: 52439
Using a nested named subroutine is kind of unusual.
The documentation for that error message offers some suggestions:
Variable "%s" will not stay shared
(W closure) An inner (nested) named subroutine is referencing a lexical variable defined in an outer named subroutine.
When the inner subroutine is called, it will see the value of the outer subroutine's variable as it was before and during the first call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no longer share a common value for the variable. In other words, the variable will no longer be shared.
This problem can usually be solved by making the inner subroutine anonymous, using the sub {} syntax. When inner anonymous subs that reference variables in outer subroutines are created, they are automatically rebound to the current values of such variables.
So you could follow that advice, or just get rid of the inner subroutine completely. I don't see any real reason for it at a quick glance.
Upvotes: 4