【问题标题】:Parse and plot data received from log-file on-the-fly即时解析和绘制从日志文件接收到的数据
【发布时间】:2013-10-14 10:05:27
【问题描述】:

我想创建一个 Perl(或 Bash)脚本来即时创建和绘制数据。这意味着我想从日志文件 file.log 中提取数据,理想情况下不要编写 tmp 文件(如果只能使用 tmp 文件,这也可以)和用 Gnuplot 绘图。随着日志文件的增长,我想在图中看到更多信息。

类似话题请见this question

对于 Perl,我目前拥有的是这个脚本:

#!/usr/bin/perl
use strict;
use warnings;

my $path = "file.log";   
my @grepped;
my $switch = "off";

open(INFILE,"< $path") or die $! \n";
while (my $line = <INFILE>) {

       if ($line =~ m{^Time = (\d+)}){
               push(@grepped,"$1\t");
       };

       if ($line =~ m{^Errors: local = (\d+), global = (\d+)}){
               push(@grepped,"$1\t");
               push(@grepped,"$2\n");
               $switch = "refresh";
       };


if ($switch eq "refresh"){

open(GP, "| gnuplot -persist") or die: $! \n";
print GP << "GNU_EOF";

plot "@grepped" u 2:1
pause 1; refresh; reread;

GNU_EOF

close(GP);
}


}
close(INFILE)};

我的第一个问题是 Gnuplot 的即时功能不起作用。当 file.log 发生变化时,Gnuplot-graph 的刷新不起作用。我不知道-persist 在这里是否正确,或者我是否必须使用replot 选项而不是refresh。我试过了,但它不适合我。

第二个问题是将数据读入数组 @grepped 并在 Gnuplot 的一个脚本中使用它来更改输入文件。另一个限制是(从代码中可以看出)gnuplot 只有在 @grepped 中写入了一个完整的新行时才应该刷新绘图。否则肯定会因为数据分配错误而发生错误。

当我尝试一个简单的脚本时:

#!/usr/bin/gnuplot -persist
plot "data.dat" u 2:1
pause 1; replot; reread;

#!/usr/bin/gnuplot
plot "data.dat" u 2:1
pause 1; refresh; reread;

如果我手动更改 data.dat 并保存它,即时部分将起作用。

【问题讨论】:

  • 嗯...好吧,您将@grepped 数组打印到gnuplot 向其中添加任何数据....?你期望它如何工作?
  • 你当然是对的。这不是真正完整的代码,无法工作。我也尝试嵌套两个 open 但这对我也不起作用。
  • -persist 是正确的,但你必须告诉gnuplotstdinplot '-' u 2:1 读取。输入流必须以e 结束。
  • @bashophil 好吧,您知道在将数组插入字符串时,元素之间用空格分隔(或者更确切地说,是$" 中包含的值)?所以如果@grepped = (1,2,3);,那么"@grepped" 将是1 2 3
  • 抱歉,e 仅用于终止内联数据(请参阅this answer。但您必须以其他方式终止输入流,然后才能绘制它:seq 1 5 | gnuplot -e "plot '-'" -persist。唐不知道如何在 PERL 中进行管理。

标签: perl bash gnuplot on-the-fly


【解决方案1】:

这里有两种即时绘制数据的方法。

使用 gnuplot 循环

您必须一遍又一遍地调用plot,数据由外部脚本进行预处理。最小的 gnuplot 脚本filter.gp 是:

while (1) {
    plot '< ./myscript.pl' using 2:1
    pause 1
}

要阻止这种情况,请点击Ctrl+C

用于预处理的 Perl 脚本可能如下所示 myscript.pl:

#!/usr/bin/perl
use strict;
use warnings;

my $path = "file.log";   
my @grepped;
my $t = 0;
open(INFILE,"< $path") or die "$! \n";

while (my $line = <INFILE>) {
    if ($line =~ m{^Time = (\d+)}){
        $t = $1;
    };

    if ($line =~ m{^Errors: local = (\d+), global = (\d+)}){
        print "$t\t$1\t$2\n";
    };
};
close(INFILE);

只需使用gnuplot filter.gp 运行它。

为了使其更具可配置性,可以更改脚本以使用通过命令行传递给 gnuplot 的变量:

while (1) {
    plot '< ./myscript.pl -f '.path using 2:1
    pause 1
}

或为此使用reread

plot '< ./myscript.pl -f '.path using 2:1
pause 1
reread

使用gnuplot -e "path='file.log';" filtermod.gp 调用此脚本。

这可行,但会一遍又一遍地过滤整个文件。

从 Perl 到 gnuplot 的管道

这是一个 Perl 脚本,它基本上适合我,但它是我的第一个真正的 Perl 脚本,所以可能有一些不理想的部分。欢迎对此发表评论。

#!/usr/bin/perl
use strict;
use warnings;

my $path = "file.log";   
my @grepped;
my $switch = "off";

open(my $gp, "| gnuplot -persist") or die "$! \n";
$gp->autoflush(0);

use File::Tail;
my $file = File::Tail->new(name=>$path, maxinterval=>1, tail=>-1);

while (defined(my $line= $file->read)) {
    if ($line =~ m{^Time = (\d+)}){
        push(@grepped,"$1\t");
    };

    if ($line =~ m{^Errors: local = (\d+), global = (\d+)}){
        push(@grepped,"$1\t");
        push(@grepped,"$2\n");
        $switch = "refresh";
    };

    if ($switch eq "refresh") {
        print $gp <<"GNU_EOF";
plot '-' using 2:1
@grepped
e
GNU_EOF
        $gp->flush;
        $switch = "off"; 
    };
    Time::HiRes::sleep(0.1);
};

我发现这里很重要的是

  1. 循环更改文件。
  2. autoflushflush的排列方式。
  3. sleep 允许 gnuplot 正确处理数据。

这适用于非常小的测试数据文件。不知道它是否也适用于更大的,但应该可以帮助您进一步。

【讨论】:

  • 谢谢克里斯托夫!不幸的是,我还不能测试仅 Perl 的解决方案,但 gnuplot-wrapping-script 效果很好。尤其是 gnuplot-intern while-loop。我调整了脚本,因为我想用脚本调用来定义脚本的位置。因此,我使用 Bash 脚本来定义变量并将heredoc 通过管道传输到gnuplot。在 Bash 中定义 while-loop 不起作用,我不得不在 heredoc (gnuplot) 中使用 while(1)
  • @bashophil 您还可以使用-e 标志(如gnuplot -e "path='file.log'; sleep=1;" filter.gp)将变量传递给gnuplot 脚本,然后在脚本中使用这些变量pathsleep
  • 但我也想像 filter.sh path/to/file 这样调用脚本。路径的这个参数通过plot '&lt; ./myscript.pl -f $pathvar' 传递给 Perl 脚本,例如我不知道这是否也可以直接在 gnuplot 中实现。
  • @bashophil 当然。通过我之前评论的命令行调用,你可以将plot命令改为plot '&lt; ./myscript.pl -f '.path
  • 太棒了!通过这种方式,我还可以使用set term x11 1set term x11 2 等通过单个脚本调用获取多个日志历史记录。谢谢很多:)
猜你喜欢
  • 2023-03-29
  • 2013-06-10
  • 2016-01-09
  • 1970-01-01
  • 2021-11-27
  • 2013-05-21
  • 1970-01-01
相关资源
最近更新 更多