¿Cómo puedo convertir una marca de tiempo log4j a milisegundos en Perl?
Pregunta
Los registros de log4j que tengo contienen marcas de tiempo en el siguiente formato:
2009-05-10 00:48:41,905
Necesito convertirlo en perl a milisegundos desde la época, que en este caso sería 124189673005 , utilizando la siguiente función gawk. ¿Cómo lo hago en perl?
Tengo poca o ninguna experiencia en perl, así que agradezco si alguien puede publicar un script completo que lo haga
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;
}
Solución
No lo he usado, pero es posible que desee consultar Time :: ParseDate .
Otros consejos
Aunque casi siempre le digo a la gente que use uno de los muchos módulos excelentes del CPAN para esto, la mayoría de ellos tienen un inconveniente importante: la velocidad. Si analiza una gran cantidad de archivos de registro en tiempo real, eso a veces puede ser un problema. En esos casos, rodar la suya a menudo puede ser una solución más adecuada, pero hay muchas trampas y matices que deben considerarse y manejarse adecuadamente. De ahí la preferencia por usar un módulo conocido, correcto, probado y confiable escrito por otra persona. :)
Sin embargo, antes de siquiera considerar mi consejo anterior, miré su código y lo convertí en perl en mi cabeza ... por lo tanto, aquí hay una conversión más o menos directa de su código gawk en perl. Traté de escribirlo de la manera más simple posible, para resaltar algunas de las partes más delicadas de lidiar con fechas y horas en perl a mano.
# 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;
}
Una diferencia importante entre mi código y el suyo: mi subrutina log4jTimeStampToMillis toma dos parámetros:
- la cadena de marca de tiempo de registro
- si esa marca de tiempo usa o no el horario de verano (1 para verdadero, 0 para falso)
Por supuesto, podría agregar código para detectar si ese tiempo cae en horario de verano o no y ajustarlo automáticamente, pero estaba tratando de mantenerlo simple. :)
NOTA: Si descomenta la línea marcada como DEBUG, asegúrese de agregar " use Data :: Dumper; " antes de esa línea en su programa para que funcione.
Aquí hay un ejemplo de cómo podría probar esa subrutina:
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
Debe aprovechar el excelente DateTime , use específicamente 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
Esto le ahorra la molestia de calcular el horario de verano usted mismo (aunque tendrá que pasar la TZ de su servidor a Strptime a través del parámetro time_zone
). También le evita tener que lidiar con el salto de todo si se vuelve relevante (y estoy seguro de que lo hará).
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
Date time = dateFormat.parse(log4jts);
long millis = time.getTime();