Starts logger & conf
This commit is contained in:
parent
5e80043631
commit
0050577e45
3 changed files with 455 additions and 0 deletions
83
src/conf.h
Normal file
83
src/conf.h
Normal 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
204
src/logger.c
Normal 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
168
src/logger.h
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue