123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- /*
- * 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 <time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- /**@file logger.h
- * @brief PyFCGI logging facility
- * @ingroup conf_logger
- */
- /**@defgroup conf_logger Logging configuration
- * @ingroup conf_internal
- * @ingroup logging
- */
-
- /**@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 PYFCGI_LOGGER_MAX 64
- #define PYFCGI_LOGGER_FMT_MAX PYFCGI_LOGGER_MAX
- #define PYFCGI_LOGGER_FIELD_MAX 24
- #define PYFCGI_LOGGER_FMT_PARSE_ERRSZ 64
- /**@brief The size of the @ref struct pyfcgi_logger_format_t.buf allocated to
- * the message field */
- #define PYFCGI_LOGGER_MSG_BUF_SZ 64
-
- #define PYFCGI_LOG_DTM_LEN 25
- #define PYFCGI_LOG_LVL_LEN 7
- #define PYFCGI_LOG_TYP_LEN 7
- #define PYFCGI_LOG_PID_LEN 6
- #define PYFCGI_LOG_PID_FMT "%6d"
-
- #define SYSLOG_syslog syslog
- #define SYSLOG_vsyslog vsyslog
- #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
-
- #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)
-
- /**@brief Convert a PyFCGI loglevel in a syslog one */
- #define PYFCGI_SYSLOG_LVL(lvl) (((lvl & 0xF0) >> 4)-1)
-
- /**@brief Macro checking if syslog is activated and log a message
- * @params int lvl the PyFCGI log level
- * @param char* fmt the message format
- * @see _vsyslog syslog
- */
- #define _syslog(lvl, ...) if(conf->flags & PYFCGI_LOG_FSYSLOG) { \
- syslog(PYFCGI_SYSLOG_LVL(lvl), __VA_ARGS__);\
- }
- #define _vsyslog(lvl, fmt, ap) if(conf->flags & PYFCGI_LOG_FSYSLOG) { \
- vsyslog(PYFCGI_SYSLOG_LVL(lvl), fmt, ap);\
- }
-
- /**@brief Macro checking if syslog is activated and log a message using PyFCGI
- * loglevels
- * @params int lvl the PyFCGI log level
- * @param char* fmt the message format
- * @see vsyslog _syslog
- */
-
-
- /**@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
- * @warn not implemented
- * @ingroup cong_logger_flags */
- #define PYFCGI_LOG_FRETRY 2
- /**@brief Exit if failure
- * @warn not implemented
- * @ingroup cong_logger_flags */
- #define PYFCGI_LOG_FEXIT_ONFAIL 4
-
- #define PYFCGI_LOGGER_FMT_DEFAULT "{datetime} {ident}[{pid}] {level} {msg}"
- #define PYFCGI_LOGGER_TIME_FMT_DEFAULT "%F %T%z"
- #define PYFCGI_SYSLOG_IDENT_FMT "pyfcgi(%d)[%s]"
- #define PYFCGI_SYSLOG_IDENT_FMT_SHORT "pyfcgi(%d)"
-
-
- /**@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;
- typedef struct pyfcgi_logger_format_s pyfcgi_logger_format_t;
- typedef struct pyfcgi_logger_fmt_field_s pyfcgi_logger_fmt_field_t;
- typedef union pyfcgi_logger_fmt_field_u pyfcgi_logger_fmt_value_t;
- typedef enum pyfcgi_logger_field_type pyfcgi_logger_field_type_e;
- typedef struct strftime_args_s strftime_args_t;
- typedef struct ident_args_s ident_args_t;
- typedef union pyfcgi_logger_field_args pyfcgi_logger_field_args_u;
-
-
- static const char* PYFCGI_LOGGER_LVLNAME[] __attribute__((unused)) = {
- " Emerge",
- " Alert",
- " Critic",
- " Error",
- "Warning",
- " Notice",
- " Info",
- " Debug"};
-
- static const char* PYFCGI_LOGGER_TYPNAME[] __attribute__((unused)) =
- {"Global", "Access", "Internal", "Worker", "Master"} ;
-
-
- /**@defgroup conf_logger_format Logline format
- * @ingroup conf_logger
- * A small description langage allows to describe wanted logline format.
- * A format is a string with special markup indicating fields. Fields markup
- * are surrounded by '{' and '}' chr. This markup can be divided in multiple
- * subfields separated by ':' chr, but the first field is always the field
- * name.
- *
- * Valid fields are :
- * - {datetime:SIZE:FMT} defines a format and a constant length for date
- * string. By default %F %T%z ISO 8601 date format + time + tz
- * see @ref PYFCGI_LOGGER_TIME_FMT_DEFAULT
- * - {level} the loglevel (with a constant length of 7)
- * - {facility} the log facility (constant length od 6)
- * - {pid:SIZE} PID with a constant length for pid field
- * - {ident} the defined ident (size is processed when set)
- * - {msg} the log message (can only appears once)
- *
- * @note You can escape '{' and '}' by using '{{' and '}}'
- * @note There is a maximum of 24 fields by format (see
- * @note All fields can be abbreviate to one character
- * @ref PYFCGI_LOGGER_FIELD_MAX )
- */
-
- struct strftime_args_s
- {
- //char **s; // field.buf_ptr
- //size_t max; // field.len
- char *format;
- //const struct tm *tm; // fecthed each time
- };
-
- struct ident_args_s
- {
- size_t len;
- };
-
- union pyfcgi_logger_field_args
- {
- strftime_args_t datetime;
- ident_args_t ident;
- };
-
- /**@brief Logger format field's type
- * @ingroup conf_logger_format */
- enum pyfcgi_logger_field_type
- {
- pyfcgi_logger_field_null = 0,
- pyfcgi_logger_field_const = -1,
- pyfcgi_logger_field_datetime = 1,
- pyfcgi_logger_field_level = 2,
- pyfcgi_logger_field_facility = 3,
- pyfcgi_logger_field_pid = 4,
- pyfcgi_logger_field_ppid = 5,
- pyfcgi_logger_field_ident = 6,
- pyfcgi_logger_field_msg = 7,
- };
-
- /**@brief Logger format field data
- * @ingroup conf_logger_format */
- struct pyfcgi_logger_fmt_field_s
- {
- pyfcgi_logger_field_type_e type;
-
- short known_length;
- size_t len;
-
- /** @brief pointer on value (interpreted given field type) */
- void *val;
- pyfcgi_logger_field_args_u args;
- /**@brief Points in prefix or sufix buffer */
- char *buf_ptr;
- /**@brief Field offset in msg buffer (prefix or sufix) */
- size_t buf_off;
- /**@brief 1 if in suffix else 0 */
- short suff;
- };
-
- /**@brief Logger format data
- * @ingroup conf_logger_format */
- struct pyfcgi_logger_format_s
- {
- /**@brief String copy of the format */
- char *fmt;
- /**@brief Stores data about fields */
- pyfcgi_logger_fmt_field_t fields[PYFCGI_LOGGER_FIELD_MAX];
- /**@brief field count */
- int nfield;
- /**@brief Preallocated buffer for prefix & suffix */
- char *buf;
- size_t buflen[2];
- /**@brief Message prefix */
- char *prefix;
- /**@brief Message suffix */
- char *suffix;
-
- char *_msg;
- size_t _msglen;
- };
-
- /**@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;
- };
-
- /**@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[PYFCGI_LOGGER_MAX];
- unsigned char logger_sz;
-
- pyfcgi_logger_format_t formats[PYFCGI_LOGGER_MAX];
- //char **format;
- unsigned char format_sz;
-
- /**@brief Buffer for message field formating */
- char *msg_buf;
- size_t msg_buf_sz;
-
- /**@brief Internal pipe to tee(2) the message on loggers (USELESS)*/
- int pipes[2];
- };
- #include "conf.h"
-
- /**@brief Initiliaze logger conf */
- int pyfcgi_logger_init();
-
- /**@brief Stop & free the logger
- * @note also free formats
- */
- int pyfcgi_logger_stop();
-
- /**@brief Enable syslog logging with given ident
- * @param char* ident if NULL use current ident
- */
- void pyfcgi_logger_enable_syslog(const char*);
-
- /**@brief Stop & free an individual logger */
- void _pyfcgi_logger_free(pyfcgi_logger_t*);
-
- /**@brief Add a new logger
- * @param char* filename or NULL if stderr (fd 2 ) wanted
- * @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_format_add(const char*, size_t*);
-
- /**@brief Parse a format string and populate corresponding
- * @ref struct pyfgci_logger_format_s
- * @param const char* fmt string
- * @param pyfcgi_logger_format_t* fmt_data
- * @return 0 if no errors
- */
- int pyfcgi_logger_parse_format(const char*, pyfcgi_logger_format_t*);
-
- /**@brief Initialize a pyfcgi_logger_format_t.buf attribute (to init the
- * prefix & sufix attributes.
- * @note have to be called when ident is updated
- * @param pyfcgi_logger_format_t* fmt
- * @note called by @ref pyfcgi_logger_add_format but should be called
- * by @ref pyfcgi_logger_parse_format
- */
- int pyfcgi_logger_format_bufinit(pyfcgi_logger_format_t*);
-
- /**@brief Parse a field string and populate corresponding
- * @ret struct pyfcgi_logger_field_s
- * @param const char ** ptr on current format pointer
- * @param char * if not NULL and parse error occurs, this string
- * will be set
- * @return 0 if no errors and 1 if parse error
- */
- int pyfcgi_logger_parse_field(const char**, const char *,
- pyfcgi_logger_fmt_field_t*,
- char[PYFCGI_LOGGER_FMT_PARSE_ERRSZ]);
-
- /**@brief Free allocated memory in given field
- * @param pyfcgi_logger_fmt_field_t* field to free
- */
- void pyfcgi_logger_field_free(pyfcgi_logger_fmt_field_t*);
-
- /**@brief Given a field pointer return the size option incrementing
- * ptr
- * @warning do not check if the next character is OK, the caller has to
- * do it
- * @param char** pointer on format
- * @param size_t* size if found will be set to size option. if not found set to
- * 0
- * @return 0 if no error
- */
- int pyfcgi_logger_parse_field_sz(const char**, size_t*);
-
- /**@brief Alloc memory by parsing & strdup the strftime format found
- * in field. If not found use default format
- * @note set the @ref struct pyfcgi_logger_fmt_field_s.args field
- * @param const char** ptr
- * @param char** format
- * @return
- */
- int pyfcgi_logger_parse_field_dtfmt(const char**, char**);
-
- /**@brief Return a str repr of given loglevel
- * @warning returned pointer must NOT be freed or modified
- * @return The loglevel name or NULL if error
- */
- const char* pyfcgi_logger_value_level(short);
- const char* pyfcgi_logger_value_facility(short);
-
- /**@brief Open a logger
- * @param pyfcgi_logger_t
- * @return 0 if no errors
- */
- int pyfcgi_logger_open(pyfcgi_logger_t*);
-
- /**@brief Set programm identity for logger
- * @note ident is global to a process
- * @note this function triggers the refresh of the loggers internal
- * buffers if needed (see @ref pyfcgi_logger_format_bufinit() )
- * @param const char* new_ident
- * @return 0 if no error
- */
- int pyfcgi_logger_set_ident(const char*);
-
- /**@brief Format a message using a @ref struct pyfcgi_logger_format_s
- * @note alloc and write the logline in the attribute _msg
- * @param pyfcgi_logger_format_t the pyfcgi logger format structure
- * @param loglvl_t the loglevel (see @ref pyfcgi_log() )
- * @param char* message the message sent by user
- * @param size_t len the message len
- * @return NULL if error
- */
- char* vpyfcgi_logger_format_message(pyfcgi_logger_format_t *fmt,
- loglvl_t lvl, const char* message, size_t len);
-
- int pyfcgi_log(loglvl_t, const char*, ...);
- int vpyfcgi_log(loglvl_t, const char*, va_list);
-
- #endif
|