Starts logger & conf

This commit is contained in:
Yann Weber 2019-07-02 06:54:27 +02:00
commit 0050577e45
3 changed files with 455 additions and 0 deletions

83
src/conf.h Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright (C) 2019 Weber Yann
*
* This file is part of PyFCGI.
*
* PyFCGI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PyFCGI 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PyFCGI. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONF_H___
#define __CONF_H___
#include "config.h"
/**@defgroup conf_internal PYFCGI configuration handling
*/
/**@defgroup conf_glob PYFCGI global (for all process) configurations
* @see struct_pyfcgi_conf_s
* @ingroup conf_internal */
/**@defgroup ret_status Function & process return status
*/
#define PYFCGI_ERR 16
/**@ingroup ret_status */
#define PYFCGI_WORKER_FAIL 32
/**@ingroup ret_status */
#define PYFCGI_MASTER_FAIL 64
/**@ingroup ret_status */
#define PYFCGI_FATAL 128
/**@brief Friendly name for @ref struct pyfcgi_conf_s
* @see struct pyfcgi_conf_s */
typedef struct pyfcgi_conf_s pyfcgi_conf_t;
typedef struct pyfcgi_conf_logger_s pyfcgi_conf_logger_t;
typedef struct pyfcgi_context_s pyfcgi_context_t;
struct pyfcgi_context_s {
int foo;
};
/**@brief Structure containing configuration
* @ingroup conf_internal
* The structure is used for the global @ref pyfcgi_conf variable.
* @see pyfcgi_conf_t
*/
struct pyfcgi_conf_s
{
/**@brief Entrypoint module name
* @ingroup conf_glob */
char *py_entrymod;
/**@brief Entrypoint function name
* @ingroup conf_glob */
char *py_entryfun;
/**@brief Minimum count worker in pool
* @ingroup conf_glob */
int min_wrk;
/**@brief Maximum count workers in pool
* @ingroup conf_glob */
int max_wrk;
/**@brief Maximum request before a worker restarts (0 for no restart)
* @ingroup conf_glob */
int max_reqs;
/**@brief Logger configuration
* @ingroupe conf_glob */
pyfcgi_conf_logger_t logs;
pyfcgi_context_t context;
};
/**@brief Configuration globals, inherited from parent to childs */
pyfcgi_conf_t PyFCGI_conf;
#endif

204
src/logger.c Normal file
View file

@ -0,0 +1,204 @@
#include "logger.h"
int pyfcgi_logger_add(const char *filename, logmask_t loglvl, logmask_t logtyp,
const char *format)
{
pyfcgi_conf_logger_t *conf;
pyfcgi_logger_t logger;
size_t new_idx;
void *tmp;
int err;
char *err_fmt;
conf = &PyFCGI_conf.logs;
if(conf->logger_sz == 255)
{
pyfcgi_log(LOG_ERR, "Maximum of 255 logger reached, unable to add this one...");
return PYFCGI_ERR;
}
if(pyfcgi_logger_add_format(format, &(logger.fmt_id)))
{
return PYFCGI_FATAL;
}
if(!logger.filename)
{
err_fmt = "Unable to duplicate logger filename : %s";
goto err;
}
logger.loglvl = loglvl;
logger.logtyp = logtyp;
logger.filename = strdup(filename);
new_idx = conf->logger_sz;
conf->logger_sz++;
if( !(tmp = realloc(conf->loggers,
sizeof(pyfcgi_logger_t) * conf->logger_sz)) )
{
err = errno;
err_fmt = "Unable to realloc loggers array : %s";
goto err_free_filename;
}
conf->loggers[new_idx] = logger;
return 0;
err_free_filename:
free(logger.filename);
err:
pyfcgi_log(LOG_ALERT,
err_fmt,
strerror(err));
return PYFCGI_FATAL;
}
int pyfcgi_logger_add_format(const char* format, size_t* idx)
{
char *fmt;
size_t i;
void *tmp;
pyfcgi_conf_logger_t *conf;
conf = &PyFCGI_conf.logs;
for(i=0; i<conf->format_sz; i++)
{
if(!strcmp(format, conf->format[i])) { break; }
}
if(idx) { *idx = i; }
if( i<conf->format_sz )
{
return 0;
}
if( !(fmt = strdup(format)) )
{
pyfcgi_log(LOG_ALERT, "Fails to strdup new format : %s",
strerror(errno));
return PYFCGI_FATAL;
}
conf->format_sz++;
if( !(tmp = realloc(conf->format,
sizeof(char*) * conf->format_sz)) )
{
conf->format_sz--;
pyfcgi_log(LOG_ALERT, "Fails to realloc logger format array : %s",
strerror(errno));
return PYFCGI_FATAL;
}
conf->format[i] = fmt;
return 0;
}
int pyfcgi_logger_open(pyfcgi_logger_t *logger)
{
if( (logger->fd = open(logger->filename,
O_WRONLY | O_APPEND | O_CREAT, 00640) < 0) )
{
pyfcgi_log(LOG_ERR,
"Unable to open log file '%s' : %s",
strerror(errno));
return PYFCGI_ERR;
}
return 0;
}
int pyfcgi_log(loglvl_t lvl, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vpyfcgi_log(lvl, fmt, ap);
va_end(ap);
return ret;
}
int vpyfcgi_log(loglvl_t lvl, const char *fmt, va_list ap)
{
int len, ret;
pyfcgi_conf_logger_t *conf;
unsigned char i;
char buf[512];
conf = &PyFCGI_conf.logs;
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
vsyslog(SYSLOG_LVLS[(lvl & 0xF0) >> 4], fmt, ap);
}
len = 0;
if(conf->format_sz > 1)
{
len = vdprintf(conf->pipes[1], fmt, ap);
if(len < 0)
{
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
syslog(SYSLOG_ALERT,
"Unable to write to multiplexer pipe when trying to log : %s",
strerror(errno));
}
return PYFCGI_FATAL;
}
}
else if (conf->format_sz)
{
len = vdprintf(conf->loggers[0].fd, fmt, ap);
if(len < 0)
{
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
syslog(SYSLOG_ALERT,
"Unable to write to single FD to '%s' when trying to log : %s",
conf->loggers[0].filename, strerror(errno));
}
return PYFCGI_FATAL;
}
return 0;
}
for(i=0; i<conf->logger_sz-1; i++)
{
ret = tee(conf->pipes[0], conf->loggers[i].fd, len, 0);
if(ret < 0)
{
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
syslog(SYSLOG_ALERT,
"Unable to splice to last logfile '%s' : %s",
conf->loggers[i].filename, strerror(errno));
}
return PYFCGI_FATAL;
}
}
ret = splice(conf->pipes[0], NULL, conf->loggers[i].fd, NULL, len, 0);
if(ret < 0)
{
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
syslog(SYSLOG_ALERT,
"Unable to splice to last logfile '%s' : %s",
conf->loggers[i].filename, strerror(errno));
}
return PYFCGI_ERR;
}
if(ret < len)
{
if(conf->flags & PYFCGI_LOG_FSYSLOG)
{
syslog(SYSLOG_WARNING,
"Unable to splice all data to logfile. Flushing pipe.");
}
do
{
len -= (ret<len)?ret:len;
ret = read(conf->pipes[0], buf, len>512?512:len);
if(ret < 0)
{
return PYFCGI_ERR;
}
}while(len);
}
return 0;
}

168
src/logger.h Normal file
View file

@ -0,0 +1,168 @@
/*
* Copyright (C) 2019 Weber Yann
*
* This file is part of PyFCGI.
*
* PyFCGI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PyFCGI 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with PyFCGI. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LOGGER_H___
#define __LOGGER_H___
#include "config.h"
#include <syslog.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
/**@defgroup conf_logger Logging configuration
* @ingroup conf_internal
*/
/**@defgroup log_facility Logger custom facilities */
/**@ingroup log_facility */
#define LOG_GLOBAL 0
/**@ingroup log_facility */
#define LOG_ACCESS 1
/**@ingroup log_facility */
#define LOG_INTERN 2
/**@ingroup log_facility */
#define LOG_WORKER 4
/**@ingroup log_facility */
#define LOG_MASTER 8
#define SYSLOG_EMERG LOG_EMERG
#define SYSLOG_ALERT LOG_ALERT
#define SYSLOG_CRIT LOG_CRIT
#define SYSLOG_ERR LOG_ERR
#define SYSLOG_WARNING LOG_WARNING
#define SYSLOG_NOTICE LOG_NOTICE
#define SYSLOG_INFO LOG_INFO
#define SYSLOG_DEBUG LOG_DEBUG
const short SYSLOG_LVLS[8] = {LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG};
#undef LOG_EMERG
#undef LOG_ALERT
#undef LOG_CRIT
#undef LOG_ERR
#undef LOG_WARNING
#undef LOG_NOTICE
#undef LOG_INFO
#undef LOG_DEBUG
/* This way we can mimic syslog and the or'ed level | facility */
//#define LOG_EMERG (1 << 4)
#define LOG_EMERG (2 << 4)
#define LOG_ALERT (2 << 4)
#define LOG_CRIT (3 << 4)
#define LOG_ERR (4 << 4)
#define LOG_WARNING (5 << 4)
#define LOG_NOTICE (6 << 4)
#define LOG_INFO (7 << 4)
#define LOG_DEBUG (8 << 4)
/**@defgroup conf_logger_flags Logger confifurations flags
* @ingroup conf_logger */
/**@ingroup cong_logger_flags */
#define PYFCGI_LOG_FSYSLOG 1
/**@brief Indicate if the logger should try to reopen on failure
* @ingroup cong_logger_flags */
#define PYFCGI_LOG_FRETRY 2
/**@brief Exit if failure
* @ingroup cong_logger_flags */
#define PYFCG_LOG_FEXIT_ONFAIL 4
/**@brief Log level mask
* @ingroup conf_logger
* Allow selection of loglevels using a bitwise mask 1 << LEVEL
*/
typedef unsigned char logmask_t;
typedef unsigned char loglvl_t;
typedef struct pyfcgi_logger_s pyfcgi_logger_t;
/**@brief Logger configuration
* @ingroup conf_logger
*/
struct pyfcgi_conf_logger_s
{
/**@brief Or combination of @ref PYFCGI_LOG_SYSLOG or
* @ref PYFCGI_LOG_RETRY */
short flags;
char *syslog_ident;
int syslog_facility;
logmask_t syslog_loglvl;
logmask_t syslog_logtyp;
/**@brief PyFCGI internal ident, prefixes all log messages */
char *ident;
logmask_t facility;
pyfcgi_logger_t *loggers;
unsigned char logger_sz;
char **format;
unsigned char format_sz;
/**@brief Internal pipe to tee(2) the message on loggers */
int pipes[2];
};
/**@brief Informations on a logger
* @ingroup conf_logger
*/
struct pyfcgi_logger_s
{
char *filename;
int fd;
logmask_t loglvl;
logmask_t logtyp;
size_t fmt_id;
};
#include "conf.h"
/**@brief Add a new logger
* @param char* filename
* @param logmask_t loglvl a mask indicating wich loglevels should be logged
* @param logmask_t typemask a mask indicating wich facility should be logged
* @param char* log format (or NULL for default format)
*/
int pyfcgi_logger_add(const char*, logmask_t, logmask_t, const char*);
/**@brief Add a new format
* @param char *format
* @param size_t* idx if not NULL, will contain the format index
* @return 0 if OK
*/
int pyfcgi_logger_add_format(const char*, size_t*);
/**@brief Open a logger
* @param pyfcgi_logger_t*
* @return 0 if no errors
*/
int pyfcgi_logger_open(pyfcgi_logger_t*);
int pyfcgi_logger_set_ident(const char*);
int pyfcgi_log(loglvl_t, const char*, ...);
int vpyfcgi_log(loglvl_t, const char*, va_list);
#endif