У вас есть JSON, встроенный в JSON, поэтому вам нужно декодировать его дважды. Это часто происходит, когда одна служба проходит через ответ для другой службы.
Ваш data2json
не декодировал этот второй уровень, поэтому значение для имени Message
все еще было строкой. Так как это значение не было ссылкой ha sh, вы получите сообщение об ошибке.
Вы не хотите использовать кучу подстановок для всего объекта, потому что вы можете непреднамеренно изменить то, что не должны ' не возиться. Расшифруйте верхний уровень так же, как вы, но затем сделайте то же самое для значения Message
:
# read in all the data, even though it looks like a single line. Maybe it won't be later.
my $data = do { local $/; <DATA> };
# decode the first layer
my $decoded = decode_json( $data );
# decode the Message value:
$decoded->{Message} = decode_json( $decoded->{Message} );
Теперь, когда вы вызываете rec2msg
, это должно сработать.
Обратите внимание, что проблема заключается в обратном. Вы не можете просто закодировать все это в JSON снова. Значение для Message
все еще должно быть строкой, поэтому вам нужно сначала ее кодировать, если вы хотите отправить ее куда-нибудь еще. Если вы делаете это, вы, вероятно, хотите работать над копией. Я использую dclone
для создания глубокой копии, поэтому все, что я делаю с $encoded
, не отображается в $decoded
:
# make a deep copy so nested references aren't shared
use Storable qw(dclone);
my $encoded = dclone( $decoded );
$encoded->{Message} = encode_json( $encoded->{Message} );
my $new_data = encode_json( $encoded );
Тогда $new_data
будет иметь тот же выход, что и исходный ввод.
Вот и все:
use strict;
use warnings;
use feature 'say';
use JSON;
use utf8;
my %IDs = ( 'User awx01 logged in.' => 1001 );
my %levels = ( INFO => 4 );
# read in all the data, even though it looks
my $data = do { local $/; <DATA> };
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;
}