• Publicidad

Parseando CSV

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Re: Parseando CSV

Notapor explorer » 2012-10-14 16:33 @731

Tampoco pienses que a mi se me ocurre escribir esa sintaxis y funcionar a la primera...

Lo que yo hago es imaginar la estructura de datos que necesito, cómo agrupar la información, dividirla en pura lista de elementos que convertiré en un array, o si voy a almacenar estructuras con nombre, que convertiré en un hash.

Y casi siempre, lo que se escribe en el programa, no funciona a la primera, ni a la segunda, ni a la décima. Hay que jugar con Data::Dumper para verificar una y otra vez que Perl está construyendo nuestro castillo de naipes de forma sólida. Y que está extrayendo las cartas una a una y todo sigue en pie :)

Te explico un poco lo que hacen las líneas:

my @fechas = sort keys %{ $log{$maquina}->{ ${ $medidas{$medida}->{datos} }[0] } };

El hash %medidas es una constante. Mejor dicho, guarda una serie de constantes, de las magnitudes y textos que deben acompañar a los xml generados. Definida a partir de la línea 8.

El bucle de la línea 89 recorre las claves de ese hash, es decir, 'cpu', 'mem' e 'io'.

Con la expresión $medidas{$medida}->{datos} estamos accediendo a la entrada 'datos' de cada una de esas medidas. Y es una referencia a un array. Como tal, podemos acceder a su primer elemento: ${ $medidas{$medida}->{datos} }[0] (otra forma de escribirlo, más clara: $medidas{$medida}->{datos}->[0]).

Si $medida fuera 'cpu', entonces de esta última expresión obtendríamos el valor 'cpu_ready_summation'. Ahora tenemos esto: $log{$maquina}->{'cpu_ready_summation'}, que, según la línea 72, es una referencia a un hash que guarda en sus claves los 'Timestamp' de esa medida. Esas claves son extraídas por keys(), y luego ordenadas alfabéticamente por sort() (podemos hacerlo porque las fechas fueron normalizadas en la línea 68).

El resultado final es que en @fechas quedan los 'timestamp' de la primera magnitud ('cpu_ready_summation') de la $medida que en ese momento estemos analizando. ¿Por qué de la primera y solo de la primera? Pues porque vamos a dar por supuesto que el archivo CSV está bien, y por cada medida realizada, todas las magnitudes tienes los mismos 'timestamp' (esto es algo que no nos has dicho, pero que suponemos que es así).

Más tarde, las @fechas se usarán para recuperar los valores capturados (línea 120).

for my $item ( @{ $medidas{$medida}->{datos} } )

Esto es la línea 96 del segundo código y la línea 114 del primer código: recorren los valores del array que se encuentra referenciado por la entrada 'datos' en cada hash según la $medida que sea en ese momento. En tu código de ejemplo, pusiste dos bucles distintos para recorrer los valores de 'cpu.usage.average' y 'cpu.ready.summation'. Aquí hay un bucle que recorre todos los valores, por lo que da igual si son dos, tres o más magnitudes que hay que leer.

open my $SALIDA, '>', "${maquina}_$medida.xml";

Bueno, esto no tiene nada que ver con referencias de array o hash. Es solo una cuestión de nomenclatura.

La intención es crear un archivo .xml con el nombre de la máquina, un guion bajo, y seguido por el nombre de la medida en cuestión.

Resulta que si pongo "$maquina_$medida.xml", Perl intentará interpolar la variable '$maquina_' (se cree que el guion bajo forma parte del nombre de la variable), y claro, esa variable no existe.

El guion bajo es un carácter legal para los nombres de variables, así que hay que decirle a Perl que en realidad, ese guion bajo es un guion bajo literal. La forma de hacerlo es reescribiendo la variable $maquina como ${maquina}.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Publicidad

Re: Parseando CSV

Notapor tutoki » 2012-10-30 15:36 @691

Hola, he estado trasteando con el código, y la verdad es que modificando las constantes puedo controlar las iteraciones de los bucles, me vale para cualquier CVS del tipo que estoy acostumbrado a trabajar.

Incluso he generado (situándolo dentro del primer bucle) la estructura HTML con su fichero xml asociado y... funciona de maravilla.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. ##############################################################
  2. # Generar estructura HTML
  3. ##############################################################
  4. open my $html, '>>', "cliente.html";
  5. $n += 1;
  6. my $chartid = "ChartId"."_".$n;
  7. say $html       qq(<div id="${maquina}_$medida">FusionCharts will load here!</div>
  8. <script type="text/javascript" >
  9.     /*FusionCharts.setCurrentRenderer('javascript');*/
  10.     var myChart = new FusionCharts("fusion/MSLine.swf", "$chartid ", "1100", "600", "0", "1");
  11.     myChart.setXMLUrl("fusion/datos/${maquina}_$medida.xml");
  12.     myChart.render("${maquina}_$medida");
  13. </script>);
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Tengo una duda de cómo modificar un dato. En este caso el cpu_ready_summation, su magnitud (milisegundos) difiere de cpu_usage_average (%), lógicamente así no pueden ir en la misma gráfica (solo hay un eje Y) así que tengo que dividirlo por 18000 (30x60x10).

Creo que debería de situarlo detrás de

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for my $item ( @{ $medidas{$medida}->{datos} } )
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Algo así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ($item eq "cpu_ready_summation"){
  2.             { $medidas{$medida}->{datos} } / 18000;
  3.             }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Gracias por anticipado.
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

Re: Parseando CSV

Notapor explorer » 2012-10-30 16:21 @723

Mejor en la línea 63, cuando se está leyendo el archivo (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ($item->{MetricId} eq 'cpu_ready_summation') {
  2.         $item->{Value   } /= 18_000;                     # modificamos el valor leído
  3.     }
  4.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parseando CSV

Notapor tutoki » 2012-10-30 16:43 @738

Hola

Salen muchos decimales:
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
  1. <dataset SeriesName="cpu_ready_summation">
  2.     <set value="0.473666666666667" />
  3.     <set value="0.468166666666667" />
  4.  
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


pero lo redondeamos
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ($item->{MetricId} eq 'cpu_ready_summation') {
  2.         $item->{Value   } /= 18_000; ## modificamos el valor leído
  3.         $item->{Value   } = sprintf "%.2f", $item->{Value   }; #redondeo
  4.      }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


y voila:

Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
  1.   <dataset SeriesName="cpu_ready_summation">
  2.     <set value="0.47" />
  3.     <set value="0.47" />
  4.  
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Muchas gracias de nuevo.
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

Re: Parseando CSV

Notapor tutoki » 2012-11-03 03:58 @207

Hola de nuevo,

Necesito adelgazar de alguna manera la cantidad de ficheros generados, de todos modos estoy impresionado, he tratado un fichero de 46MB ¡de texto! (más de 230.000 líneas en uno o dos minutos). He estado probando con las expresiones regulares (línea 25) para los nombre de los servidores (Entity), pero no es suficiente.

Copio el trozo del código donde se trata el fichero a analizar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. ####################################################################################
  2. ## Lectura del archivo
  3. ####################################################################################
  4. my $datos = Text::CSV::Slurp->load(
  5.     file       => $archivo_csv,
  6.     sep_char   => ';',
  7.     quote_char => '"'
  8. );
  9.  
  10. my %log;
  11.  
  12. for my $item (@$datos) {
  13.     my ( $dia, $mes, $year, $hora, $minuto, $segundo ) = $item->{Timestamp} =~ /(\d+)/g;
  14.     $item->{Timestamp} = sprintf "%02d%02d%02dT%02d%02d%02d", $year, $mes, $dia, $hora, $minuto, $segundo;
  15.     $item->{MetricId} =~ s/[.]/_/g;
  16.     if ( $item->{MetricId} eq 'cpu_ready_summation' ) {
  17.         $item->{Value} /= 18_000;
  18.         $item->{Value} = sprintf "%.2f", $item->{Value};    #redondeo
  19.         $item->{Value} =~ s/[.]/,/;    # modificamos el valor leído
  20.     }
  21.     if (   ( $item->{Entity} !~ m/(?:po)+/ig )
  22.         || ( $item->{Entity} =~ m/(?:rhe)+/ig )
  23.         || ( $item->{Entity} =~ m/(?:netb)+/ig ) ) {
  24.         next;
  25.     }
  26.     else {
  27.         $log{ $item->{Entity} }->{ $item->{MetricId} }->{ $item->{Timestamp} } = $item->{Value};
  28.     }
  29. }
  30.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Creo que es más operativo hacer un filtro comparando los valores (Value).

Por ejemplo, para cargarme todos los ficheros en donde la media de cpu (cpu_usage_average) sea menor de 10:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ( $item->{MetricId} eq 'cpu_usage_average' && ( $item->{Value} <= 10 ) ) {
  2.     next;
  3. }
  4. else {
  5.     $log{ $item->{Entity} }->{ $item->{MetricId} }->{ $item->{Timestamp} } = $item->{Value};
  6.  
  7. }
  8.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Lógicamente no vale, el fichero se sigue generando pero sin los valores de cpu_usage_average; pero claro como cada XML generado (por ejemplo el de cpu, cpu_ready_summation y cpu_usage_average) lo componen más de un valor, pues el fichero se genera.

¿Qué otro camino hay?
¿Cómo puedo filtrar por valores (Values) y conseguir que el fichero no se genere?

Otra posibilidad (de adelgazar el número de ficheros), es que dado un valor (Values) no se genere ninguno de los XML para este servidor (Entity), es decir tres ficheros menos. Yo creo que esta sería la mejor opción, que... supongo que lo lía todo más ;-)

SALUD...
Última edición por explorer el 2012-11-03 07:04 @336, editado 1 vez en total
Razón: Formateado de código con Perltidy
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

Re: Parseando CSV

Notapor explorer » 2012-11-03 07:22 @348

Según dijiste al principio, debes generar los xml para luego generar los gráficos. Así que estás condicionado por eso.

Si no fuera así, podrías meter toda la información en un único archivo XML.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parseando CSV

Notapor tutoki » 2012-11-03 09:12 @425

Hola,

Lo sé, lo sé. En una respuesta anterior pego la generación del HTML. Como puedes ver cada gráfica necesita de un contenedor <div> o <span> para generarse. Esto es ineludible.

70 máquinas x 3 ficheros XML, pues... tarda mucho y a veces el Flash se cae. Estoy probando a renderizar sin Flash (tarda más pero no se cae).

Había pensado en poner un valor de mínimo cpu.average.usage u otro, y así podría controlar la cantidad de ficheros generados.

Con este código lo he conseguido pero no es coherente, es decir mato moscas a cañonazos. Si logro asociar el Value a Entity, yo creo que sí lo podré conseguir.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if (   ( $item->{Entity} !~ m/(?:po)+/ig )
  2.                 || ( $item->{Entity} =~ m/(?:rhe)+/ig )
  3.                 || ( $item->{Entity} =~ m/(?:netb)+/ig )
  4.                 )
  5.         {
  6.                 next;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Voy a seguir probando cosas.

SALUD
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

Re: Parseando CSV

Notapor explorer » 2012-11-03 12:10 @549

Puedes hacer un sistema de 'cacheo'.

En el cgi, primero compruebas si hay una nueva versión del archivo CSV. Puede ser algo tan sencillo como comparar las edades del archivo CSV con la edad de los XML generados (con comparar con uno de ellos, vale).

Si los archivos XML son más viejos, entras a la fase de generación de nuevos XML. Pero si resulta que son más modernos, eso significa que el archivo CSV no ha cambiado desde la última vez, así que no es necesario regenerarlos, y el CGI termina inmediatamente.

tutoki escribiste:tarda mucho y a veces el Flash se cae
¿Te refieres a esa tecnología que no funciona en los sistemas operativos Apple?. Te recomiendo que empieces a aprender a escribir o dibujar en SVG.

tutoki escribiste:Esto es ineludible.
Pues no. Siempre se puede abreviar. Por ejemplo. ¿Por qué generar 70 archivos si el usuario solo va a ver la estadística de una máquina cada vez? Si quiere ver una máquina distinta, se generan las gráficas para solo esa máquina.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parseando CSV

Notapor tutoki » 2012-11-03 15:28 @686

No es tan fácil, los gráficos se generan vía JavaScript con un software que se llama FusionChart. Si tienes Flash te renderiza en Flash, si no, en puro JavaScript. Los gráficos digamos están vivos puedes interactuar con ellos, se generan en el momento que abres la página (solo la primera vez).

Sobre el tema mostrar más o menos ficheros pues efectivamente tienes razón, lo que pasa es que no sé de antemano cuáles son dignos de mostrarse por un motivo u otro, quiero decir, para que voy a mostrar gráficas de CPU por debajo de 10% de consumo.

Tengo que seguir trabajando. Seguro que sale algo...

SALUD...
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

Re: Parseando CSV

Notapor tutoki » 2012-11-25 03:47 @199

Tengo un tema colando de este hilo, a ver si me puedes ayudar.

En el proceso de transformación del CSV modificabamos el campo Timestamp ( las fechas) para que perl las pudiera ordenar

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.      my($dia, $mes, $year, $hora, $minuto, $segundo) = $campos{'Timestamp'} =~ /(\d+)/g;
  2.      $campos{'Timestamp'} = sprintf "%02d%02d%02dT%02d%02d%02d", $year, $mes, $dia, $hora, $minuto, $segundo;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Efectivamente, lo hace perfectamente, pero claro al generar los ficheros XML, lógicamente lo pinta con ese formato:
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
  1.  <categories>
  2.     <category label="20121005T100000" />
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


¿Hay alguna manera de humanizar este campo a un formato fecha en el momento de generar el/los XML?
o
¿Es mejor generar los XML tal cual y luego modificar vía otro script.pl este campo?

SALUD...
tutoki
Perlero nuevo
Perlero nuevo
 
Mensajes: 58
Registrado: 2012-04-15 01:53 @120

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 16 invitados