Parsear fichero de logs al rotar con cronolog
Resulta común querer parsear los logs una vez rotados, para ello se suelen configurar scripts que buscan el último fichero que se ha rotado y lo parsean. En lugar de complicar el script buscando el último, he realizado un pequeño patch para cronolog que permite ejecutar un script cuando cierra el fichero.
El patch añade la opción -F que indica el fichero a ejecutar al rotar los logs. Dicho patch incluye también el anterior que hice para cronolog que añade la opción para mandar directamente los logs a un syslog:
cd /usr/local/src svn export http://nagios-systemadmin.googlecode.com/svn/trunk/patchs/cronolog-syslog-onrotate.patch /usr/local/src/cronolog-onrotate-syslog.patch cd cronolog-1.6.2/ patch -p1 < ../cronolog-onrotate-syslog.patch ./configure && make && make install
A continuación simplemente deberemos añadir dicha opción -F con el script a ejecutar:
CustomLog "| /usr/local/sbin/cronolog -F /bin/true -S /var/www/systemadmin.es/logs/current.custom.log /var/www/systemadmin.es/logs/%Y/%m/%d/custom.log" combined
El script se ejecutará con el fichero cerrado como parámetro, por lo que ya podremos realizar la tarea que sea necesaria fácilmente sin tener que buscar el fichero.
El patch utiliza fstat() para saber si el descriptor de fichero apunta a un fichero que aún existe (no se ha borrado) y readlink() sobre /proc/self/fd/<id> para obtener el path del fichero:
diff -Naur cronolog-1.6.2/src/cronolog.c cronolog-1.6.2-syslog-onrotate/src/cronolog.c --- cronolog-1.6.2/src/cronolog.c 2001-05-03 18:42:48.000000000 +0200 +++ cronolog-1.6.2-syslog-onrotate/src/cronolog.c 2013-05-09 15:46:04.000000000 +0200 @@ -84,7 +84,16 @@ #include "cronoutils.h" #include "getopt.h" - +#include <stdio.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <netinet/in.h> +#include <sys/stat.h> +#include <sys/types.h> /* Forward function declaration */ @@ -105,8 +114,10 @@ "\n" \ " -H NAME, --hardlink=NAME maintain a hard link from NAME to current log\n" \ " -S NAME, --symlink=NAME maintain a symbolic link from NAME to current log\n" \ - " -P NAME, --prev-symlink=NAME maintain a symbolic link from NAME to previous log\n" \ " -l NAME, --link=NAME same as -S/--symlink\n" \ + " -P NAME, --prev-symlink=NAME maintain a symbolic link from NAME to previous log\n" \ + " -R NAME, --remote-syslog=NAME syslog server\n" \ + " -F NAME, --on-rotate=FILE file to execute on rotate\n" \ " -h, --help print this help, then exit\n" \ " -p PERIOD, --period=PERIOD set the rotation period explicitly\n" \ " -d DELAY, --delay=DELAY set the rotation period delay\n" \ @@ -122,7 +133,7 @@ /* Definition of the short and long program options */ -char *short_options = "ad:eop:s:z:H:P:S:l:hVx:"; +char *short_options = "ad:eop:s:z:H:P:F:R:S:l:hVx:"; #ifndef _WIN32 struct option long_options[] = @@ -134,6 +145,8 @@ { "hardlink", required_argument, NULL, 'H' }, { "symlink", required_argument, NULL, 'S' }, { "prev-symlink", required_argument, NULL, 'P' }, + { "remote-syslog", required_argument, NULL, 'R' }, + { "on-rotate", required_argument, NULL, 'F' }, { "link", required_argument, NULL, 'l' }, { "period", required_argument, NULL, 'p' }, { "delay", required_argument, NULL, 'd' }, @@ -156,6 +169,10 @@ char read_buf[BUFSIZE]; char tzbuf[BUFSIZE]; char filename[MAX_PATH]; + char onrotateexec[MAX_PATH]; + char onrotatefile[MAX_PATH]; + char *onrotatept = "/proc/self/fd/%d"; + char onrotateprocfile[MAX_PATH]; char *start_time = NULL; char *template; char *linkname = NULL; @@ -167,6 +184,11 @@ time_t time_offset = 0; time_t next_period = 0; int log_fd = -1; + int sock=-1; + struct sockaddr_in syslogsrv; + struct stat fstat_onrotate; + + onrotateexec[0]=0; #ifndef _WIN32 while ((ch = getopt_long(argc, argv, short_options, long_options, NULL)) != EOF) @@ -214,7 +236,25 @@ } prevlinkname = optarg; break; - + + case 'F': + strncpy(onrotateexec,optarg,MAX_PATH); + + break; + + case 'R': + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(sock< 0) + { + fprintf(stderr,"Failed to create socket\n"); + exit(1); + } + + memset(&syslogsrv,0,sizeof(syslogsrv)); + syslogsrv.sin_family = AF_INET; + syslogsrv.sin_addr.s_addr = inet_addr(optarg); + syslogsrv.sin_port = htons(514); + break; case 'd': period_delay_units = parse_timespec(optarg, &period_delay); @@ -334,6 +374,27 @@ */ if ((time_now >= next_period) && (log_fd >= 0)) { + if(onrotateexec[0]!=0) + { + if(fstat(log_fd, &fstat_onrotate) == 0) + { + if(fstat_onrotate.st_nlink>0) + { + snprintf(onrotateprocfile, MAX_PATH, onrotatept, log_fd); + if(readlink(onrotateprocfile, onrotatefile, MAX_PATH)) + { + DEBUG(("readlink(log_file)=%s\n", onrotatefile)); + + signal(SIGCHLD, SIG_IGN); + if(!fork()) + { + execl(onrotateexec, onrotateexec, onrotatefile, (char*)0 ); + } + } + } + } + } + close(log_fd); log_fd = -1; } @@ -359,6 +420,18 @@ perror(filename); exit(5); } + + /* syslog */ + if(sock >= 0) + { + if(sendto(sock, read_buf, n_bytes_read, 0, + (struct sockaddr *) &syslogsrv, + sizeof(syslogsrv) + ) == -1) + fprintf(stderr,"Error sendto()\n"); + } + + } /* NOTREACHED */
Deja un comentario: