Я получаю сообщение об ошибке "Переменная не останется общей" при использовании подпрограммы - PullRequest
3 голосов
/ 13 апреля 2020

Я написал функцию, вот она:

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\"}"}

Желаемый результат после запуска этого кода:

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

Однако, когда я запускаю этот код, я получаю эта ошибка:

Переменная «% ID» не будет публиковаться в /usr/libexec/nxlog/modules/extension/perl/event1.pl строке 25. Переменная «% level» не будет публиковаться в / usr /libexec/nxlog/modules/extension/perl/event1.pl строка 26.

Как я могу это исправить? Мне действительно нужно, чтобы это было в одной функции

Я попробовал это, но не сработало:

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\"}"}

Ответы [ 2 ]

3 голосов
/ 13 апреля 2020

Использование вложенной именованной подпрограммы довольно необычно.

Документация для этого сообщения об ошибке предлагает несколько предложений:

Переменная "% s "не останется общим

(закрытие W) Внутренняя (вложенная) подпрограмма с именем ссылается на лексическую переменную, определенную во внешней подпрограмме с именем.

Когда вызывается внутренняя подпрограмма , он увидит значение переменной внешней подпрограммы, как это было до и во время первого вызова внешней подпрограммы; в этом случае после завершения первого вызова внешней подпрограммы внутренняя и внешняя подпрограммы больше не будут иметь общего значения для переменной. Другими словами, переменная больше не будет общей.

Эту проблему обычно можно решить, сделав внутреннюю подпрограмму анонимной, используя синтаксис sub {}. Когда создаются внутренние анонимные подпрограммы, которые ссылаются на переменные во внешних подпрограммах, они автоматически возвращаются к текущим значениям таких переменных.

Таким образом, вы можете последовать этому совету или просто полностью избавиться от внутренней подпрограммы. , Я не вижу никакой реальной причины для этого с первого взгляда.

0 голосов
/ 13 апреля 2020

Объявите перечисленные ниже переменные в верхней части кода следующим образом:

my (%IDs,%levels) = ();

удалите объявленную переменную здесь,

my %IDs = ( "User awx01 logged in." => 1001 ); #instead of my %IDs...
my %levels = ( INFO => 4 );

Переместите внутреннюю функцию rec2msg наружу из родительской функции process.

Уже вы получили теоретическое объяснение из ответа Шон .

...