Cambio de cortes a SED para analizar las fechas del registro de Apache (archivo de registro común) -- performance campo con datetime campo con bash campo con logging campo con sed camp codereview Relacionados El problema

Changing cuts to sed for parsing dates from apache log (common log file)


3
vote

problema

Español

¿Cambiaría mis cortes a continuación para Sed Mejorar el rendimiento? Estoy tratando de obtener un recuento por fecha de solicitudes de las últimas dos semanas desde un registro de servidores. El guión se ejecuta, pero lentamente (llega alrededor de 14 minutos). El archivo es de 8,867,820 líneas de largo y alrededor de 1.9 g. Supongo que GREP, SED (o AWK) haría esto de manera más eficiente, pero mis intentos iniciales fallaron y recurrí a Cuts.

¿Mi tubería y la redirección causan un retraso innecesario? ¿Es simplemente un problema de un archivo grande?

  # Log is in common log format # host ident authuser date request status bytes # 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326  #initialize check date and end date ckdate=$(date --date='1 days ago' +%s) #enddate=$(date --date='1 fortnight ago' +%s) enddate=$(date --date='3 days ago' +%s) #test date for shorter term  #feed log in reverse into loop # tac to print log backwards into loop (newest log entry at bottom of file) # chkdate is seconds most recent date from line is tac "/etc/httpd/logs/access_log" |   while read line && (( $ckdate >= $enddate )) do   #send line into output, cutting out the date-time (-f4),   # and cleaning for date only (-d: f1)   #echo $line | cut -d ' ' -f4 | tr -d '[' | cut -d: -f1    echo $line | cut -d ' ' -f4 | tr -d '['      | cut -d: -f1 | tr '/' '-' | xargs -i date -d '{}' +'%Y-%m-%d'    #update the check date based on latest line, formatting as seconds since 1970   ckdate=$( ( echo $line | cut -d ' ' -f4 | tr -d '['      | cut -d: -f1 | tr '/' '-' | xargs -i date -d '{}' +'%s' ) )  done | sort | uniq -c | head -n -1 | head -n 2 #put output into sorted list, with uniq counts, and trim outer bounds   
Original en ingles

Would switching my cuts below to SED improve performance? I am trying to get a per date count of requests for the last two weeks from a server log. The script runs, but slowly (comes in around 14 minutes). The file is 8,867,820 lines long and around 1.9G. I would guess grep, SED (or AWK) would do this more efficiently but my initial attempts failed and I resorted to cuts.

Is my piping and redirection causing unnecessary delay? Is this simply an issue of a large file?

# Log is in common log format # host ident authuser date request status bytes # 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326  #initialize check date and end date ckdate=$(date --date='1 days ago' +%s) #enddate=$(date --date='1 fortnight ago' +%s) enddate=$(date --date='3 days ago' +%s) #test date for shorter term  #feed log in reverse into loop # tac to print log backwards into loop (newest log entry at bottom of file) # chkdate is seconds most recent date from line is tac "/etc/httpd/logs/access_log" | \  while read line && (( $ckdate >= $enddate )) do   #send line into output, cutting out the date-time (-f4),   # and cleaning for date only (-d: f1)   #echo $line | cut -d ' ' -f4 | tr -d '[' | cut -d: -f1    echo $line | cut -d ' ' -f4 | tr -d '[' \     | cut -d: -f1 | tr '/' '-' | xargs -i date -d '{}' +'%Y-%m-%d'    #update the check date based on latest line, formatting as seconds since 1970   ckdate=$( ( echo $line | cut -d ' ' -f4 | tr -d '[' \     | cut -d: -f1 | tr '/' '-' | xargs -i date -d '{}' +'%s' ) )  done | sort | uniq -c | head -n -1 | head -n 2 #put output into sorted list, with uniq counts, and trim outer bounds 
              

Lista de respuestas

3
 
vote
vote
La mejor respuesta
 

Sus sospechas son correctas. La cantidad de trabajo que realiza el sistema operativo para usted generar un proceso es formidable, mucho más trabajo que el proceso de procesamiento de cadenas.

Para cada línea en el archivo de registro, usted es Sprawning 13 procesos:

  1. cut
  2. tr
  3. cut
  4. tr
  5. xargs
  6. date
  7. bash - Debido al uso de $( ) sustitución
  8. cut8
  9. tr
  10. tr0
  11. tr1
  12. tr2
  13. tr3

Por lo tanto, el problema se puede simplificar a la de la extracción, la reformateo y comparando las fechas repetidamente utilizando los menores subprocesos posibles. Incluso aconsejaría en contra de cualquier uso del comando 99887766655443314 dentro del bucle. Todo se puede hacer con solo procesamiento de cadenas, usando SED y AWK.

  tr5  

Algunas observaciones adicionales:

  • Estoy desconcertado por el hecho de que tr6 se definió con una granularidad de un segundo. Hubiera esperado que usted quiera usar la medianoche como el límite, no sea la hora del día en que ejecute el script.
  • También estoy desconcertado por el uso de tr7 y tr8 para descartar algunos de los resultados. ¿Por qué no solo establecer la primera y la última fecha correctamente en el primer lugar?
  • Dado que la salida del bucle ya está en orden cronológico inverso, 99887776655443319 simplemente revierte todo. cut0 lograría lo mismo con más facilidad.

También sugeriría que no se molestara en procesar el archivo de registro a la inversa. Leer un archivo de línea por línea hacia atrás es más complicado, ya que la lectura no se realiza secuencialmente, byte por byte. Además, la necesidad de revertir los resultados requiere el almacenamiento en búfer a toda la salida, evitando que el script imprimue los resultados incrementalmente al día a la vez. El procesamiento cronológico inverso solo tiene sentido si el archivo de registro es enorme y cubre un período mucho más largo que la quincena de interés. Sin embargo, si su archivo de registro es realmente tan grande, realmente debería considerar una mecanismo de rodadura de registro . Si cada archivo de registro solo se extiende un día, ¡todo el problema se convierte en un ejercicio de conteo de línea trivial!

 

Your suspicions are correct. The amount of work that the operating system does for you to spawn a process is formidable xe2x80x94 much more work than the string processing work itself.

For every line in the log file, you are spawning 13 processes:

  1. cut
  2. tr
  3. cut
  4. tr
  5. xargs
  6. date
  7. bash xe2x80x94 due to the use of $( ) substitution
  8. cut
  9. tr
  10. cut
  11. tr
  12. xargs
  13. date

Therefore, the problem can be simplified to that of extracting, reformatting, and comparing dates repeatedly using the fewest subprocesses possible. I would even advise against any use of the date command within the loop. The whole thing can be done with just string processing, using sed and awk.

# Log is in common log format # host ident authuser date request status bytes # 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326  first_date=$(date --date='1 fortnight ago' +%Y-%m-%d) last_date=$(date --date='1 day ago' +%Y-%m-%d)  # Processing the log file in reverse chronological order, # extract the date as YYYY-MM-DD, if it is between # $first_date and $last_date, inclusive. # # Then, present the hit counts in chronological order. tac /etc/httpd/logs/access_log | \     sed -e 's!.*\[\(../.../....\):.*!\1!' | \     gawk -F/ -v first_date="$first_date" -v last_date="$last_date" '         BEGIN {             M["Jan"] = "01"; M["Feb"] = "02"; M["Mar"] = "03"; M["Apr"] = "04";             M["May"] = "05"; M["Jun"] = "06"; M["Jul"] = "07"; M["Aug"] = "08";             M["Sep"] = "09"; M["Oct"] = "10"; M["Nov"] = "11"; M["Dec"] = "12";         }         {             DATE=sprintf("%s-%s-%s", $3, M[$2], $1);             if (DATE < first_date) { exit }             if (DATE <= last_date) { print DATE }         }     ' | \     uniq -c | \     tac 

Some additional remarks:

  • I am puzzled by the fact that $enddate was defined with a granularity of one second. I would have expected that you would want to use midnight as the limit, not whatever time of day you happen to run the script at.
  • I am also puzzled by the use of head -n -1 and head -n 2 to discard some of the results. Why not just set the first and last date correctly in the first place?
  • Since the output from the loop is already in reverse chronological order, sort merely reverses everything. tac would accomplish the same thing more easily.

I would also suggest that you not bother processing the log file in reverse. Reading a file line-by-line backwards is trickier, as reading is not done sequentially, byte by byte. Furthermore, the need to reverse the results requires buffering all of the output, preventing the script from printing results incrementally a day at a time. Reverse chronological processing only makes sense if the log file is enormous and covers a period much much longer than the fortnight of interest. However, if your log file is really that large, you really ought to consider a log-rolling mechanism. If each log file only spans one day, the entire problem becomes a trivial line count exercise!

 
 
 
 

Relacionados problema

4  Usando la expresión regular de SED para extraer el nombre de dominio del archivo  ( Using sed regular expression to extract domain name from file ) 
Estoy aprendiendo regex con sed Para extraer el último campo del archivo llamado "Prueba". El método que estoy intentando da la salida deseada. Por favor, s...

2  Añadiendo un cero a los nombres de archivos  ( Adding a zero to file names ) 
He descubierto recientemente el poder del SED; Las expresiones regulares parecen que se llevarán toda la vida para dominar. Este pequeño script utiliza ambos ...

4  Bash Shell Script utiliza SED para crear e insertar varias líneas después de una línea en particular en un archivo existente  ( Bash shell script uses sed to create and insert multiple lines after a particula ) 
Este código parece funcionar, pero me gustaría que alguien con Shell-Fu lo revisara. es el archivo temporal una buena idea? ¿Cómo lo haría sin? es la her...

4  Find-grep-sed para la búsqueda de proyectos y reemplazar  ( Find grep sed for project wide search replace ) 
Siempre olvido cómo hacer esto de manera eficiente con el Arglista de VIM. Inspiración de dibujo en una publicación en Desbordamiento de la pila , escribí un...

3  Script de bash para administrar notas de hashtag  ( Bash script for managing hashtag notes ) 
He escrito un script simple para administrar las notas de Hashtag. No estoy familiarizado con la scriptación de bash, así que realmente lo apreciaría si alg...

3  Acelerar el conjunto de comandos SED en archivos (recursivamente en el directorio completo)  ( Accelerate set of sed commands in files recursively over full directory ) 
ejecuto esto para solucionar algunas referencias codificadas por duros, reemplazando las ocurrencias de Folder.py3 por Folder.py4 : Folder.py5 Sin em...

4  Retire cada línea que incluya y siga la segunda ocurrencia de un patrón dado  ( Remove every line that include and follows the second occurrence of a given patt ) 
De un archivo, estoy tratando de eliminar cada línea que incluya y siga la segunda ocurrencia de un patrón dado en Bash (Mac OSX). Tenga en cuenta que un arch...

0  Cargando un archivo en VIM a través de la salida de tubos de AG  ( Loading a file in vim via piped output of ag ) 
Me siento como si mi escenario fuera bastante simple, pero que podría sobrecomplicarlo. Estoy buscando a través de archivos en busca de una condición especi...

4  Transponer una matriz usando sed  ( Transpose a matrix using sed ) 
Estoy tratando de transponer los siguientes datos de: template <class T> using Container = std::vector< std::shared_ptr<T> >; template <class T> Container...

3  Habilitar o deshabilitar secciones de un modelo de acuerdo con la entrada del usuario  ( Enable or disable sections of a model according to user input ) 
Estoy usando el comando SED para comentar dentro o fuera de las secciones en mi modelo de acuerdo con la entrada del usuario (comentar se realiza al prefijars...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos