Apache Logging Via ZeroMQ (Part 2)

By Morten Møller Riis

July 20 2012 10:00 CET

Since my previous blog post about Apache Logging Via ZeroMQ I’ve noticed that the Ruby script seems to use a lot of CPU on our servers.

I rewrote the logger in C which uses way less memory and a lot less CPU. Feel free to grab it and do whatever :)

Note that the server IP is hardcoded in the program. You might want to pass the IP and port using ARGV instead.

Also note that it will only read 2048 characters from STDIN at a time. This should, however, be more than sufficient for Apache access log lines.

To compile this script you will ofcourse need libzmq and gcc. Then just compile as gcc -Wall -lzmq zeromqlogger.c -o zeromqlogger.

            /*
            
              zeromqlogger.c
            
              This program takes Apache log lines from STDIN and sends them via zeromq.
            
              Written by Morten Møller Riis
            
            */
            
            #include <stdlib.h>
            #include <stdio.h>
            #include <assert.h>
            #include <string.h>
            #include <zmq.h>
            #include <signal.h>
            
            // These are global so we can close them in the signal handler
            void* ctx = NULL;
            void* socket = NULL;
            
            void term(int signum)
            {
                printf("Received %i, closing context and socket...\n", signum);
                zmq_close(socket);
                zmq_term(ctx);
                printf("Exiting.");
                exit(0);
            }
            
            int main(int argc, char **argv) {
              signal(SIGTERM, term);
              signal(SIGINT, term);
            
              int nbytes = 2049; // The max message size +1
              char message[nbytes];
              char c;
              int i;
            
              int rc;
              void *ctx, *socket;
              zmq_msg_t query;
            
              ctx = zmq_init(1);
              assert(ctx);
            
              socket = zmq_socket(ctx, ZMQ_PUSH);
              assert(socket);
            
              // The server ip is compiled in for the moment
              rc = zmq_connect(socket, "tcp://1.2.3.4:4010");
              assert(rc == 0);
            
              while(1) {
                // Clear the char array
                memset(message, '\0', nbytes);
            
                // Read the input from stdin
                for(i=0;i<nbytes-1;i++) {
                  c = fgetc(stdin);
                  if(c == EOF) break;
                  if(c == '\n') break;
                  message[i] = c;
                }
            
                // Send the message
                rc = zmq_msg_init_size(&query, strlen(message));
                assert(rc == 0);
            
                memcpy(zmq_msg_data(&query), message, strlen(message));
                rc = zmq_send(socket, &query, 0);
                assert(rc == 0);
                zmq_msg_close(&query);
              }
            
              // Should never reach this point
              zmq_close(socket);
              zmq_term(ctx);
              
              return 0;
            }