首页 > 解决方案 > 使用子例程时出现错误“变量不会保持共享”

问题描述

我写了一个函数,这里是:

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

但是,当我运行此代码时,出现此错误:

变量“%IDs”不会在 /usr/libexec/nxlog/modules/extension/perl/event1.pl 第 25 行保持共享。变量“%levels”不会在 /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\"}"}

标签: perlsubroutine

解决方案


使用嵌套的命名子程序有点不寻常。

该错误消息的文档提供了一些建议:

变量“%s”不会保持共享

(W 闭包)内部(嵌套)命名子例程正在引用在外部命名子例程中定义的词法变量。

当调用内部子程序时,它将看到外部子程序变量的值,就像它在第一次调用外部子程序之前和期间一样;在这种情况下,在对外部子例程的第一次调用完成后,内部子例程和外部子例程将不再共享该变量的公共值。换句话说,变量将不再被共享。

这个问题通常可以通过使用 sub {} 语法使内部子例程匿名来解决。当创建引用外部子例程中变量的内部匿名子时,它们会自动重新绑定到此类变量的当前值。

所以你可以听从这个建议,或者完全摆脱内部子程序。一眼看去,我看不出有什么真正的原因。


推荐阅读