bongo/dev-libs/log4c/files/log4c-socket.patch

1165 lines
35 KiB
Diff
Raw Permalink Normal View History

commit 71138c20cb9d40b5c0d1cdce7430616d7088148b
Author: František Dvořák <valtri@civ.zcu.cz>
Date: Sun Mar 24 18:15:37 2013 +0100
New socket appender (SF patch #2881285).
diff --git a/configure.in b/configure.in
index a4b49dd..0e2993a 100644
--- a/configure.in
+++ b/configure.in
@@ -93,11 +93,14 @@ AC_CHECK_HEADER(pthread.h,[
AC_CHECK_LIB(pthread,pthread_mutex_init,[
LIBS="$LIBS -lpthread"
AC_DEFINE([WITH_ROLLINGFILE], [], [Define if we found pthread.h libpthread])
- AC_MSG_NOTICE([Compile with rollingfile code])
- with_rollingfile=true],[AC_MSG_NOTICE([No pthread--not compiling rollingfile code])]
+ AC_DEFINE([WITH_SOCKET], [], [Define if we found pthread.h libpthread])
+ AC_MSG_NOTICE([Compile with additional appenders])
+ with_rollingfile=true
+ with_socket=true],[AC_MSG_NOTICE([No pthread--not compiling rollingfile code])]
)
])
AM_CONDITIONAL(WITH_ROLLINGFILE, test "x$with_rollingfile" = "xtrue")
+AM_CONDITIONAL(WITH_SOCKET, test "x$with_socket" = "xtrue")
#####################################
# Enable test compilation if required
diff --git a/src/log4c/appender_type_socket.c b/src/log4c/appender_type_socket.c
new file mode 100644
index 0000000..9ce215e
--- /dev/null
+++ b/src/log4c/appender_type_socket.c
@@ -0,0 +1,783 @@
+static const char version[] = "$Id$";
+
+/*
+ * appender_socket.c
+ *
+ * Copyright 2009, H.A.J ten Brugge All rights reserved.
+ *
+ * See the COPYING file for the terms of usage and distribution.
+ */
+
+#define _XOPEN_SOURCE 500 /* PTHREAD_PRIO_INHERIT */
+
+#ifdef __linux__
+#define _GNU_SOURCE /* syscall */
+#include <unistd.h>
+#include <syscall.h>
+#endif
+#include <log4c/appender.h>
+#include <log4c/appender_type_socket.h>
+#include <sd/malloc.h>
+#include <sd/sd_xplatform.h>
+#include <priority.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <semaphore.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define DEFAULT_PORTNR (4560) /* chainsaw port number */
+#define DEFAULT_SIZE (10000)
+
+#define SOCK_PACK(b,p,v) { (b)[(p) + 0] = (unsigned char) ((v) >> 24); \
+ (b)[(p) + 1] = (unsigned char) ((v) >> 16); \
+ (b)[(p) + 2] = (unsigned char) ((v) >> 8); \
+ (b)[(p) + 3] = (unsigned char) ((v) >> 0); }
+#define SOCK_UNPACK(b,p) ((((b)[(p) + 0] & 0xff) << 24) | \
+ (((b)[(p) + 1] & 0xff) << 16) | \
+ (((b)[(p) + 2] & 0xff) << 8) | \
+ (((b)[(p) + 3] & 0xff) << 0))
+
+/* Local type for starting stopping service */
+typedef enum
+{
+ DOWN, /** initial state and when server finished */
+ STARTUP, /** set when the server is started */
+ RUNNING, /** set by server when initialized and running */
+ STOP /** set when the server must be stopped */
+}
+SERVER_STATE;
+
+struct socket_udata {
+ int socket;
+ int port;
+ char *hostname;
+ SERVER_STATE state;
+ unsigned int rd;
+ unsigned int wr;
+ unsigned int size;
+ unsigned char *buffer;
+ unsigned char *tmp;
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+ sem_t sem;
+};
+
+/* xxx would be nice to run-time check the type here */
+#define socket_get_udata(this) \
+ (socket_udata_t)log4c_appender_get_udata(this)
+
+static void uint2asc(unsigned int n, char *str);
+static void * socket_thread (void *data);
+static int socket_init (log4c_appender_t* this);
+static socket_udata_t socket_get_or_make_udata (log4c_appender_t* this);
+static void socket_free_udata (socket_udata_t sud);
+static int socket_append (log4c_appender_t* this,
+ const log4c_logging_event_t* a_event);
+static int socket_close (log4c_appender_t* this);
+
+/*******************************************************************************/
+
+static void uint2asc(unsigned int n, char *str)
+{
+ char *end = str;
+ char *begin = str;
+ char tmp;
+
+ do {
+ *end++ = "0123456789"[n % 10];
+ n /= 10;
+ } while (n);
+ *end-- = 0;
+ while (end > begin) {
+ tmp = *end;
+ *end-- = *begin,
+ *begin++ = tmp;
+ }
+}
+
+/*******************************************************************************/
+
+static void * socket_thread (void *data)
+{
+ static const char header[] = { '\xAC', '\xED', /* STREAM_MAGIC */
+ '\x00', '\x05' }; /* STREAM_VERSION */
+ socket_udata_t sud = (socket_udata_t ) data;
+ unsigned char *buf;
+ unsigned int len;
+ unsigned int count;
+ int r;
+ fd_set fdset;
+ struct timeval timeout;
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ char port[20];
+
+ uint2asc ((unsigned int) sud->port, port);
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_STREAM; /* Stream socket */
+ hints.ai_flags = AI_NUMERICSERV; /* Numeric portnr */
+ hints.ai_protocol = 0; /* Any protocol */
+ if (getaddrinfo(sud->hostname, port, &hints, &result) == 0) {
+ sud->state = RUNNING;
+ sem_post (&sud->sem);
+ pthread_mutex_lock (&sud->mtx);
+ while (sud->state == RUNNING) {
+ if (sud->socket < 0) {
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sud->socket = socket (rp->ai_family, rp->ai_socktype,
+ rp->ai_protocol);
+ if (sud->socket >= 0) {
+ if (connect (sud->socket, rp->ai_addr,
+ rp->ai_addrlen) != -1) {
+ break;
+ }
+ close (sud->socket);
+ sud->socket = -1;
+ }
+ }
+ if (sud->socket >= 0) {
+ buf = (unsigned char *) header;
+ len = sizeof (header);
+ count = 10;
+ while (sud->state == RUNNING && len) {
+ r = write (sud->socket,buf,len);
+ if (r < 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN ||
+ errno == EINTR)) {
+ count--;
+ if (count == 0) {
+ close (sud->socket);
+ sud->socket = -1;
+ len = 0;
+ }
+ }
+ else {
+ len -= r;
+ buf += r;
+ }
+ }
+ }
+ if (sud->socket < 0) {
+ pthread_mutex_unlock (&sud->mtx);
+ sleep (1);
+ pthread_mutex_lock (&sud->mtx);
+ }
+ }
+ else if (sud->rd != sud->wr) {
+ len = SOCK_UNPACK (sud->buffer, sud->rd);
+ if (len == 0) {
+ sud->rd = 0;
+ }
+ else {
+ memcpy (sud->tmp, sud->buffer + sud->rd + 4, len);
+ sud->rd += len + 4;
+ if (sud->rd == sud->wr) {
+ sud->rd = sud->wr = 0;
+ }
+ buf = sud->tmp;
+ pthread_mutex_unlock (&sud->mtx);
+ while (sud->state == RUNNING && len) {
+ r = write (sud->socket, buf, len);
+ if (r <= 0) {
+ if (r < 0 &&
+ (errno == EWOULDBLOCK || errno == EAGAIN ||
+ errno == EINTR)) {
+ FD_ZERO (&fdset);
+ FD_SET (sud->socket,&fdset);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1000000;
+ r = select (sud->socket + 1, NULL, &fdset, NULL,
+ &timeout);
+ if (r < 0 && errno != EWOULDBLOCK &&
+ errno != EAGAIN && errno != EINTR) {
+ close (sud->socket);
+ sud->socket = -1;
+ len = 0;
+ }
+ }
+ else {
+ close (sud->socket);
+ sud->socket = -1;
+ len = 0;
+ }
+ }
+ else {
+ len -= r;
+ buf += r;
+ }
+ }
+ pthread_mutex_lock (&sud->mtx);
+ }
+ }
+ if (sud->state == RUNNING && sud->socket >= 0 && sud->rd == sud->wr) {
+ pthread_cond_wait (&sud->cond, &sud->mtx);
+ }
+ }
+ pthread_mutex_unlock (&sud->mtx);
+ freeaddrinfo (result);
+ }
+ sud->state = DOWN;
+ sem_post (&sud->sem);
+ return NULL;
+}
+
+
+/*******************************************************************************/
+static int socket_init(log4c_appender_t* this){
+
+ socket_udata_t sud = socket_make_udata();
+
+ log4c_appender_set_udata (this, sud);
+
+ return(0);
+}
+
+/*******************************************************************************/
+static int socket_open(log4c_appender_t* this)
+{
+ socket_udata_t sud;
+ pthread_attr_t attr;
+ pthread_t id;
+ int rc = -1;
+
+ if (!this) {
+ return rc;
+ }
+ sud = socket_get_or_make_udata (this);
+ if (!sud) {
+ return rc;
+ }
+
+ sud->state = STARTUP;
+
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
+ if (pthread_create (&id, &attr, socket_thread, sud) == 0) {
+ while (sud->state == STARTUP) {
+ while (sem_wait (&sud->sem) < 0 && errno == EINTR);
+ }
+ }
+ else {
+ sud->state = DOWN;
+ }
+ pthread_attr_destroy (&attr);
+
+ log4c_appender_set_udata (this, sud);
+
+ return 0;
+}
+
+/*******************************************************************************/
+
+static socket_udata_t socket_get_or_make_udata(log4c_appender_t* this){
+ socket_udata_t sud;
+ int rc = 0;
+
+ sud = (socket_udata_t) log4c_appender_get_udata (this);
+
+ if ( !sud) {
+ rc = socket_init (this);
+ }
+
+ return (socket_get_udata (this));
+}
+
+/*******************************************************************************/
+
+LOG4C_API socket_udata_t socket_make_udata(){
+
+ socket_udata_t sud =
+ (socket_udata_t) sd_calloc(1, sizeof (struct socket_udata));
+ char *hostname = sd_strdup ("localhost");
+ unsigned char *buffer = (unsigned char *) sd_malloc (DEFAULT_SIZE);
+ unsigned char *tmp = (unsigned char *) sd_malloc (DEFAULT_SIZE);
+ pthread_mutexattr_t mattr;
+ pthread_condattr_t cattr;
+
+ if (sud && hostname && buffer && tmp) {
+ sud->socket = -1;
+ sud->size = DEFAULT_SIZE;
+ sud->hostname = hostname;
+ sud->port = DEFAULT_PORTNR;
+ sud->state = DOWN;
+ sud->rd = 0;
+ sud->wr = 0;
+ sud->buffer = buffer;
+ sud->tmp = tmp;
+ pthread_mutexattr_init (&mattr);
+#if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT != -1
+ pthread_mutexattr_setprotocol (&mattr, PTHREAD_PRIO_INHERIT);
+#endif
+ pthread_mutex_init (&sud->mtx, &mattr);
+ pthread_mutexattr_destroy (&mattr);
+ pthread_condattr_init (&cattr);
+ pthread_cond_init (&sud->cond, &cattr);
+ pthread_condattr_destroy (&cattr);
+ sem_init (&sud->sem, 1, 0);
+ }
+ else {
+ free (sud);
+ free (hostname);
+ free (buffer);
+ free (tmp);
+ sud = NULL;
+ }
+ return(sud);
+}
+
+/*******************************************************************************/
+
+LOG4C_API int socket_udata_set_host (socket_udata_t sud, char *value)
+{
+ char *hostname;
+ int rc = -1;
+
+ if (sud && value) {
+ hostname = sd_strdup (value);
+ if (hostname) {
+ free (sud->hostname);
+ sud->hostname = hostname;
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+/*******************************************************************************/
+
+LOG4C_API int socket_udata_set_port (socket_udata_t sud, int value)
+{
+ int rc = -1;
+
+ if (sud) {
+ sud->port = value;
+ }
+ return rc;
+}
+
+/*******************************************************************************/
+
+LOG4C_API int socket_udata_set_size (socket_udata_t sud, int value)
+{
+ unsigned char *buffer;
+ unsigned char *tmp;
+ int rc = -1;
+
+ if (!sud) return -1;
+ if (sud->size == value) return 0;
+
+ buffer = (unsigned char *) malloc (value);
+ tmp = (unsigned char *) malloc (value);
+ if (buffer && tmp) {
+ pthread_mutex_lock (&sud->mtx);
+ free (sud->buffer);
+ free (sud->tmp);
+ sud->size = value;
+ sud->buffer = buffer;
+ sud->tmp = tmp;
+ sud->rd = 0;
+ sud->wr = 0;
+ pthread_mutex_unlock (&sud->mtx);
+ rc = 0;
+ } else {
+ free (buffer);
+ free (tmp);
+ }
+
+ return rc;
+}
+
+/*******************************************************************************/
+
+static void socket_free_udata(socket_udata_t sud)
+{
+ pthread_mutex_destroy (&sud->mtx);
+ pthread_cond_destroy (&sud->cond);
+ sem_destroy (&sud->sem);
+ free (sud->buffer);
+ free (sud->tmp);
+ free (sud->hostname);
+ free (sud);
+}
+
+/*******************************************************************************/
+static int socket_append(log4c_appender_t* this,
+ const log4c_logging_event_t* a_event)
+{
+/* See: http://java.sun.com/javase/6/docs/platform/serialization/spec/protocol.html */
+ static const char event[] = {
+ '\x79', /* TC_RESET */
+ '\x73', /* TC_OBJECT */
+ '\x72', /* TC_CLASSDESC */
+ '\x00', '\x21', /* "org.apache.log4j.spi.LoggingEvent".length() */
+ 'o','r','g','.','a','p','a','c','h','e','.','l','o','g','4','j','.',
+ 's','p','i','.','L','o','g','g','i','n','g','E','v','e','n','t',
+ /* LoggingEvent.serialVersionUID */
+ '\xf3','\xf2','\xb9','\x23','\x74','\x0b','\xb5','\x3f',
+ '\x03', /* classDescFlags: SC_WRITE_METHOD | SC_SERIALIZABLE */
+ '\x00','\x0a', /* fields.length() */
+ 'Z', /* typecode for boolean 'Z' */
+ '\x00','\x15', /* "mdcCopyLookupRequired".length() */
+ 'm','d','c','C','o','p','y','L','o','o','k','u','p',
+ 'R','e','q','u','i','r','e','d',
+ 'Z', /* boolean field 'Z' */
+ '\x00','\x11', /* "ndcLookupRequired".length() */
+ 'n','d','c','L','o','o','k','u','p','R','e','q','u','i','r','e','d',
+ 'J', /* typecode for long 'J' */
+ '\x00','\x09', /* "timeStamp".length() */
+ 't','i','m','e','S','t','a','m','p',
+ 'L', /* typecode 'L' */
+ '\x00','\x0C', /* "categoryName".length() */
+ 'c','a','t','e','g','o','r','y','N','a','m','e',
+ '\x74', /* TC_STRING */
+ '\x00','\x12', /* "Ljava/lang/String;".length() */
+ 'L','j','a','v','a','/','l','a','n','g','/','S','t','r','i','n','g',';',
+ 'L', /* typecode 'L' */
+ '\x00','\x0C', /* "locationInfo".length() */
+ 'l','o','c','a','t','i','o','n','I','n','f','o',
+ '\x74', /* TC_STRING */
+ '\x00','\x23', /* "Lorg/apache/log4j/spi/LocationInfo;".length() */
+ 'L','o','r','g','/','a','p','a','c','h','e','/','l','o','g','4','j',
+ '/','s','p','i','/','L','o','c','a','t','i','o','n','I','n','f','o',';',
+ 'L', /* typecode 'L' */
+ '\x00','\x07', /* "mdcCopy".length() */
+ 'm','d','c','C','o','p','y',
+ '\x74', /* TC_STRING */
+ '\x00','\x15', /* "Ljava/lang/Hashtable;".length() */
+ 'L','j','a','v','a','/','l','a','n','g','/',
+ 'H','a','s','h','t','a','b','l','e',';',
+ 'L', /* typecode 'L' */
+ '\x00','\x03', /* "ndc".length() */
+ 'n','d','c',
+ '\x71', /* TC_REFERENCE */
+ '\x00','\x7E','\x00','\x01', /* handle to second serialized field */
+ 'L', /* typecode 'L' */
+ '\x00','\x0F', /* "renderedMessage".length() */
+ 'r','e','n','d','e','r','e','d','M','e','s','s','a','g','e',
+ '\x71', /* TC_REFERENCE */
+ '\x00','\x7E','\x00','\x01', /* handle to second serialized field */
+ 'L', /* typecode 'L' */
+ '\x00','\x0a', /* "threadName".length() */
+ 't','h','r','e','a','d','N','a','m','e',
+ '\x71', /* TC_REFERENCE */
+ '\x00','\x7E','\x00','\x01', /* handle to second serialized field */
+ 'L', /* typecode 'L' */
+ '\x00','\x0D', /* "throwableInfo".length() */
+ 't','h','r','o','w','a','b','l','e','I','n','f','o',
+ '\x74', /* TC_STRING */
+ '\x00','\x2B', /* "Lorg/apache/log4j/spi/ThrowableInformation;".length() */
+ 'L','o','r','g','/','a','p','a','c','h','e','/','l','o','g','4','j',
+ '/','s','p','i','/','T','h','r','o','w','a','b','l','e','I','n','f',
+ 'o','r','m','a','t','i','o','n',';',
+ '\x78', /* TC_ENDBLOCKDATA */
+ '\x70' }; /* TC_NULL */
+
+ char data1[10];
+#if 0
+ static const char datax[] = {
+ '\x00', /* mdcCopyLookupRequired */
+ '\x00', /* ndcLookupRequired */
+ /* timeStamp in ms */
+ '\x00','\x00','\x00','\x00','\x00','\x00','\x00','\x00' };
+#endif
+ char data2[3];
+#if 0
+ static const char datax[] = {
+ '\x74', /* categoryName: TC_STRING */
+ '\x00','\x04', /* "root".length() */
+ 'r','o','o','t' };
+#endif
+ static const char location[] = {
+ '\x73', /* TC_OBJECT */
+ '\x72', /* TC_CLASSDESC */
+ '\x00','\x21', /* "org.apache.log4j.spi.LocationInfo".length() */
+ 'o','r','g','.','a','p','a','c','h','e','.','l','o','g','4','j','.',
+ 's','p','i','.','L','o','c','a','t','i','o','n','I','n','f','o',
+ /* LocationInfo.serialVersionUID */
+ '\xed','\x99','\xbb','\xe1','\x4a','\x91','\xa5','\x7c',
+ '\x02', /* classDescFlags of SC_SERIALIZABLE */
+ '\x00','\x01', /* fields.length() */
+ 'L', /* typecode 'L' */
+ '\x00','\x08', /* "fullInfo".length() */
+ 'f','u','l','l','I','n','f','o',
+ '\x71', /* TC_REFERENCE */
+ '\x00','\x7E','\x00','\x01', /* handle to second serialized field */
+ '\x78', /* TC_ENDBLOCKDATA */
+ '\x70', /* TC_NULL */
+ '\x74' }; /* LocationInfo: TC_STRING */
+ char data3[2];
+#if 0
+static const char datax[] = {
+ '\x00','\x14', /* "tst.main(tst.java:8)".length() */
+ 't','s','t','.','m','a','i','n','(','t','s','t','.',
+ 'j','a','v','a',':','8',')' };
+#endif
+ char data4[6];
+ char data5[3];
+#if 0
+ static const char datax[] = {
+ '\x70', /* LocationInfo:: TC_NULL */
+ '\x70', /* mdcCopy: TC_NULL */
+ '\x70', /* ndc: TC_NULL */
+ '\x74', /* renderedMessage: TC_STRING */
+ '\x00','\x11', /* "Here is some INFO".length() */
+ 'H','e','r','e',' ','i','s',' ','s','o','m','e',' ','I','N','F','O',
+ '\x74', /* threadName: TC_STRING */
+ '\x00','\x04', /* "main".length() */
+ 'm','a','i','n' };
+#endif
+ char data6[9];
+#if 0
+ static const char datax[] = {
+ '\x70', /* throwableInfo: TC_NULL */
+ '\x77', /* BLOCKDATA */
+ '\x04', /* size */
+ '\x00','\x00','\x4e','\x20', /* Level.INFO */
+ '\x70', /* throwableInfo: TC_NULL */
+ '\x78' }; /* TC_ENDBLOCKDATA */
+#endif
+
+ socket_udata_t sud = (socket_udata_t) log4c_appender_get_udata(this);
+ char threadname[100];
+ char location_string[1000];
+ unsigned int len1;
+ unsigned int len2 = 0;
+ unsigned int len3;
+ unsigned int len4;
+ unsigned int level;
+ XP_UINT64 t;
+ unsigned int rdlen;
+ unsigned int totallen;
+
+ if ( !sud ) {
+ return(-1);
+ }
+
+ t = (XP_UINT64) a_event->evt_timestamp.tv_sec * 1000 +
+ (XP_UINT64) a_event->evt_timestamp.tv_usec / 1000;
+
+ data1[0] = 0x00; /* mdcCopyLookupRequired */
+ data1[1] = 0x00; /* ndcLookupRequired */
+ data1[2] = t >> 56; /* timeStamp in ms */
+ data1[3] = t >> 48;
+ data1[4] = t >> 40;
+ data1[5] = t >> 32;
+ data1[6] = t >> 24;
+ data1[7] = t >> 16;
+ data1[8] = t >> 8;
+ data1[9] = t >> 0;
+
+ len1 = strlen (a_event->evt_category);
+ data2[0] = 0x74; /* categoryName: TC_STRING */
+ data2[1] = len1 >> 8; /* categoryName:.length() */
+ data2[2] = len1 >> 0;
+
+ if (a_event->evt_loc) {
+ len3 = a_event->evt_loc->loc_function ?
+ strlen (a_event->evt_loc->loc_function) : 0;
+ len4 = a_event->evt_loc->loc_file ?
+ strlen (a_event->evt_loc->loc_file) : 0;
+ if ((len3 + len4 + 20) < sizeof (location_string)) {
+ location_string[0] = '\0';
+ if (a_event->evt_loc->loc_function) {
+ strcpy (&location_string[len2],
+ a_event->evt_loc->loc_function);
+ len2 += len3;
+ }
+ if (a_event->evt_loc->loc_file || a_event->evt_loc->loc_line) {
+ strcpy (&location_string[len2], "(");
+ len2++;
+ }
+ if (a_event->evt_loc->loc_file) {
+ strcpy (&location_string[len2],
+ a_event->evt_loc->loc_file);
+ len2 += len4;
+ }
+ if (a_event->evt_loc->loc_file || a_event->evt_loc->loc_line) {
+ strcpy (&location_string[len2], ":");
+ len2++;
+ }
+ if (a_event->evt_loc->loc_line) {
+ uint2asc ((unsigned int) a_event->evt_loc->loc_line,
+ &location_string[len2]);
+ len2 += strlen (&location_string[len2]);
+ }
+ if (a_event->evt_loc->loc_file || a_event->evt_loc->loc_line) {
+ strcpy (&location_string[len2], ")");
+ len2++;
+ }
+ data3[0] = len2 >> 8;
+ data3[1] = len2 >> 0;
+ }
+ }
+
+ len3 = strlen (a_event->evt_msg);
+ data4[0] = 0x70; /* LocationInfo:: TC_NULL */
+ data4[1] = 0x70; /* mdcCopy: TC_NULL */
+ data4[2] = 0x70; /* ndc: TC_NULL */
+ data4[3] = 0x74; /* renderedMessage: TC_STRING */
+ data4[4] = len3 >> 8; /* renderedMessage.length() */
+ data4[5] = len3 >> 0;
+
+#ifdef __linux__
+ uint2asc ((unsigned int) syscall (SYS_gettid), threadname);
+#else
+ uint2asc ((unsigned int) pthread_self (), threadname);
+#endif
+ len4 = strlen (threadname);
+ data5[0] = 0x74; /* threadName: TC_STRING */
+ data5[1] = len4 >> 8; /* threadName.length() */
+ data5[2] = len4 >> 0;
+
+ level = a_event->evt_priority;
+ switch (level) {
+ case LOG4C_PRIORITY_FATAL: level = 50000; break;
+ case LOG4C_PRIORITY_ALERT: level = 50000; break;
+ case LOG4C_PRIORITY_CRIT: level = 50000; break;
+ case LOG4C_PRIORITY_ERROR: level = 40000; break;
+ case LOG4C_PRIORITY_WARN: level = 30000; break;
+ case LOG4C_PRIORITY_NOTICE: level = 20000; break;
+ case LOG4C_PRIORITY_INFO: level = 20000; break;
+ case LOG4C_PRIORITY_DEBUG: level = 10000; break;
+ case LOG4C_PRIORITY_TRACE: level = 10000; break;
+ case LOG4C_PRIORITY_NOTSET: level = 2147483647; break;
+ case LOG4C_PRIORITY_UNKNOWN: level = 2147483647; break;
+ }
+ data6[0] = 0x70; /* throwableInfo: TC_NULL */
+ data6[1] = 0x77; /* BLOCKDATA */
+ data6[2] = 0x04; /* size */
+ data6[3] = level >> 24; /* Level */
+ data6[4] = level >> 16;
+ data6[5] = level >> 8;
+ data6[6] = level >> 0;
+ data6[7] = 0x70; /* throwableInfo: TC_NULL */
+ data6[8] = 0x78; /* TC_ENDBLOCKDATA */
+
+ totallen = sizeof(event) + sizeof(data1) + sizeof(data2) + len1 +
+ sizeof(data4) + len3 + sizeof(data5) + len4 + sizeof(data6);
+ if (len2) {
+ totallen += sizeof(location) + sizeof(data3) + len2 - 1;
+ }
+ pthread_mutex_lock (&sud->mtx);
+ for (;;) {
+ if (sud->wr < sud->rd) {
+ if ((totallen + 4) < (sud->rd - sud->wr)) {
+ break;
+ }
+ rdlen = SOCK_UNPACK (sud->buffer, sud->rd);
+ if (rdlen == 0) {
+ sud->rd = 0;
+ }
+ else {
+ sud->rd += rdlen + 4;
+ }
+ }
+ else {
+ if ((totallen + 8) <= (sud->size - sud->wr)) {
+ break;
+ }
+ if (sud->wr && sud->rd == 0) {
+ rdlen = SOCK_UNPACK (sud->buffer, sud->rd);
+ sud->rd += rdlen + 4;
+ }
+ else if (sud->wr == 0) {
+ totallen = 0;
+ break;
+ }
+ SOCK_PACK (sud->buffer, sud->wr, 0);
+ sud->wr = 0;
+ }
+ }
+ if (totallen) {
+ SOCK_PACK (sud->buffer, sud->wr, totallen);
+ sud->wr += 4;
+ memcpy (sud->buffer + sud->wr, event, sizeof(event));
+ sud->wr += sizeof(event);
+ memcpy (sud->buffer + sud->wr, data1, sizeof(data1));
+ sud->wr += sizeof(data1);
+ memcpy (sud->buffer + sud->wr, data2, sizeof(data2));
+ sud->wr += sizeof(data2);
+ memcpy (sud->buffer + sud->wr, a_event->evt_category, len1);
+ sud->wr += len1;
+ if (len2) {
+ memcpy (sud->buffer + sud->wr, location, sizeof(location));
+ sud->wr += sizeof(location);
+ memcpy (sud->buffer + sud->wr, data3, sizeof(data3));
+ sud->wr += sizeof(data3);
+ memcpy (sud->buffer + sud->wr, location_string, len2);
+ sud->wr += len2;
+ memcpy (sud->buffer + sud->wr, data4 + 1, sizeof(data4) - 1);
+ sud->wr += sizeof(data4) - 1;
+ }
+ else {
+ memcpy (sud->buffer + sud->wr, data4, sizeof(data4));
+ sud->wr += sizeof(data4);
+ }
+ memcpy (sud->buffer + sud->wr, a_event->evt_msg, len3);
+ sud->wr += len3;
+ memcpy (sud->buffer + sud->wr, data5, sizeof(data5));
+ sud->wr += sizeof(data5);
+ memcpy (sud->buffer + sud->wr, threadname, len4);
+ sud->wr += len4;
+ memcpy (sud->buffer + sud->wr, data6, sizeof(data6));
+ sud->wr += sizeof(data6);
+ pthread_cond_broadcast (&sud->cond);
+ }
+ pthread_mutex_unlock (&sud->mtx);
+ return 0;
+}
+
+/*******************************************************************************/
+static int socket_close(log4c_appender_t* this)
+{
+ socket_udata_t sud = (socket_udata_t) log4c_appender_get_udata (this);
+ int rc = -1;
+
+ if ( !this){
+ return rc;
+ }
+ sud = socket_get_udata (this);
+ if ( !sud){
+ return(rc);
+ }
+
+ if (sud->state == RUNNING) {
+ if (sud->socket >= 0 && sud->rd != sud->wr) {
+ sleep (1);
+ }
+ sud->state = STOP;
+ pthread_cond_broadcast (&sud->cond);
+ while (sud->state == STOP) {
+ while (sem_wait (&sud->sem) < 0 && errno == EINTR);
+ }
+ }
+
+ if (sud->socket >= 0) {
+ rc = close (sud->socket);
+ } else {
+ rc = 0;
+ }
+
+ /* Free up and reset any data associated with this socket appender */
+ socket_free_udata (sud);
+ log4c_appender_set_udata (this, NULL);
+
+ return (rc);
+}
+
+/*******************************************************************************/
+const log4c_appender_type_t log4c_appender_type_socket = {
+ "socket",
+ socket_open,
+ socket_append,
+ socket_close,
+};
diff --git a/src/log4c/appender_type_socket.h b/src/log4c/appender_type_socket.h
new file mode 100644
index 0000000..ac8ee00
--- /dev/null
+++ b/src/log4c/appender_type_socket.h
@@ -0,0 +1,81 @@
+/* $Id$
+ *
+ * appender_type_socket.h
+ *
+ * Copyright 2009, H.A.J ten Brugge All rights reserved.
+ *
+ * See the COPYING file for the terms of usage and distribution.
+ */
+
+#ifndef log4c_appender_type_socket_h
+#define log4c_appender_type_socket_h
+
+/**
+ * @file appender_type_socket.h
+ *
+ * @brief Log4c socket appender interface.
+ *
+ * The socket appender uses a socket connection for logging. The socket
+ * interface is the same as the log4j SocketReceiver. The default settings
+ * will connect to the chainsaw interface for log4j.
+ *
+ * There are some extra parameters in the xml file to setup the connection.
+ * The host (default localhost) and port (default 4560) are used to connect
+ * to a remote chainsaw server. The size option (default 10000) is used
+ * to buffer size data bytes until the connection to chainsaw is made.
+ * If no connection can be made the oldest event is deleted and overwritten
+ * the latest event.
+ *
+ **/
+
+#include <log4c/defs.h>
+#include <log4c/appender.h>
+
+__LOG4C_BEGIN_DECLS
+
+typedef struct socket_udata *socket_udata_t;
+
+/**
+ * Stream appender type definition.
+ *
+ * This should be used as a parameter to the log4c_appender_set_type()
+ * routine to set the type of the appender.
+ *
+ **/
+LOG4C_API const log4c_appender_type_t log4c_appender_type_socket;
+
+
+/**
+ * Get a new socket udata
+ * @return a new socket udata, otherwise NULL.
+ */
+LOG4C_API socket_udata_t socket_make_udata();
+
+/**
+ * Set the host name for the socket interface.
+ * @param sup the socket udata configuration object.
+ * @param value the host name.
+ * @return zero if successful, non-zero otherwise.
+ */
+LOG4C_API int socket_udata_set_host (socket_udata_t sup, char *value);
+
+/**
+ * Set the port number for the socket interface.
+ * @param sup the socket udata configuration object.
+ * @param value the post number.
+ * @return zero if successful, non-zero otherwise.
+ */
+LOG4C_API int socket_udata_set_port (socket_udata_t sup, int value);
+
+/**
+ * Set the buffer size for the socket interface.
+ * @param sup the socket udata configuration object.
+ * @param value the size to use for the buffering of data.
+ * @return zero if successful, non-zero otherwise.
+ */
+LOG4C_API int socket_udata_set_size (socket_udata_t sup, int value);
+
+
+__LOG4C_END_DECLS
+
+#endif
diff --git a/src/log4c/init.c b/src/log4c/init.c
index 4fa8577..d99dbd7 100644
--- a/src/log4c/init.c
+++ b/src/log4c/init.c
@@ -25,6 +25,7 @@ static const char version[] = "$Id$";
#include <appender_type_stream.h>
#include <appender_type_stream2.h>
+#include <appender_type_socket.h>
#include <appender_type_syslog.h>
#include <appender_type_mmap.h>
#include <appender_type_rollingfile.h>
@@ -59,7 +60,10 @@ static const log4c_appender_type_t * const appender_types[] = {
&log4c_appender_type_syslog,
#endif
#ifdef WITH_ROLLINGFILE
- &log4c_appender_type_rollingfile
+ &log4c_appender_type_rollingfile,
+#endif
+#ifdef WITH_SOCKET
+ &log4c_appender_type_socket,
#endif
};
static size_t nappender_types = sizeof(appender_types) / sizeof(appender_types[0]);
diff --git a/src/log4c/rc.c b/src/log4c/rc.c
index a9bb46e..fe6cbb1 100644
--- a/src/log4c/rc.c
+++ b/src/log4c/rc.c
@@ -19,6 +19,7 @@ static const char version[] = "$Id$";
#include <log4c/appender_type_rollingfile.h>
#include <log4c/rollingpolicy.h>
#include <log4c/rollingpolicy_type_sizewin.h>
+#include <log4c/appender_type_socket.h>
#include <sd/error.h>
#include <sd/domnode.h>
#include <sd/malloc.h>
@@ -218,6 +219,28 @@ static int appender_load(log4c_rc_t* this, sd_domnode_t* anode)
}
}
#endif
+#ifdef WITH_SOCKET
+ if ( !strcasecmp(type->value, "socket")) {
+ socket_udata_t sud = NULL;
+ sd_domnode_t* host = sd_domnode_attrs_get(anode,
+ "host");
+ sd_domnode_t* port = sd_domnode_attrs_get(anode,
+ "port");
+ sd_domnode_t* size = sd_domnode_attrs_get(anode,
+ "size");
+ sud = socket_make_udata();
+ if (host && host->value) {
+ socket_udata_set_host(sud, (char *)host->value);
+ }
+ if (port && port->value) {
+ socket_udata_set_port(sud, atoi ((char *)port->value));
+ }
+ if (size && size->value) {
+ socket_udata_set_size(sud, parse_byte_size ((char *)size->value));
+ }
+ log4c_appender_set_udata(app, sud);
+ }
+#endif
}
if (layout)
diff --git a/tests/log4c/Makefile.am b/tests/log4c/Makefile.am
index 9e0be30..84dff86 100644
--- a/tests/log4c/Makefile.am
+++ b/tests/log4c/Makefile.am
@@ -9,6 +9,10 @@ if WITH_ROLLINGFILE
noinst_PROGRAMS += test_rollingfile_appender test_rollingfile_appender_mt
endif
+if WITH_SOCKET
+noinst_PROGRAMS += test_socket_appender
+endif
+
cpp_compile_test_SOURCES = cpp_compile_test.cpp
test_category_SOURCES = test_category.c
@@ -40,6 +44,11 @@ test_rollingfile_appender_mt_LDADD = $(top_builddir)/src/log4c/liblog4c.la \
-lpthread
endif
+if WITH_SOCKET
+test_socket_appender_SOURCES = test_socket_appender.c
+test_socket_appender_LDADD = $(top_builddir)/src/log4c/liblog4c.la
+endif
+
test_big_SOURCES = test_big.c
test_big_LDADD = $(top_builddir)/src/log4c/liblog4c.la
diff --git a/tests/log4c/test_socket_appender.c b/tests/log4c/test_socket_appender.c
new file mode 100644
index 0000000..db9afe4
--- /dev/null
+++ b/tests/log4c/test_socket_appender.c
@@ -0,0 +1,140 @@
+
+/*
+ * test_socket_appender.c
+ *
+ * This file demonstrates how to programatically use the socket
+ * appender. See also the API documentation for the
+ * appender_type_socket.h file.
+ *
+ * It is possible to be more terse here if you accept the default values,
+ * but we spell it out explicitly.
+ *
+ * See the COPYING file for the terms of usage and distribution.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <log4c.h>
+#include <log4c/appender_type_socket.h>
+
+/*********************** Parameters **********************************
+ *
+ * params could be taken from the command line to facillitate testing
+ *
+*/
+
+/*
+ * socket specific params
+*/
+char *param_host = "localhost";
+//int param_port = 4445;
+int param_port = 4560;
+long param_size = 10000;
+
+/*
+ * Other Logging params
+ * xxx Problem with dated layout on windows: assert failure
+ * in gmtime call.
+*/
+char *param_layout_to_use = "dated"; /* could also be "basic" */
+
+/*******************************************************************
+ *
+ * Globals
+ *
+ */
+log4c_category_t* root = NULL;
+log4c_appender_t* socket_appender = NULL;
+/******************************************************************************/
+
+/*
+ * Init log4c and configure a socket appender
+ *
+*/
+static void init_log4c_with_socket_appender(){
+ int rc = 2;
+ socket_udata_t sud = NULL;
+
+ printf("using the socket appender "
+ "to send log events\n"
+ "remote host is '%s', remote port is %d, buffer size is %ld\n",
+ param_host, param_port, param_size);
+
+ if ( (rc = log4c_init()) == 0 ) {
+ printf("log4c init success\n");
+ } else {
+ printf("log4c init failed--error %d\n", rc);
+ return;
+ }
+
+ /*
+ * Get a reference to the root category
+ */
+ root = log4c_category_get("root");
+ log4c_category_set_priority(root,
+ LOG4C_PRIORITY_WARN);
+
+ /*
+ * Get an appender and set the type to socket
+ */
+ socket_appender = log4c_appender_get("aname");
+ log4c_appender_set_type(socket_appender,
+ log4c_appender_type_get("socket"));
+
+ /*
+ * Make a rolling file udata object and set the basic parameters
+ */
+ sud = socket_make_udata();
+ if (param_host) socket_udata_set_host(sud, param_host);
+ if (param_port) socket_udata_set_port(sud, param_port);
+ if (param_size) socket_udata_set_size(sud, param_size);
+
+ log4c_appender_set_udata(socket_appender, sud);
+
+ /*
+ * Configure a layout for the rolling file appender
+ */
+ log4c_appender_set_layout(socket_appender,
+ log4c_layout_get(param_layout_to_use) );
+
+ /*
+ * Configure the root category with our socket appender...
+ * and we can then start logging to it.
+ *
+ */
+ log4c_category_set_appender(root, socket_appender);
+
+ log4c_dump_all_instances(stderr);
+}
+
+static int test0(int argc, char* argv[])
+{
+ int i = 0;
+ init_log4c_with_socket_appender();
+
+ for (i = 0; i<200; i++){
+
+ log4c_category_fatal(root,
+ "%d%d%d%d%d%d%d%d%d%d%d%d%d\n",i,i,i,i,i,i,i,i,i,i,i,i,i);
+
+ }
+
+ /* Explicitly call the log4c cleanup routine */
+ if ( log4c_fini()){
+ printf("log4c_fini() failed");
+ }
+
+ return 1;
+}
+
+/******************************************************************************/
+int main(int argc, char* argv[])
+{
+
+ test0(argc,argv);
+
+ return(0);
+}
diff --git a/src/log4c/Makefile.am b/src/log4c/Makefile.am
index f9f5882..c14dac9 100644
--- a/src/log4c/Makefile.am
+++ b/src/log4c/Makefile.am
@@ -33,6 +33,10 @@
rollingpolicy.c rollingpolicy_type_sizewin.c
endif
+if WITH_SOCKET
+liblog4c_la_SOURCES += appender_type_socket.c
+endif
+
if WITH_MMAP
liblog4c_la_SOURCES += appender_type_mmap.c
endif
@@ -58,6 +62,7 @@
layout_type_dated_r.h \
layout_type_dated_local_r.h \
layout.h \
+ appender_type_socket.h \
appender_type_stream.h \
appender_type_stream2.h \
appender_type_syslog.h \