2009-11-18 04:44:18 +03:00
/*
ctdb logging code
Copyright ( C ) Ronnie Sahlberg 2009
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2010-08-18 03:46:31 +04:00
# include "lib/tevent/tevent.h"
2009-11-18 04:44:18 +03:00
# include "lib/tdb/include/tdb.h"
2009-11-18 11:10:50 +03:00
# include "system/time.h"
2009-11-18 04:44:18 +03:00
# include "../include/ctdb_private.h"
2010-05-20 09:48:30 +04:00
# include "../include/ctdb_client.h"
2009-11-18 04:44:18 +03:00
2010-01-15 07:38:56 +03:00
int log_ringbuf_size ;
2009-12-04 03:36:27 +03:00
# define MAX_LOG_SIZE 128
static int first_entry ;
static int last_entry ;
2009-11-18 04:44:18 +03:00
struct ctdb_log_entry {
int32_t level ;
struct timeval t ;
2009-12-04 03:36:27 +03:00
char message [ MAX_LOG_SIZE ] ;
2009-11-18 04:44:18 +03:00
} ;
2010-01-15 07:38:56 +03:00
static struct ctdb_log_entry * log_entries ;
2009-11-18 04:44:18 +03:00
/*
* this function logs all messages for all levels to a ringbuffer
*/
static void log_ringbuffer_v ( const char * format , va_list ap )
{
int ret ;
2010-01-15 07:38:56 +03:00
if ( log_entries = = NULL & & log_ringbuf_size ! = 0 ) {
/* Hope this works. We cant log anything if it doesnt anyway */
log_entries = malloc ( sizeof ( struct ctdb_log_entry ) * log_ringbuf_size ) ;
}
if ( log_entries = = NULL ) {
return ;
}
2009-12-04 03:36:27 +03:00
log_entries [ last_entry ] . message [ 0 ] = ' \0 ' ;
2009-11-18 04:44:18 +03:00
2009-12-04 03:36:27 +03:00
ret = vsnprintf ( & log_entries [ last_entry ] . message [ 0 ] , MAX_LOG_SIZE , format , ap ) ;
2009-11-18 04:44:18 +03:00
if ( ret = = - 1 ) {
return ;
}
log_entries [ last_entry ] . level = this_log_level ;
log_entries [ last_entry ] . t = timeval_current ( ) ;
last_entry + + ;
2010-01-15 07:38:56 +03:00
if ( last_entry > = log_ringbuf_size ) {
2009-11-18 04:44:18 +03:00
last_entry = 0 ;
}
if ( first_entry = = last_entry ) {
first_entry + + ;
}
2010-01-15 07:38:56 +03:00
if ( first_entry > = log_ringbuf_size ) {
2009-11-18 04:44:18 +03:00
first_entry = 0 ;
}
}
void log_ringbuffer ( const char * format , . . . )
{
va_list ap ;
va_start ( ap , format ) ;
log_ringbuffer_v ( format , ap ) ;
va_end ( ap ) ;
}
static void ctdb_collect_log ( struct ctdb_context * ctdb , struct ctdb_get_log_addr * log_addr )
{
TDB_DATA data ;
2009-11-18 11:10:50 +03:00
FILE * f ;
long fsize ;
int tmp_entry ;
int count = 0 ;
DEBUG ( DEBUG_ERR , ( " Marshalling log entries first:%d last:%d \n " , first_entry , last_entry ) ) ;
/* dump to a file, then send the file as a blob */
f = tmpfile ( ) ;
if ( f = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Unable to open tmpfile - %s \n " , strerror ( errno ) ) ) ;
return ;
}
2009-11-18 04:44:18 +03:00
2009-11-18 11:10:50 +03:00
tmp_entry = first_entry ;
while ( tmp_entry ! = last_entry ) {
struct tm * tm ;
char tbuf [ 100 ] ;
2009-11-18 04:44:18 +03:00
2010-01-15 07:38:56 +03:00
if ( log_entries = = NULL ) {
break ;
}
2009-11-18 11:10:50 +03:00
if ( log_entries [ tmp_entry ] . level > log_addr - > level ) {
tmp_entry + + ;
2010-01-15 07:38:56 +03:00
if ( tmp_entry > = log_ringbuf_size ) {
2009-11-18 11:10:50 +03:00
tmp_entry = 0 ;
2009-11-18 04:44:18 +03:00
}
2009-11-18 11:10:50 +03:00
continue ;
2009-11-18 04:44:18 +03:00
}
2009-11-18 11:10:50 +03:00
tm = localtime ( & log_entries [ tmp_entry ] . t . tv_sec ) ;
strftime ( tbuf , sizeof ( tbuf ) - 1 , " %Y/%m/%d %H:%M:%S " , tm ) ;
2009-11-18 04:44:18 +03:00
2009-11-18 11:10:50 +03:00
if ( log_entries [ tmp_entry ] . message ) {
count + = fprintf ( f , " %s:%s %s " , tbuf , get_debug_by_level ( log_entries [ tmp_entry ] . level ) , log_entries [ tmp_entry ] . message ) ;
}
2009-11-18 04:44:18 +03:00
2009-11-18 11:10:50 +03:00
tmp_entry + + ;
2010-01-15 07:38:56 +03:00
if ( tmp_entry > = log_ringbuf_size ) {
2009-11-18 11:10:50 +03:00
tmp_entry = 0 ;
2009-11-18 04:44:18 +03:00
}
}
2009-11-18 11:10:50 +03:00
fsize = ftell ( f ) ;
rewind ( f ) ;
data . dptr = talloc_size ( NULL , fsize ) ;
CTDB_NO_MEMORY_VOID ( ctdb , data . dptr ) ;
data . dsize = fread ( data . dptr , 1 , fsize , f ) ;
fclose ( f ) ;
DEBUG ( DEBUG_ERR , ( " Marshalling log entries into a blob of %d bytes \n " , ( int ) data . dsize ) ) ;
2009-11-18 04:44:18 +03:00
2009-11-18 11:10:50 +03:00
DEBUG ( DEBUG_ERR , ( " Send log to %d:%d \n " , ( int ) log_addr - > pnn , ( int ) log_addr - > srvid ) ) ;
2010-06-02 03:45:21 +04:00
ctdb_client_send_message ( ctdb , log_addr - > pnn , log_addr - > srvid , data ) ;
2009-11-18 11:10:50 +03:00
talloc_free ( data . dptr ) ;
2009-11-18 04:44:18 +03:00
}
int32_t ctdb_control_get_log ( struct ctdb_context * ctdb , TDB_DATA addr )
{
struct ctdb_get_log_addr * log_addr = ( struct ctdb_get_log_addr * ) addr . dptr ;
pid_t child ;
/* spawn a child process to marshall the huge log blob and send it back
to the ctdb tool using a MESSAGE
*/
child = fork ( ) ;
if ( child = = ( pid_t ) - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to fork a log collector child \n " ) ) ;
return - 1 ;
}
if ( child = = 0 ) {
2010-07-19 13:59:09 +04:00
if ( switch_from_server_to_client ( ctdb , " log-collector " ) ! = 0 ) {
2009-11-18 04:44:18 +03:00
DEBUG ( DEBUG_CRIT , ( __location__ " ERROR: failed to switch log collector child into client mode. \n " ) ) ;
_exit ( 1 ) ;
}
ctdb_collect_log ( ctdb , log_addr ) ;
_exit ( 0 ) ;
}
return 0 ;
}
int32_t ctdb_control_clear_log ( struct ctdb_context * ctdb )
{
first_entry = 0 ;
last_entry = 0 ;
return 0 ;
}