【问题标题】:How can I convert a log4j timestamp to milliseconds in Perl?如何在 Perl 中将 log4j 时间戳转换为毫秒?
【发布时间】:2009-05-10 16:04:22
【问题描述】:

我拥有的 log4j 日志包含以下格式的时间戳:

2009-05-10 00:48:41,905

我需要使用以下 gawk 函数将 perl 中的它转换为自纪元以来的毫秒数,在本例中为 124189673005。我如何在 perl 中做到这一点?

我在 perl 方面几乎没有经验,如果有人能发布一个完整的脚本来做这件事,我将不胜感激

function log4jTimeStampToMillis(log4jts) {
    # log4jts is of the form 2009-03-02 20:04:13,474
    # extract milliseconds that is after the command
    split(log4jts, tsparts, ",");
    millis = tsparts[2];

    # remove - : from tsstr
    tsstr = tsparts[1];
    gsub("[-:]", " ", tsstr);
    seconds = mktime(tsstr);
    print log4jts;
    return seconds * 1000 + millis;
}

【问题讨论】:

    标签: perl log4j timestamp


    【解决方案1】:

    尽管我几乎总是告诉人们为此使用 CPAN 的众多优秀模块之一,但它们中的大多数确实有一个主要缺点 - 速度。如果您要实时解析大量日志文件,这有时可能是个问题。在这些情况下,自己滚动通常可能是更合适的解决方案,但有许多陷阱和细微差别必须加以考虑和妥善处理。因此,更倾向于使用由其他人编写的已知正确、经过验证、可靠的模块。 :)

    但是,在我考虑上面的建议之前,我查看了您的代码并在脑海中将其转换为 perl...因此,这里或多或少地将您的 gawk 代码直接转换为 perl。我试图尽可能简单地编写它,以便突出显示在 perl 中手动处理日期和时间的一些更微妙的部分。

    # import the mktime function from the (standard) POSIX module
    use POSIX qw( mktime );
    
    sub log4jTimeStampToMillis {
        my ($log4jts, $dst) = @_;
    
        # extract the millisecond field
        my ($tsstr, $millis) = split( ',', $log4jts );
    
        # extract values to pass to mktime()
        my @mktime_args = reverse split( '[-: ]', $tsstr );
    
        # munge values for posix compatibility (ugh)
        $mktime_args[3] -= 1;
        $mktime_args[4] -= 1;
        $mktime_args[5] -= 1900;
        # print Dumper \@mktime_args; ## DEBUG
    
        # convert, make sure to account for daylight savings
        my $seconds = mktime( @mktime_args, 0, 0, $dst );
    
        # return that time as milliseconds since the epoch
        return $seconds * 1000 + $millis;
    }
    

    我的代码和你的代码之间的一个重要区别 - 我的 log4jTimeStampToMillis 子例程采用 两个 参数:

    1. 日志时间戳字符串
    2. 时间戳是否使用夏令时(1 为真,0 为假)

    当然,您可以添加代码来检测该时间是否在 DST 中并自动调整,但我试图保持简单。 :)

    注意:如果取消注释标记为 DEBUG 的行,请确保添加“use Data::Dumper;”在程序中的那一行之前,这样它就可以工作了。

    这是一个如何测试该子例程的示例:

    my $milliseconds = log4jTimeStampToMillis( "2009-05-10 00:48:41,905", 1 );    
    my $seconds = int( $milliseconds / 1000 );
    my $local = scalar localtime( $seconds );
    
    print "ms:    $milliseconds\n"; # ms:    1241844521905
    print "sec:   $seconds\n";      # sec:   1241844521
    print "local: $local\n";        # local: Sat May  9 00:48:41 2009
    

    【讨论】:

    • 我已经得到了我的解决方案,但是你的回复教会了我更多的 perl,我相信在编写一些 perl 代码时我会回到这个回复。 +1
    • 我不会投反对票,但说真的......这可能有效......直到它不起作用......我无法评论速度方面,但如果 DateTime 很慢,它就是因为它做有用的事情。
    【解决方案2】:

    您应该利用出色的DateTime 包,特别是使用DateTime::Format::Strptime

    use DateTime;
    use DateTime::Format::Strptime;
    
    sub log4jTimeStampToMillis {
        my $log4jts=shift(@_);
    
        #see package docs for how the pattern parameter works
        my $formatter= new DateTime::Format::Strptime(pattern => '%Y-%m-%d %T,%3N');
        my $dayObj = $formatter->parse_datetime($log4jts);
    
        return $dayObj->epoch()*1000+$dayObj->millisecond();
    }
    
    print log4jTimeStampToMillis('2009-05-10 10:48:41,905')."\n";
    #prints my local version of the TS: 1241952521905
    

    这省去了您自己弄清楚 DST 的痛苦(尽管您必须通过 time_zone 参数将服务器的 TZ 传递给 Strptime)。如果它变得相关,它还可以让你免于处理跳跃所有事情(我相信它会)。

    【讨论】:

      【解决方案3】:

      没用过,但你可能想看看Time::ParseDate

      【讨论】:

      • 非常感谢。模块中的 parsedate 与 gawk 中的 mktime 相同,但我可以弄清楚其余的。
      【解决方案4】:
      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
      Date time = dateFormat.parse(log4jts);
      long millis = time.getTime();
      

      【讨论】:

      • 这是什么语言?另外,查看代码格式化程序 - 选择您的代码并单击小 101010 按钮,它会美化它。
      猜你喜欢
      • 2012-12-02
      • 2014-04-17
      • 2016-03-04
      • 2013-03-09
      • 2016-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多