2

我拥有的 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;
}
4

4 回答 4

2

尽管我几乎总是告诉人们为此使用来自 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
于 2009-05-10T23:53:43.127 回答
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)。如果它变得相关(我相信它会),它还可以让你免于处理跳跃的一切。

于 2010-11-24T00:38:29.323 回答
1

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

于 2009-05-10T16:18:57.963 回答
0
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
Date time = dateFormat.parse(log4jts);
long millis = time.getTime();
于 2010-11-24T00:05:10.350 回答