2013-11-22 16:31:24 +01:00
|
|
|
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);
|
|
|
|
+}
|
2013-11-22 17:01:27 +01:00
|
|
|
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 \
|