Tengo un proceso que escribir un montón de datos a la salida estándar (stdout), de las que voy a redirigir a un archivo de registro. Me gustaría limitar el tamaño del archivo de vez en cuando a copiar el archivo actual con un nuevo nombre y truncar.

Mis técnicas habituales de truncar un archivo, como

cp /dev/null file

no funcionan, presumiblemente debido a que el proceso está utilizando.

¿Hay alguna manera de que pueda truncar el archivo? O eliminarlo y de alguna manera asociado el proceso de’ stdout con un nuevo archivo?

Por lo que vale, es un producto de terceros que no puedo modificar para cambiar su modelo de registro.

EDITAR redirigir sobre el archivo parece tener el mismo problema que la copia anterior – el archivo vuelve a su tamaño anterior y la próxima vez escrito a:

ls -l sample.log ; echo > sample.log ; ls -l sample.log ; sleep 10 ; ls -l sample.log
-rw-rw-r-- 1 user group 1291999 Jun 11  2009 sample.log
-rw-rw-r-- 1 user group 1 Jun 11  2009 sample.log
-rw-rw-r-- 1 user group 1292311 Jun 11  2009 sample.log
InformationsquelleAutor Hobo | 2009-06-11

13 Comentarios

  1. 10

    Echar un vistazo a la utilidad split(1), parte de GNU Coreutils.

    • Excelente, gracias. Se ve como la mejor opción para lo que yo quiero hacer.
    • Parece extraño que esta es la solución elegida. No hace nada para reducir el tamaño del archivo; todo lo que hace es darle una copia de las secciones del archivo, así como el original.
    • Sí, este hace lo que necesito, en lugar de lo que te pedí. Voy a redirigir a través de split, en lugar de directamente en el archivo de registro, lo que limitará el tamaño de los archivos de registro individuales.
    • para aquellos que están rascándose la cabeza que ¿qué significa esto: $your_command | split –bytes 100M – prefijo
    • Votada abajo. Necesita más de una respuesta, con detalles, de ser ASÍ la calidad.
  2. 31

    Como de coreutils 7.0, hay un truncate comando.

    • Es que una opción de línea de comandos? O una función de C? El hombre de las páginas parecen implicar el último. No es que yo soy reacio a escribir un contenedor, sólo para mi entendimiento.
    • Siempre ha (para algún valor de siempre) ha sido una función de C truncate(). Como de coreutils 7.0, también hay un programa de truncar, que, presumiblemente, se ajusta la función C.
    • Gracias, me ayudó. He estado tratando de limpiar un tomcat registro sin parar y funciona.
    • ¿Realmente funciona para aplicaciones java? Para mí no! Incluso si truncate -s 0 GC.log durante unos segundos, se muestra un «truncado» archivo, después de este tiempo (supongo – cuando la aplicación se escribe más) – el archivo vuelve a su tamaño original.
  3. 26

    La cosa interesante acerca de los rebrotado de archivos es que los primeros 128 KB o lo será todo ceros después de truncar el archivo de copia de /dev/null sobre él. Esto ocurre porque el archivo se trunca a longitud cero, pero el archivo descriptor de la aplicación de los puntos inmediatamente después de su última escritura. Cuando se escribe de nuevo, el sistema de archivos que trata el inicio del archivo, como todos los de cero bytes sin escribir los ceros en el disco.

    Idealmente, usted debe pedir al proveedor de la aplicación para abrir el archivo de registro con el O_APPEND bandera. Esto significa que después de truncar el archivo, la siguiente escritura se implícitamente buscar hasta el final del archivo (el significado de vuelta a la compensación de cero) y, a continuación, escriba la nueva información.


    Este código plataformas de salida estándar por lo que es en O_APPEND modo y, a continuación, se invoca el comando dado por sus argumentos (algo así como nice se ejecuta un comando después de ajustar su buen nivel, o nohup se ejecuta un comando después de arreglar las cosas por lo que ignora SIGHUP).

    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <string.h>
    #include <errno.h>
    
    static char *arg0 = "<unknown>";
    
    static void error(const char *fmt, ...)
    {
        va_list args;
        int errnum = errno;
        fprintf(stderr, "%s: ", arg0);
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        if (errnum != 0)
            fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
        putc('\n', stderr);
        fflush(0);
        exit(1);
    }
    
    int main(int argc, char **argv)
    {
        int attr;
        arg0 = argv[0];
    
        if (argc < 2)
            error("Usage: %s cmd [arg ...]", arg0);
        if ((attr = fcntl(1, F_GETFL, &attr)) < 0)
            error("fcntl(F_GETFL) failed");
        attr |= O_APPEND;
        if (fcntl(1, F_SETFL, attr) != 0)
            error("fcntl(F_SETFL) failed");
        execvp(argv[1], &argv[1]);
        error("failed to exec %s", argv[1]);
        return(1);
    }
    

    Mi prueba de ello fue algo casual, pero apenas lo suficiente para convencerme de que funcionó.


    Alternativa más sencilla

    Billy notas en su respuesta que ‘>>‘ es el append operador – y, de hecho, en Solaris 10, bash (versión 3.00.16(1)) hace uso de la O_APPEND bandera – lo que hace que el código anterior innecesarios, como se muestra (‘Black JL:’ es mi mensaje en esta máquina):

    Black JL: truss -o bash.truss bash -c "echo Hi >> x3.29"
    Black JL: grep open bash.truss
    open("/var/ld/ld.config", O_RDONLY)             Err#2 ENOENT
    open("/usr/lib/libcurses.so.1", O_RDONLY)       = 3
    open("/usr/lib/libsocket.so.1", O_RDONLY)       = 3
    open("/usr/lib/libnsl.so.1", O_RDONLY)          = 3
    open("/usr/lib/libdl.so.1", O_RDONLY)           = 3
    open("/usr/lib/libc.so.1", O_RDONLY)            = 3
    open("/platform/SUNW,Ultra-4/lib/libc_psr.so.1", O_RDONLY) = 3
    open64("/dev/tty", O_RDWR|O_NONBLOCK)           = 3
    stat64("/usr/openssl/v0.9.8e/bin/bash", 0xFFBFF2A8) Err#2 ENOENT
    open64("x3.29", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3
    Black JL:
    

    Uso anexar la redirección en lugar de la envoltura (‘cantrip‘) código de arriba. Esto sólo sirve para demostrar que cuando se utiliza una técnica particular para otros (válido) a los efectos de adaptarlo a otro no es necesariamente el mecanismo más sencillo, aunque funciona.

    • El archivo de registro está creado por mí, por redirigir stdout. De cualquier manera para hacer el equivalente de O_APPEND en un archivo creado por un simple redirección?
    • sucintamente – no. O, al menos, muy poco probable. Si fueron capaces de iniciar el programa bajo un depurador, usted podría ser capaz de hacer un fcntl() llamada al sistema para agregar el O_APPEND atributo a la salida estándar, pero de lo contrario, usted está atascado, creo. Bueno, vamos a pensar…podría escribir una envoltura alrededor de la otra aplicación…que hace la fcntl() – y tal vez la redirección demasiado – y, a continuación, ejecuta el Programa de 3er Partido. Dame un tiempo para ver que correctamente…
    • Wow. Saludos por tomarse el tiempo para escribir eso. Creo que es más de lo que me gustaría hacer en este momento, creo que me quedo con el split – pero realmente agradezco que se haya tomado el tiempo. Una pena que no puedo votar más de una vez por tu respuesta 😉
    • no era un problema; se trata en su mayoría de reciclaje utilizado anteriormente fragmentos (a pesar de que el ajuste de las banderas con las dos llamadas a fcntl() era nuevo). Usted puede ver me tomó 25 minutos para montar – no mucho.
    • Simplemente redirigir la salida estándar con >> en lugar de >, como se señaló en @Billy respuesta.
    • Gracias por esta respuesta. Me metí en esa cuestión al rotar con la copia/truncar un archivo de registro y no entendía por qué el archivo fue creciendo de nuevo a su estado original tamaño lógico.

  4. 12

    Redirigir la salida con >> en lugar de >. Esto permitirá que usted para truncar el archivo sin el archivo a crecer a su tamaño original. También, no olvide redirigir STDERR (2>&1).

    Por lo que el resultado final sería: myprogram >> myprogram.log 2>&1 &

  5. 8

    Intentar > file.


    Actualización con respecto a los comentarios: funciona muy bien para mí:

    [email protected]:~> echo "content" > test-file
    [email protected]:~> cat test-file 
    content
    [email protected]:~> > test-file
    [email protected]:~> cat test-file 
    
    • Agradecería saber por qué tengo votada abajo.
    • Redirigir el archivo no parece funcionar con el mismo problema como el «cp /dev/null archivo» he mencionado en la pregunta. Parece que funciona, pero la próxima vez que el archivo del escrito que vuelve a su tamaño anterior. En mi sabor de linux que cada comando devuelve «no Válido de null comando.»; no sé si usted estaba sugiriendo que «[algo] > archivo», en lugar de «> archivo».
    • Quiero decir exactamente ‘> archivo’, tal vez es un golpe comando específico. El archivo de la reversión es bastante strage aunque.
    • He visto este comportamiento también. Casi parece que el puntero de archivo se cambia a un nuevo archivo vacío. Pero el proceso de ejecución tiene una manija en el archivo antiguo. Cuando se escribe, se cambia el puntero de archivo para el archivo antiguo.
  6. 6

    Tuve un problema similar en redhat v6, echo > file o > file estaba causando apache y tomcat para ir defectuoso como el registro de los archivos se vuelven inaccesibles para ellos.

    Y la solución era extraño

    echo " " > file
    

    iba a limpiar el archivo y no causa ningún problema.

    • este trabajó como un encanto!
    • Trabajó para mí también. Usted salvó mi día
  7. 3

    como el archivo está siendo utilizado, si se intenta anular o algo así, a veces puede «confundir» a la aplicación que está escrito en el archivo de registro y es posible que no registro nada después de eso.

    Lo que me gustaría probar ot hacer es establecer una especie de proxy/filtro para ese registro, en lugar de redirigir a un archivo, se redirige a un proceso o algo que pudiera obtener la entrada y escribir en un archivo rodante.

    Tal vez puede ser hecho por el guión de lo contrario, usted puede escribir una aplicación sencilla para que ( java o algo más ). El impacto en el rendimiento de la aplicación debe ser muy pequeño, pero usted tendrá que ejecutar algunas pruebas.

    Por cierto, tu aplicación, es un stand-alone, web app, … ? Tal vez hay otras opciones para ser investigado.

    Edit: también hay un Anexar Operador de Redirección >> que personalmente nunca he usado, pero podría no bloquear el archivo.

    • Saludos. Sí, yo creo que ese es el enfoque que voy a tomar. Voy a usar Michiel sugerencia de uso de split. No me había dado cuenta de lo trabajado en stdin, así como archivos (que yo debería tener).
  8. 3

    En Linux (en realidad todos los unicies) se crean los archivos cuando se abren y se elimina cuando nada contiene una referencia a ellos. En este caso el programa que se abrieron y el directorio fue inaugurado el ‘en’ mantener las referencias al archivo. Cuando el programa cp quiere escribir en el archivo que se obtiene una referencia a él desde el directorio, escribe una longitud de cero en los metadatos que se almacenan en el directorio (esto es una pequeña simplificación) y da la manija. A continuación, el programa original, que todavía se mantiene el original identificador de archivo, escribe algunos datos más para el archivo y guarda lo que piensa que la longitud debe ser.

    incluso si elimina el archivo en el directorio el programa de continuar con la escritura de datos (y el uso de espacio en disco), incluso a pesar de que ningún otro programa habría alguna manera de hacer referencia a ella.

    en resumen una vez que el programa tiene una referencia (asa) a un archivo nada de lo que hagas va a cambiar eso.

    hay en la teoría de las formas de modificar el comportamiento de programas mediante el establecimiento de LD_LIBRARY_PATH para incluir un programa que intercepta todos los archivos de sistema de acceso de llamadas. Recuerdo haber visto algo como esto en alguna parte, aunque puedo recordar el nombre.

    • Usted probablemente necesita LD_PRELOAD en lugar de LD_LIBRARY_PATH. Creo que estás en el camino correcto con su explicación, aunque los detalles son un poco lanudo – ver mi explicación (que probablemente pueda tener la misma acusación lanzada a ella).
    • Gracias por aclarar por qué está sucediendo. Me imaginé que era algo así, pero bueno han confirmado. Creo que la interceptación de llamadas al sistema es más de lo que me gustaría hacer en este caso, pero gracias por otra alternativa.
  9. 3

    He descargado y compilado la última coreutils para que yo pudiera tener truncate disponible.

    Corrió ./configure y make, pero no se ejecutó make install.

    Todos los resultados de las utilidades que aparecen en el «src» de la carpeta.

    Corrí

    [path]/src/truncate -s 1024000 textfileineedtotruncate.log

    en un 1,7 GB de archivo de registro.

    No cambiar el tamaño de la muestra cuando el uso de ls -l, pero lo hizo liberar todo el espacio de disco – que es lo que realmente necesitaba hacer antes de /var llena y se mató el proceso.

    Gracias por la punta en «truncar»!

  10. 2

    ¿Has comprobado el comportamiento de las señales como SIGHUP a los productos de terceros, a ver si se puede iniciar el registro de un nuevo archivo? Podría mover el antiguo archivo a un nombre permanente, en primer lugar.

    kill-HUP [proceso-id]

    Y, a continuación, iba a empezar a escribir de nuevo.

    Alternativamente (como Billy sugerido) tal vez redirigir el resultado de la aplicación de un programa de registro como multilog o el que se usa comúnmente con Apache, conocido como cronolog. Entonces usted tendrá más control muy detallado de donde todo va delante de él está escrito inicial descriptor de archivo (file), que es realmente todo lo que es.

    • Creo que no quiero reiniciar el proceso es bastante lento para llegar, y que había afectar a nuestros usuarios), pero se alegra por enseñarme acerca de kill-HUP – yo no estaba consciente de eso.
    • multilog se ve genial, gracias por la sugerencia !
    • Solo para aclarar, para los demonios que reconocer HOP, ‘kill-HUP’ les dice a releer su configuración y/o cerrar y volver a abrir los archivos que está utilizando. No reiniciar el proceso. (Si el demonio no la trampa de la HUP, entonces, sí, se morirá normalmente…)
    • Saludos Dave. Realmente necesito leer las páginas del manual más de cerca…
  11. 2

    @Hobo uso freopen(), reutiliza secuencia para abrir el archivo especificado por nombre de archivo o cambiar su modo de acceso.
    Si un nuevo nombre de archivo es especificado, la función de los primeros intentos para cerrar cualquier archivo que se encuentra asociado con la corriente (tercer parámetro) y disocia de ella. Entonces, independientemente de que el arroyo se cerró exitosamente o no, freopen abre el archivo especificado por nombre de archivo y la asocia con la corriente como fopen haría con el mismo modo.

    si un tercero binario es la generación de los registros que tenemos que escribir un contenedor que va a rotar los logs, y en tercero se ejecutará en proxyrun de hilo de abajo.

    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <unistd.h>
    #include <string.h>
    
    using namespace std;
    
    extern "C" void * proxyrun(void * pArg){
       static int lsiLineNum = 0;
       while(1) 
       {
         printf("\nLOGGER: %d",++lsiLineNum);
         fflush(stdout);
       }
      return NULL;
    }
    
    
    int main(int argc, char **argv)
    {
      pthread_t lThdId;
      if(0 != pthread_create(&lThdId, NULL, proxyrun, NULL))
      {
        return 1;
      }
    
      char lpcFileName[256] = {0,};
    
      static int x = 0;
    
      while(1)
      {
        printf("\n<<<MAIN SLEEP>>>");
        fflush(stdout);
        sprintf(lpcFileName, "/home/yogesh/C++TestPrograms/std.txt%d",++x);
        freopen(lpcFileName,"w",stdout);
        sleep(10);
      }
    
      return 0;
    }
    
  12. 1

    lugar de redirigir a un archivo que podría dirigir a un programa que gira automáticamente el archivo por el cierre, se mueve y la apertura de uno nuevo cada vez que se vuelve demasiado grande.

  13. 1

    He tenido un problema similar y era incapaz de hacer un «tail-f» en la salida de un script que se ejecuta desde el cron:

        * * * * * my_script >> /var/log/my_script.log 2>&1
    

    Me fijo cambiando la redirigir stderr:

        * * * * * my_script >> /var/log/my_script.log 2>/var/log/my_script.err
    

Dejar respuesta

Please enter your comment!
Please enter your name here