view waaad/log.c @ 313:082d8f33f645

Temporary fix
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 25 Feb 2009 10:50:44 +0900
parents c2f839305f23
children 987cea8b1e37
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2008, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

/* Log facility.
 *
 * All messages generated by the application and extensions should be passed to one of the functions in this file.
 *
 * log_error : message is saved in syslog as error and/or sent to stderr.
 * log_normal: message is saved in syslog as info and/or sent to stdout.
 * log_debug : message is sent to stdout only.
 *
 * See log.h and log-api.h for more information on the functions 
 *
 */

#include "waaad-internal.h"

#include <stdarg.h>
#include <syslog.h>
#include <unistd.h>

/* Save the facilities where the logs must be sent */
static int log_to = 0;
pthread_key_t thread_name;

/* Mutex to protect concurrent accesses to the logs */
pthread_mutex_t log_mtx = PTHREAD_MUTEX_INITIALIZER;

/* Function to init/fini the log to the syslog */
static int log_init_syslog( void )
{
	/* open the log */
#ifndef PROJECT_NAME
#define PROJECT_NAME PACKAGE_NAME
#endif
	openlog(PROJECT_NAME, LOG_ODELAY, 0);
	
	/* Return */
	return 0;
}
static int log_fini_syslog( void )
{
	/* close the log */
	closelog();
	
	/* Return */
	return 0;
}

/* Function to init/fini the log to the console */
static int log_init_console( void )
{
	/* Nothing to do */
	return 0;
}
static int log_fini_console( void )
{
	/* Nothing to do */
	return 0;
}

/* Function to init/fini the log to a file */
static int log_init_file( void )
{
	fprintf (stderr, "Logging to file is not yet supported\n");
	/* Return */
	return ENOTSUP;
}
static int log_fini_file( void )
{
	fprintf (stderr, "Logging to file is not yet supported\n");
	/* Return */
	return ENOTSUP;
}

/* Function to set the thread's friendly name (usually called with THREAD_NAME) */
void log_set_thread_name(char * name, char * cat)
{
	void * val = NULL;
	
	TRACE_ENTRY("%p(%s) %p(%s)", name, name?:"/", cat, cat?:"/")
	
	/* First, check if a value is already assigned to the current thread */
	val = pthread_getspecific(thread_name);
	if (val != NULL) {
		TRACE_DEBUG(INFO, "Freeing old thread name: %s", val);
		free(val);
	}
	
	/* Now create the new string */
	if (name == NULL) {
		CHECK_POSIX_DO( pthread_setspecific(thread_name, NULL), /* continue */);
		return;
	}
	
	if (cat == NULL) {
		CHECK_MALLOC_DO( val = strdup(name), return );
	} else {
		CHECK_MALLOC_DO( val = malloc(strlen(name) + strlen(cat) + 2), return );
		sprintf(val, "%s/%s", cat, name);
	}
	
	CHECK_POSIX_DO( pthread_setspecific(thread_name, val), /* continue */);
	return;
}


/* Initialize the log facility */
int log_init ( int flags )
{
	int ret;
	
	if (flags == 0) {
		fprintf (stderr, "invalid flags in log_init\n");
		return EINVAL;
	}
		
	ret = pthread_key_create(&thread_name, free);
	if (ret != 0) {
		fprintf (stderr, "Error in pthread_key_create: %s\n", strerror(ret));
		return ret;
	}
		
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return ret;
	}
	
	if (log_to != 0) {
		fprintf (stderr, "Module already initialized\n");
		ret = EINVAL;
		goto error;
	}

	/* Save the value */
	log_to = flags;
	
	/* Init the facilities */
	if ( log_to & LOG_TO_SYSLOG ) {
		ret = log_init_syslog();
		if (ret < 0) {
			goto error;
		}
	}
	if ( log_to & LOG_TO_CONSOLE ) {
		ret = log_init_console();
		if (ret < 0) {
			goto error;
		}
	}
	if ( log_to & LOG_TO_FILE ) {
		ret = log_init_file();
		if (ret < 0) {
			goto error;
		}
	}
	
	ret = 0;
	
error:
	/* Unlock the mutex and return ret */
	(void) pthread_mutex_unlock(&log_mtx);
	if (ret == 0) {
		TRACE_DEBUG(FULL, "Log facility initialized");
	}
	return ret;
}
		
/* Reinit the facility */
int log_reinit ( int flags )
{
	int ret = 0;
	
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return ret;
	}
	
	/* log_to contains the previous facilities, flags contains the new ones */
	if ( (log_to ^ flags) & LOG_TO_SYSLOG ) {
		if (flags & LOG_TO_SYSLOG ) {
			/* Start the syslog facility */
			ret = log_init_syslog();
			if (ret < 0) {
				goto error;
			}
			log_to |= LOG_TO_SYSLOG;
		} else {
			/* Stop the syslog facility */
			(void) log_fini_syslog();
			log_to &= ~LOG_TO_SYSLOG;
		}
	}
			
	if ( (log_to ^ flags) & LOG_TO_CONSOLE ) {
		if (flags & LOG_TO_CONSOLE ) {
			/* Start the syslog facility */
			ret = log_init_console();
			if (ret < 0) {
				goto error;
			}
			log_to |= LOG_TO_CONSOLE;
		} else {
			/* Stop the syslog facility */
			(void) log_fini_console();
			log_to &= ~LOG_TO_CONSOLE;
		}
	}
	
	/* For file, we would have to reinit in all case since the file may have changed */
	if ( flags & LOG_TO_FILE ) {
		fprintf (stderr, "Logging to file is not yet supported\n");
		/* Return */
		ret = ENOTSUP;
	}

	ret = 0;

error:
	/* Unlock the mutex and return ret */
	(void) pthread_mutex_unlock(&log_mtx);
	return ret;
}

/* Terminate the facility */
int log_fini ( void )
{
	int ret;
	
	TRACE_ENTRY();
	
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return ret;
	}
	
	if (log_to == 0) {
		fprintf (stderr, "Module not initialized\n");
		ret = EINVAL;
		goto error;
	}

	/* Close the facilities */
	if ( log_to & LOG_TO_SYSLOG ) {
		(void) log_fini_syslog();
	}
	if ( log_to & LOG_TO_CONSOLE ) {
		(void) log_fini_console();
	}
	if ( log_to & LOG_TO_FILE ) {
		(void) log_fini_file();
	}
	
	/* Destroy the key */
	(void)pthread_key_delete(thread_name);
	
	log_to = 0;
	ret = 0;
	
error:
	/* Unlock the mutex and return ret */
	(void) pthread_mutex_unlock(&log_mtx);
	return ret;
}

/* Write current time into a buffer */
char * log_time(char * buf, size_t len)
{
	int ret;
	size_t offset = 0;
	struct timespec tp;
	struct tm tm;
	
	/* Get current time */
	ret = clock_gettime(CLOCK_REALTIME, &tp);
	if (ret != 0) {
		snprintf(buf, len, "%s", strerror(ret));
		return buf;
	}
	
	offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &tp.tv_sec , &tm ));
	offset += snprintf(buf + offset, len - offset, ".%6.6ld", tp.tv_nsec / 1000);

#if 0 /* Removed  cause it is not very useful... */
	#if defined(_POSIX_CPUTIME) && (_POSIX_CPUTIME != -1)
	if ((ret = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp))) {
		snprintf(buf + offset, len - offset, "(%s)", strerror(ret));
	} else {
		long sec;
		offset += snprintf(buf + offset, len - offset, "(pr:%ldd", tp.tv_sec / 86400);
		sec = tp.tv_sec % 86400;
		offset += strftime(buf + offset, len - offset, "%T", gmtime_r( &sec , &tm ));
		offset += snprintf(buf + offset, len - offset, ".%6.6ld)", tp.tv_nsec / 1000);
	}
	#endif /* _POSIX_CPUTIME */

	#if defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME != -1)
	if ((ret = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) {
		snprintf(buf + offset, len - offset, "(%s)", strerror(ret));
	} else {
		long sec;
		offset += snprintf(buf + offset, len - offset, "(th:%ldd", tp.tv_sec / 86400);
		sec = tp.tv_sec % 86400;
		offset += strftime(buf + offset, len - offset, "%T", gmtime_r( &sec , &tm ));
		offset += snprintf(buf + offset, len - offset, ".%6.6ld)", tp.tv_nsec / 1000);
	}
	#endif
#endif /* 0 */
	
	return buf;
}

/* Log an error message */
void log_error ( char * format, ... )
{
	int ret;
	va_list ap;
	
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return;
	}
	
	pthread_cleanup_push(cleanup_mutex, &log_mtx);
	
	if ( log_to & LOG_TO_SYSLOG ) {
		va_start(ap, format);
		vsyslog( LOG_ERR, format, ap);
		va_end(ap);
	}
	if ( log_to & LOG_TO_CONSOLE ) {
		va_start(ap, format);
		fprintf( stderr, "[ERR] ");
		vfprintf( stderr, format, ap);
		va_end(ap);
		fflush(stderr);
	}
	if ( log_to & LOG_TO_FILE ) {
		/* ignore yet, not supported */
		ASSERT(0);
	}
		
	/* Unlock the mutex and return ret */
	pthread_cleanup_pop(0);
	(void) pthread_mutex_unlock(&log_mtx);
	return;
}

/* Log a normal message */
void log_normal ( char * format, ... )
{
	int ret;
	va_list ap;
	
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return;
	}
	
	pthread_cleanup_push(cleanup_mutex, &log_mtx);
	
	if ( log_to & LOG_TO_SYSLOG ) {
		va_start(ap, format);
		vsyslog( LOG_INFO, format, ap);
		va_end(ap);
	}
	if ( log_to & LOG_TO_CONSOLE ) {
		va_start(ap, format);
		fprintf( stdout, "[NRM] ");
		vfprintf( stdout, format, ap);
		va_end(ap);
		fflush(stdout);
	}
	if ( log_to & LOG_TO_FILE ) {
		/* ignore yet, not supported */
		ASSERT(0);
	}
		
	/* Unlock the mutex and return ret */
	pthread_cleanup_pop(0);
	(void) pthread_mutex_unlock(&log_mtx);
	return;
}

/* Log a debug message */
void log_debug ( char * format, ... )
{
	int ret;
	va_list ap;
	
	/* If "quiet" has been specified, do not issue debug */
	if (g_conf->log_verbose < 0)
		return;
	
	ret = pthread_mutex_lock(&log_mtx);
	if (ret < 0) {
		fprintf (stderr, "pthread_mutex_lock failed\n");
		return;
	}
	
	pthread_cleanup_push(cleanup_mutex, &log_mtx);
	
	if ( log_to & LOG_TO_SYSLOG ) {
		va_start(ap, format);
		vsyslog( LOG_DEBUG, format, ap);
		va_end(ap);
	}
	if ( log_to & LOG_TO_CONSOLE ) {
		va_start(ap, format);
		fprintf( stdout, "[DBG] ");
		vfprintf( stdout, format, ap);
		va_end(ap);
		fflush(stdout);
	}
	if ( log_to & LOG_TO_FILE ) {
		/* ignore yet, not supported */
		ASSERT(0);
	}
		
	/* Unlock the mutex and return ret */
	pthread_cleanup_pop(0);
	(void) pthread_mutex_unlock(&log_mtx);
	return;
}

"Welcome to our mercurial repository"