// Abstract logging system used to facilitate multiple modes
// of logging
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <syslog.h>
#endif
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include "logger.h"
#ifndef WIN32
static int _LOGGER_mode = _LOGGER_SYSLOG;
static int _LOGGER_syslog_mode = LOG_MAIL|LOG_INFO;
#else
static int _LOGGER_mode = _LOGGER_STDERR;
static int _LOGGER_syslog_mode = 0;
#endif
static FILE *_LOGGER_outf;
struct LOGGER_globals {
int wrap;
int wraplength;
};
// Create and Initialise the global structure for LOGGER,
// we init it to have NO wrapping.
static struct LOGGER_globals LOGGER_glb={ 0, 0 };
/*------------------------------------------------------------------------
Procedure: LOGGER_get_file ID:1
Purpose: Returns the pointer to the file being used to output logs to
Input:
Output:
Errors:
------------------------------------------------------------------------*/
FILE *LOGGER_get_file( void )
{
return _LOGGER_outf;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_output_mode ID:1
Purpose: Sets the message/log output method, ie, stderr, stdout
or syslog
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_output_mode( int modechoice )
{
_LOGGER_mode = modechoice;
return 0;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_output_file ID:1
Purpose: Sets the output file for when _LOGGER_mode is set to
_LOGGER_file
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_output_file( FILE *f )
{
_LOGGER_outf = f;
return 0;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_syslog_mode ID:1
Purpose: Sets the mode that messaging to the syslog daemon will
be sent as (ie, LOG_MAIL|LOG_INFO)
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_syslog_mode( int syslogmode )
{
_LOGGER_syslog_mode = syslogmode;
return 0;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_logfile ID:1
Purpose: Opens and setups the internal Log file file pointer with the
log file as given by lfname
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_logfile( char *lfname )
{
int result = 0;
_LOGGER_outf = fopen(lfname,"a");
if (!_LOGGER_outf)
{
#ifndef WIN32
syslog(1,"LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)",lfname,strerror(errno));
#else
fprintf(stderr, "LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)\n", lfname, strerror(errno));
#endif
result = -1;
}
return result;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_wraplength ID:1
Purpose: Sets the character count at which LOGGER will break a line
Input: int length: Positive integer indicating number of chracters at which to wrap at
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_wraplength( int length )
{
if ( length >= 0 )
{
LOGGER_glb.wraplength = length;
}
return LOGGER_glb.wraplength;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_set_wrap ID:1
Purpose: Set log output wrapping to on or off
Input: int level: 0 = no wrap, > 0 = wrap.
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_set_wrap( int level )
{
if ( level >= 0 )
{
LOGGER_glb.wrap = level;
}
return LOGGER_glb.wrap;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_close_logfile ID:1
Purpose: Closes the modules log file pointer.
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_close_logfile( void )
{
int result = 0;
if (_LOGGER_outf) fclose(_LOGGER_outf);
return result;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_clean_output ID:1
Purpose: Checks through the output string for any characters which could cause
potential 'isssues' with the data writing calls, items such as stray non-escaped
% characters can cause havoc.
Input: char *string: Raw string
int maxsize: Maximum available buffer size for this string to expand to
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_clean_output( char *string, char **buffer )
{
char *newstr;
char *p, *q;
char *next_space;
int pc;
int slen = strlen( string );
int line_size;
int maxsize = slen *2;
// First up, allocate maxsize bytes for a temporary new string.
newstr = malloc(slen *2 +1);
if ( newstr == NULL )
{
// FIXME - Report an error here ... to -somewhere-
return -1;
}
p = newstr;
q = string;
pc = 0;
line_size = 0;
while (slen--)
{
// Do we need to apply any wrapping to the output? If so then we
// shall embark on a journey of strange space and distance
// evaluations to determine if we should wrap now or later
if ( LOGGER_glb.wrap > 0 )
{
if (isspace((int)*q))
{
next_space = strpbrk( (q+1), "\t\r\n\v " );
if (next_space != NULL)
{
if ((line_size +(next_space -q)) >= LOGGER_glb.wraplength)
{
*p = '\n';
p++;
pc++;
line_size = 0;
}
}
}
if ( line_size >= LOGGER_glb.wraplength )
{
*p = '\n';
p++;
pc++;
line_size = 0;
}
}
// If the string has a % in it, then we need to encode it as
// a DOUBLE % symbol.
if (*q == '%') {
// if (strchr("fdlsxXn",*(q+1)))
// {
*p = '%';
p++;
pc++;
// }
}
// Copy the character of the string in
*p = *q;
// Move everything along.
q++;
p++;
pc++;
line_size++;
if ( pc > (maxsize -1) ) {
break;
}
}
*p = '\0';
// This will have to be deallocated later!
if (newstr) *buffer = newstr;
return 0;
}
/*------------------------------------------------------------------------
Procedure: LOGGER_log ID:1
Purpose: Logs the params as supplied to the required
output as defined by LOGGER_set_output
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int LOGGER_log( char *format, ...)
{
va_list ptr;
char tmpoutput[10240];
char linebreak[]="\n";
char nolinebreak[]="";
char *lineend;
char *output;
// get our variable arguments
va_start(ptr,format);
// produce output, and spit to the log file
#ifdef NO_SNPRINTF
vsprintf(tmpoutput, format, ptr);
#else
vsnprintf(tmpoutput,10240,format,ptr);
#endif
LOGGER_clean_output( tmpoutput, &output );
if ( output[strlen(output)-1] == '\n' ) {
lineend = nolinebreak;
}
else {
lineend = linebreak;
}
if ( output[strlen(output)-1] == '\n' ) { lineend = nolinebreak; } else { lineend = linebreak; }
// Send the output to the appropriate output destination
switch (_LOGGER_mode) {
case _LOGGER_STDERR:
fprintf(stderr,"%s%s",output, lineend );
break;
case _LOGGER_SYSLOG:
syslog(_LOGGER_syslog_mode,output);
break;
case _LOGGER_STDOUT:
fprintf(stdout,"%s%s",output, lineend);
fflush(stdout);
break;
case _LOGGER_FILE:
fprintf(_LOGGER_outf,"%s%s",output,lineend);
fflush(_LOGGER_outf);
break;
default:
fprintf(stdout,"LOGGER-Default: %s%s",output,lineend);
}
if (output) free(output);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1