mirror of
https://gitlab.xiph.org/xiph/icecast-common.git
synced 2024-12-04 14:46:31 -05:00
Merge branch 'feature-errorlog' into libigloo
This commit is contained in:
commit
38eff2ae99
@ -25,11 +25,13 @@ pkginclude_HEADERS = \
|
|||||||
include/igloo/stdio.h \
|
include/igloo/stdio.h \
|
||||||
include/igloo/filter.h \
|
include/igloo/filter.h \
|
||||||
include/igloo/objecthandler.h \
|
include/igloo/objecthandler.h \
|
||||||
|
include/igloo/logmsg.h \
|
||||||
include/igloo/buffer.h \
|
include/igloo/buffer.h \
|
||||||
include/igloo/list.h \
|
include/igloo/list.h \
|
||||||
include/igloo/reportxml.h
|
include/igloo/reportxml.h
|
||||||
|
|
||||||
libigloo_la_SOURCES = \
|
libigloo_la_SOURCES = \
|
||||||
|
src/private.c \
|
||||||
src/libigloo.c \
|
src/libigloo.c \
|
||||||
src/interface.c \
|
src/interface.c \
|
||||||
src/ro.c \
|
src/ro.c \
|
||||||
@ -37,6 +39,7 @@ libigloo_la_SOURCES = \
|
|||||||
src/stdio.c \
|
src/stdio.c \
|
||||||
src/filter.c \
|
src/filter.c \
|
||||||
src/objecthandler.c \
|
src/objecthandler.c \
|
||||||
|
src/logmsg.c \
|
||||||
src/buffer.c \
|
src/buffer.c \
|
||||||
src/list.c \
|
src/list.c \
|
||||||
src/reportxml.c
|
src/reportxml.c
|
||||||
|
@ -82,7 +82,7 @@ typedef unsigned long int igloo_io_opflag_t;
|
|||||||
/* Operate on metadata. */
|
/* Operate on metadata. */
|
||||||
#define igloo_IO_OPFLAG_METADATA ((igloo_io_opflag_t)0x0002)
|
#define igloo_IO_OPFLAG_METADATA ((igloo_io_opflag_t)0x0002)
|
||||||
/* Operate on data and metadata. */
|
/* Operate on data and metadata. */
|
||||||
#define igloo_IO_OPFLAG_FULL (igloo_IO_OPFLAG_DATAONLY|igloo_IO_OPFLAG_METADATAONLY)
|
#define igloo_IO_OPFLAG_FULL (igloo_IO_OPFLAG_DATA|igloo_IO_OPFLAG_METADATA)
|
||||||
/* Instructs the operation that it should ignore the output state of the object.
|
/* Instructs the operation that it should ignore the output state of the object.
|
||||||
* This may improve performance as buffer flushes may be skipped.
|
* This may improve performance as buffer flushes may be skipped.
|
||||||
* However with this set any external software interacting with this object
|
* However with this set any external software interacting with this object
|
||||||
|
194
include/igloo/logmsg.h
Normal file
194
include/igloo/logmsg.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* Copyright (C) 2019 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBIGLOO__LOGMSG_H_
|
||||||
|
#define _LIBIGLOO__LOGMSG_H_
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Put a good description of this file here
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <igloo/config.h>
|
||||||
|
|
||||||
|
#ifdef IGLOO_CTC_HAVE_STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <igloo/config.h>
|
||||||
|
#include "ro.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/* About thread safety:
|
||||||
|
* This set of functions is thread safe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
igloo_RO_FORWARD_TYPE(igloo_logmsg_t);
|
||||||
|
|
||||||
|
/* Log level for log messages */
|
||||||
|
typedef enum {
|
||||||
|
/* Used to report errors with function calls. */
|
||||||
|
igloo_LOGLEVEL__ERROR = -1,
|
||||||
|
/* Unset log level. */
|
||||||
|
igloo_LOGLEVEL__NONE = 0,
|
||||||
|
/* Logmsg reports an error. */
|
||||||
|
igloo_LOGLEVEL_ERROR,
|
||||||
|
/* Logmsg reports a warning. */
|
||||||
|
igloo_LOGLEVEL_WARN,
|
||||||
|
/* Logmsg is of information level. */
|
||||||
|
igloo_LOGLEVEL_INFO,
|
||||||
|
/* Logmsg is for debugging only. */
|
||||||
|
igloo_LOGLEVEL_DEBUG
|
||||||
|
} igloo_loglevel_t;
|
||||||
|
|
||||||
|
/* Type for logmsg options.
|
||||||
|
*/
|
||||||
|
#ifdef IGLOO_CTC_HAVE_STDINT_H
|
||||||
|
typedef uint_least32_t igloo_logmsg_opt_t;
|
||||||
|
#else
|
||||||
|
typedef unsigned long int igloo_logmsg_opt_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* No options set. */
|
||||||
|
#define igloo_LOGMSG_OPT_NONE ((igloo_logmsg_opt_t)0x000)
|
||||||
|
/* Logmsg is only useful for developing the software itself. */
|
||||||
|
#define igloo_LOGMSG_OPT_DEVEL ((igloo_logmsg_opt_t)0x001)
|
||||||
|
/* Logmsg should be acknowledged by the user. */
|
||||||
|
#define igloo_LOGMSG_OPT_ASKACK ((igloo_logmsg_opt_t)0x002)
|
||||||
|
|
||||||
|
/* This creates a new log message.
|
||||||
|
* Parameters:
|
||||||
|
* name, associated
|
||||||
|
* See refobject_new().
|
||||||
|
* msgid
|
||||||
|
* Message ID used to correlate messages of the same type.
|
||||||
|
* Used e.g. with igloo_LOGMSG_OPT_ASKACK.
|
||||||
|
* Must be globally unique. Could be URI (e.g. UUID based URN)
|
||||||
|
* or message@domain.
|
||||||
|
* cat
|
||||||
|
* Message category/module.
|
||||||
|
* func
|
||||||
|
* Function generating the log message.
|
||||||
|
* codefile
|
||||||
|
* Code file generating the message.
|
||||||
|
* codeline
|
||||||
|
* Code line generating the message.
|
||||||
|
* ts
|
||||||
|
* Timestamp of the message. If NULL a timestamp is generated.
|
||||||
|
* level
|
||||||
|
* Loglevel of the message.
|
||||||
|
* options
|
||||||
|
* Message and delivery options.
|
||||||
|
* referenced
|
||||||
|
* List of objects relevant to the context generating the message.
|
||||||
|
* format
|
||||||
|
* Format string for the log message.
|
||||||
|
* ...
|
||||||
|
* Parameters according to the format string.
|
||||||
|
*/
|
||||||
|
igloo_logmsg_t * igloo_logmsg_new(const char *name, igloo_ro_t associated, const char *msgid, const char *cat, const char *func, const char *codefile, const ssize_t codeline, const struct timespec * ts, igloo_loglevel_t level, igloo_logmsg_opt_t options, igloo_list_t *referenced, const char *format, ...);
|
||||||
|
|
||||||
|
/* Get the context from a log message object.
|
||||||
|
*
|
||||||
|
* Any parameter but the msg parameter can be NULL if the caller is not interested in the specific value.
|
||||||
|
* In that case the value is not returned.
|
||||||
|
*
|
||||||
|
* Note: Strings are returned as pointers to internal memory. Those pointers become invalide
|
||||||
|
* once the caller releases it's reference to the message.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* msg
|
||||||
|
* The log message to operate on.
|
||||||
|
* msgid, cat, func, codefile, codeline, ts
|
||||||
|
* Pointers to where the context should be stored.
|
||||||
|
*/
|
||||||
|
int igloo_logmsg_get_context(igloo_logmsg_t *msg, const char **msgid, const char **cat, const char **func, const char **codefile, ssize_t *codeline, struct timespec *ts);
|
||||||
|
|
||||||
|
/* Get the message from a log message object.
|
||||||
|
*
|
||||||
|
* Any parameter but the msg parameter can be NULL if the caller is not interested in the specific value.
|
||||||
|
* In that case the value is not returned.
|
||||||
|
*
|
||||||
|
* Note: Strings are returned as pointers to internal memory. Those pointers become invalide
|
||||||
|
* once the caller releases it's reference to the message.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* msg
|
||||||
|
* The log message to operate on.
|
||||||
|
* level, string
|
||||||
|
* Pointers to where the message should be stored.
|
||||||
|
*/
|
||||||
|
int igloo_logmsg_get_message(igloo_logmsg_t *msg, igloo_loglevel_t *level, const char **string);
|
||||||
|
|
||||||
|
/* Get extra information from a log message object.
|
||||||
|
*
|
||||||
|
* Any parameter but the msg parameter can be NULL if the caller is not interested in the specific value.
|
||||||
|
* In that case the value is not returned.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* msg
|
||||||
|
* The log message to operate on.
|
||||||
|
* options
|
||||||
|
* Options set on the message.
|
||||||
|
* referenced
|
||||||
|
* A list of referenced objects. A new reference to that list is returned.
|
||||||
|
*/
|
||||||
|
int igloo_logmsg_get_extra(igloo_logmsg_t *msg, igloo_logmsg_opt_t *options, igloo_list_t **referenced);
|
||||||
|
|
||||||
|
/* This creates a formater that allows writing of log messages to a logfile.
|
||||||
|
* Parameters:
|
||||||
|
* backend
|
||||||
|
* The backend to write data to. Must be a igloo_io_t handle.
|
||||||
|
* subformat
|
||||||
|
* Subformat to use. NULL for default.
|
||||||
|
* Must be NULL.
|
||||||
|
* name, associated
|
||||||
|
* See refobject_new().
|
||||||
|
*/
|
||||||
|
igloo_objecthandler_t * igloo_logmsg_formarter(igloo_ro_t backend, const char *subformat, const char *name, igloo_ro_t associated);
|
||||||
|
|
||||||
|
/* This creates a filter for log messages.
|
||||||
|
* Parameters:
|
||||||
|
* level_min
|
||||||
|
* Minimum log level.
|
||||||
|
* level_max
|
||||||
|
* Maximum log leve.
|
||||||
|
* options_required
|
||||||
|
* Options a message must have set.
|
||||||
|
* options_absent
|
||||||
|
* Options a message must not have set.
|
||||||
|
* ts_min
|
||||||
|
* Minimum timestamp or NULL.
|
||||||
|
* ts_max
|
||||||
|
* Maximum timestamp or NULL.
|
||||||
|
* cat
|
||||||
|
* Message category/module or NULL.
|
||||||
|
* name, associated
|
||||||
|
* See refobject_new().
|
||||||
|
*/
|
||||||
|
igloo_filter_t * igloo_logmsg_filter(igloo_loglevel_t level_min, igloo_loglevel_t level_max, igloo_logmsg_opt_t options_required, igloo_logmsg_opt_t options_absent, const struct timespec * ts_min, const struct timespec * ts_max, const char *cat, const char *name, igloo_ro_t associated);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ! _LIBIGLOO__LOGMSG_H_ */
|
@ -37,6 +37,7 @@ extern "C" {
|
|||||||
typedef struct igloo_io_tag igloo_io_t;
|
typedef struct igloo_io_tag igloo_io_t;
|
||||||
typedef struct igloo_filter_tag igloo_filter_t;
|
typedef struct igloo_filter_tag igloo_filter_t;
|
||||||
typedef struct igloo_objecthandler_tag igloo_objecthandler_t;
|
typedef struct igloo_objecthandler_tag igloo_objecthandler_t;
|
||||||
|
typedef struct igloo_logmsg_tag igloo_logmsg_t;
|
||||||
typedef struct igloo_buffer_tag igloo_buffer_t;
|
typedef struct igloo_buffer_tag igloo_buffer_t;
|
||||||
typedef struct igloo_list_tag igloo_list_t;
|
typedef struct igloo_list_tag igloo_list_t;
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ typedef union __attribute__ ((__transparent_union__)) {
|
|||||||
igloo_RO_TYPE(igloo_io_t)
|
igloo_RO_TYPE(igloo_io_t)
|
||||||
igloo_RO_TYPE(igloo_filter_t)
|
igloo_RO_TYPE(igloo_filter_t)
|
||||||
igloo_RO_TYPE(igloo_objecthandler_t)
|
igloo_RO_TYPE(igloo_objecthandler_t)
|
||||||
|
igloo_RO_TYPE(igloo_logmsg_t)
|
||||||
igloo_RO_TYPE(igloo_buffer_t)
|
igloo_RO_TYPE(igloo_buffer_t)
|
||||||
igloo_RO_TYPE(igloo_list_t)
|
igloo_RO_TYPE(igloo_list_t)
|
||||||
igloo_RO_TYPE(igloo_reportxml_t)
|
igloo_RO_TYPE(igloo_reportxml_t)
|
||||||
|
220
log/log.c
220
log/log.c
@ -53,6 +53,8 @@
|
|||||||
|
|
||||||
#include <igloo/log.h>
|
#include <igloo/log.h>
|
||||||
|
|
||||||
|
#include "../src/private.h"
|
||||||
|
|
||||||
#define LOG_MAXLOGS 25
|
#define LOG_MAXLOGS 25
|
||||||
#define LOG_MAXLINELEN 1024
|
#define LOG_MAXLINELEN 1024
|
||||||
|
|
||||||
@ -439,220 +441,6 @@ void igloo_log_contents (int log_id, char **_contents, unsigned int *_len)
|
|||||||
_unlock_logger ();
|
_unlock_logger ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int __vsnprintf__is_print(int c, int allow_space)
|
|
||||||
{
|
|
||||||
if ((c <= '"' || c == '`' || c == '\\') && !(allow_space && c == ' ')) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t __vsnprintf__strlen(const char *str, int is_alt, int allow_space)
|
|
||||||
{
|
|
||||||
size_t ret = 0;
|
|
||||||
|
|
||||||
if (!str) {
|
|
||||||
if (is_alt) {
|
|
||||||
return strlen("-");
|
|
||||||
} else {
|
|
||||||
return strlen("(null)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; *str; str++) {
|
|
||||||
if (__vsnprintf__is_print(*str, allow_space)) {
|
|
||||||
ret += 1;
|
|
||||||
} else {
|
|
||||||
ret += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_alt) {
|
|
||||||
ret += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __vsnprintf(char *str, size_t size, const char *format, va_list ap) {
|
|
||||||
static const char hextable[] = "0123456789abcdef";
|
|
||||||
int in_block = 0;
|
|
||||||
int block_size = 0;
|
|
||||||
int block_len = 0;
|
|
||||||
int block_space = 0;
|
|
||||||
int block_alt = 0;
|
|
||||||
const char * arg;
|
|
||||||
char buf[80];
|
|
||||||
|
|
||||||
for (; *format && size; format++)
|
|
||||||
{
|
|
||||||
if ( !in_block )
|
|
||||||
{
|
|
||||||
if ( *format == '%' ) {
|
|
||||||
in_block = 1;
|
|
||||||
block_size = 0;
|
|
||||||
block_len = 0;
|
|
||||||
block_space = 0;
|
|
||||||
block_alt = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*(str++) = *format;
|
|
||||||
size--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: %l*[sdupi] as well as %.4080s and "%.*s
|
|
||||||
arg = NULL;
|
|
||||||
switch (*format)
|
|
||||||
{
|
|
||||||
case 'l':
|
|
||||||
block_size++;
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
block_size = 'z';
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
// just ignore '.'. If somebody cares: fix it.
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
block_len = va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
block_space = 1;
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
block_alt = 1;
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
block_len = atoi(format);
|
|
||||||
for (; *format >= '0' && *format <= '9'; format++);
|
|
||||||
format--;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
snprintf(buf, sizeof(buf), "%p", (void*)va_arg(ap, void *));
|
|
||||||
arg = buf;
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
case 'u':
|
|
||||||
if (!arg)
|
|
||||||
{
|
|
||||||
switch (block_size)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
if (*format == 'u')
|
|
||||||
snprintf(buf, sizeof(buf), "%u", (unsigned int)va_arg(ap, unsigned int));
|
|
||||||
else
|
|
||||||
snprintf(buf, sizeof(buf), "%i", (int)va_arg(ap, int));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (*format == 'u')
|
|
||||||
snprintf(buf, sizeof(buf), "%lu", (unsigned long int)va_arg(ap, unsigned long int));
|
|
||||||
else
|
|
||||||
snprintf(buf, sizeof(buf), "%li", (long int)va_arg(ap, long int));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (*format == 'u')
|
|
||||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long int)va_arg(ap, unsigned long long int));
|
|
||||||
else
|
|
||||||
snprintf(buf, sizeof(buf), "%lli", (long long int)va_arg(ap, long long int));
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
/* We do not use 'z' type of snprintf() here as it is not safe to use on a few outdated platforms. */
|
|
||||||
if (*format == 'u')
|
|
||||||
snprintf(buf, sizeof(buf), "%llu", (unsigned long long int)va_arg(ap, size_t));
|
|
||||||
else
|
|
||||||
snprintf(buf, sizeof(buf), "%lli", (long long int)va_arg(ap, ssize_t));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
snprintf(buf, sizeof(buf), "<<<invalid>>>");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
arg = buf;
|
|
||||||
}
|
|
||||||
case 's':
|
|
||||||
case 'H':
|
|
||||||
// TODO.
|
|
||||||
if (!arg)
|
|
||||||
arg = va_arg(ap, const char *);
|
|
||||||
if (*format != 'H') {
|
|
||||||
block_alt = 0;
|
|
||||||
}
|
|
||||||
if (!arg && !block_alt)
|
|
||||||
arg = "(null)";
|
|
||||||
if (!block_len) {
|
|
||||||
block_len = __vsnprintf__strlen(arg, block_alt, block_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the if() is the outer structure so the inner for()
|
|
||||||
// is branch optimized.
|
|
||||||
if (*format == 'H' && !arg)
|
|
||||||
{
|
|
||||||
if (size && block_len) {
|
|
||||||
*(str++) = '-';
|
|
||||||
size--;
|
|
||||||
block_len--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*format == 'H')
|
|
||||||
{
|
|
||||||
if (block_alt && size && block_len) {
|
|
||||||
*(str++) = '"';
|
|
||||||
size--;
|
|
||||||
block_len--;
|
|
||||||
}
|
|
||||||
for (; *arg && block_len && size; arg++, size--, block_len--)
|
|
||||||
{
|
|
||||||
if (!__vsnprintf__is_print(*arg, block_space)) {
|
|
||||||
if (size < 4 || block_len < 4) {
|
|
||||||
/* Use old system if we do not have space for new one */
|
|
||||||
*(str++) = '.';
|
|
||||||
} else {
|
|
||||||
*(str++) = '\\';
|
|
||||||
*(str++) = 'x';
|
|
||||||
*(str++) = hextable[(*arg >> 0) & 0x0F];
|
|
||||||
*(str++) = hextable[(*arg >> 4) & 0x0F];
|
|
||||||
/* Also count the additional chars for string size and block length */
|
|
||||||
size -= 3;
|
|
||||||
block_len -= 3;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*(str++) = *arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (block_alt && size && block_len) {
|
|
||||||
*(str++) = '"';
|
|
||||||
size--;
|
|
||||||
block_len--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (; *arg && block_len && size; arg++, size--, block_len--)
|
|
||||||
*(str++) = *arg;
|
|
||||||
}
|
|
||||||
in_block = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !size )
|
|
||||||
str--;
|
|
||||||
|
|
||||||
*str = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void igloo_log_write(int log_id, unsigned priority, const char *cat, const char *func,
|
void igloo_log_write(int log_id, unsigned priority, const char *cat, const char *func,
|
||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
{
|
{
|
||||||
@ -669,7 +457,7 @@ void igloo_log_write(int log_id, unsigned priority, const char *cat, const char
|
|||||||
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
__vsnprintf(line, sizeof(line), fmt, ap);
|
igloo_private__vsnprintf(line, sizeof(line), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
@ -696,7 +484,7 @@ void igloo_log_write_direct(int log_id, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
_lock_logger();
|
_lock_logger();
|
||||||
__vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
igloo_private__vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
|
||||||
if (_log_open (log_id))
|
if (_log_open (log_id))
|
||||||
{
|
{
|
||||||
int len = igloo_create_log_entry (log_id, "", line);
|
int len = igloo_create_log_entry (log_id, "", line);
|
||||||
|
393
src/logmsg.c
Normal file
393
src/logmsg.c
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
/* Icecast
|
||||||
|
*
|
||||||
|
* This program is distributed under the GNU General Public License, version 2.
|
||||||
|
* A copy of this license is included with this source.
|
||||||
|
*
|
||||||
|
* Copyright 2019, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <igloo/logmsg.h>
|
||||||
|
#include <igloo/interface.h>
|
||||||
|
#include <igloo/objecthandler.h>
|
||||||
|
#include <igloo/filter.h>
|
||||||
|
#include <igloo/io.h>
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
#define LOG_MAXLINELEN 1024
|
||||||
|
|
||||||
|
struct igloo_logmsg_tag {
|
||||||
|
igloo_ro_base_t __base;
|
||||||
|
char *msgid;
|
||||||
|
char *cat;
|
||||||
|
char *func;
|
||||||
|
char *codefile;
|
||||||
|
ssize_t codeline;
|
||||||
|
struct timespec ts;
|
||||||
|
igloo_loglevel_t level;
|
||||||
|
igloo_logmsg_opt_t options;
|
||||||
|
igloo_list_t *referenced;
|
||||||
|
char *string;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __free(igloo_ro_t self)
|
||||||
|
{
|
||||||
|
igloo_logmsg_t *logmsg = igloo_RO_TO_TYPE(self, igloo_logmsg_t);
|
||||||
|
free(logmsg->msgid);
|
||||||
|
free(logmsg->cat);
|
||||||
|
free(logmsg->func);
|
||||||
|
free(logmsg->codefile);
|
||||||
|
free(logmsg->string);
|
||||||
|
igloo_ro_unref(logmsg->referenced);
|
||||||
|
}
|
||||||
|
|
||||||
|
igloo_RO_PUBLIC_TYPE(igloo_logmsg_t,
|
||||||
|
igloo_RO_TYPEDECL_FREE(__free)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
igloo_logmsg_t * igloo_logmsg_new(const char *name, igloo_ro_t associated,
|
||||||
|
const char *msgid,
|
||||||
|
const char *cat,
|
||||||
|
const char *func, const char *codefile, const ssize_t codeline,
|
||||||
|
const struct timespec * ts,
|
||||||
|
igloo_loglevel_t level, igloo_logmsg_opt_t options,
|
||||||
|
igloo_list_t *referenced,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
igloo_logmsg_t *logmsg = igloo_ro_new_raw(igloo_logmsg_t, name, associated);
|
||||||
|
va_list ap;
|
||||||
|
char string[LOG_MAXLINELEN];
|
||||||
|
|
||||||
|
if (!logmsg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
logmsg->codeline = codeline;
|
||||||
|
logmsg->level = level;
|
||||||
|
logmsg->options = options;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
igloo_private__vsnprintf(string, sizeof(string), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
do {
|
||||||
|
#define __set_str(x) \
|
||||||
|
if (x) { \
|
||||||
|
logmsg->x = strdup((x)); \
|
||||||
|
if (!logmsg->x) \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_str(msgid);
|
||||||
|
__set_str(cat);
|
||||||
|
__set_str(func);
|
||||||
|
__set_str(codefile);
|
||||||
|
|
||||||
|
logmsg->string = strdup(string);
|
||||||
|
if (!logmsg->string)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ts) {
|
||||||
|
logmsg->ts = *ts;
|
||||||
|
} else {
|
||||||
|
if (clock_gettime(CLOCK_REALTIME, &(logmsg->ts)) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (referenced) {
|
||||||
|
if (igloo_ro_ref(referenced) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
logmsg->referenced = referenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logmsg;
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
igloo_ro_unref(logmsg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define __SETSTRING(x) \
|
||||||
|
if ((x)) { \
|
||||||
|
*(x) = msg->x; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int igloo_logmsg_get_context(igloo_logmsg_t *msg, const char **msgid, const char **cat, const char **func, const char **codefile, ssize_t *codeline, struct timespec *ts)
|
||||||
|
{
|
||||||
|
if (!msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
__SETSTRING(msgid);
|
||||||
|
__SETSTRING(cat);
|
||||||
|
__SETSTRING(func);
|
||||||
|
__SETSTRING(codefile);
|
||||||
|
__SETSTRING(codeline);
|
||||||
|
__SETSTRING(ts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int igloo_logmsg_get_message(igloo_logmsg_t *msg, igloo_loglevel_t *level, const char **string)
|
||||||
|
{
|
||||||
|
if (!msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (level)
|
||||||
|
*level = msg->level;
|
||||||
|
|
||||||
|
__SETSTRING(string);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int igloo_logmsg_get_extra(igloo_logmsg_t *msg, igloo_logmsg_opt_t *options, igloo_list_t **referenced)
|
||||||
|
{
|
||||||
|
if (!msg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (options)
|
||||||
|
*options = msg->options;
|
||||||
|
|
||||||
|
if (referenced) {
|
||||||
|
if (msg->referenced) {
|
||||||
|
if (igloo_ro_ref(msg->referenced) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*referenced = msg->referenced;
|
||||||
|
} else {
|
||||||
|
*referenced = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * __level2str(igloo_loglevel_t level)
|
||||||
|
{
|
||||||
|
switch (level) {
|
||||||
|
case igloo_LOGLEVEL__ERROR: return "<<<ERROR>>>"; break;
|
||||||
|
case igloo_LOGLEVEL__NONE: return "NONE"; break;
|
||||||
|
case igloo_LOGLEVEL_ERROR: return "EROR"; break;
|
||||||
|
case igloo_LOGLEVEL_WARN: return "WARN"; break;
|
||||||
|
case igloo_LOGLEVEL_INFO: return "INFO"; break;
|
||||||
|
case igloo_LOGLEVEL_DEBUG: return "DBUG"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<<<unknown log level>>>";
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
igloo_FST_FULL,
|
||||||
|
igloo_FST_OLD,
|
||||||
|
igloo_FST_NORMAL = igloo_FST_OLD
|
||||||
|
} igloo_logmsg_formarter_subtype_t;
|
||||||
|
|
||||||
|
static igloo_filter_result_t __handle(igloo_INTERFACE_BASIC_ARGS, igloo_ro_t object)
|
||||||
|
{
|
||||||
|
igloo_logmsg_t *msg = igloo_RO_TO_TYPE(object, igloo_logmsg_t);
|
||||||
|
igloo_logmsg_formarter_subtype_t sf = *(igloo_logmsg_formarter_subtype_t*)*backend_userdata;
|
||||||
|
const char *level = NULL;
|
||||||
|
time_t now;
|
||||||
|
char pre[256+LOG_MAXLINELEN] = "";
|
||||||
|
int datelen;
|
||||||
|
char flags[3] = " ";
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
level = __level2str(msg->level);
|
||||||
|
|
||||||
|
switch (sf) {
|
||||||
|
case igloo_FST_FULL:
|
||||||
|
if (msg->options & igloo_LOGMSG_OPT_DEVEL)
|
||||||
|
flags[0] = 'D';
|
||||||
|
|
||||||
|
if (msg->options & igloo_LOGMSG_OPT_ASKACK)
|
||||||
|
flags[1] = 'A';
|
||||||
|
|
||||||
|
now = msg->ts.tv_sec;
|
||||||
|
datelen = strftime(pre, sizeof(pre), "[%Y-%m-%d %H:%M:%S UTC]", gmtime(&now));
|
||||||
|
snprintf(pre+datelen, sizeof(pre)-datelen, " (%s) %s [%s] %s/%s(%s:%zi) %s\n", (msg->msgid ? msg->msgid : ""), level, flags, msg->cat, msg->func, msg->codefile, msg->codeline, msg->string);
|
||||||
|
break;
|
||||||
|
case igloo_FST_OLD:
|
||||||
|
now = msg->ts.tv_sec;
|
||||||
|
datelen = strftime(pre, sizeof(pre), "[%Y-%m-%d %H:%M:%S]", localtime(&now));
|
||||||
|
snprintf(pre+datelen, sizeof(pre)-datelen, " %s %s/%s %s\n", level, msg->cat, msg->func, msg->string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
igloo_io_write(igloo_RO_TO_TYPE(*backend_object, igloo_io_t), pre, strlen(pre));
|
||||||
|
|
||||||
|
return igloo_FILTER_RESULT_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __flush(igloo_INTERFACE_BASIC_ARGS)
|
||||||
|
{
|
||||||
|
igloo_io_t *io = igloo_RO_TO_TYPE(*backend_object, igloo_io_t);
|
||||||
|
|
||||||
|
if (!io)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return igloo_io_flush(io, igloo_IO_OPFLAG_DEFAULTS|igloo_IO_OPFLAG_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __set_backend(igloo_INTERFACE_BASIC_ARGS, igloo_ro_t backend)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!igloo_RO_IS_NULL(backend)) {
|
||||||
|
if (!igloo_RO_IS_VALID(backend, igloo_io_t))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = igloo_ro_ref(backend);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
igloo_ro_unref(*backend_object);
|
||||||
|
*backend_object = backend;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const igloo_objecthandler_ifdesc_t igloo_logmsg_formarter_ifdesc = {
|
||||||
|
igloo_INTERFACE_DESCRIPTION_BASE(igloo_objecthandler_ifdesc_t),
|
||||||
|
.is_thread_safe = 1,
|
||||||
|
.handle = __handle,
|
||||||
|
.flush = __flush,
|
||||||
|
.set_backend = __set_backend
|
||||||
|
};
|
||||||
|
|
||||||
|
igloo_objecthandler_t * igloo_logmsg_formarter(igloo_ro_t backend, const char *subformat, const char *name, igloo_ro_t associated)
|
||||||
|
{
|
||||||
|
igloo_logmsg_formarter_subtype_t *sf = NULL;
|
||||||
|
igloo_objecthandler_t *objecthandler;
|
||||||
|
|
||||||
|
if (!subformat || strcmp(subformat, "default") == 0)
|
||||||
|
subformat = "normal";
|
||||||
|
|
||||||
|
sf = malloc(sizeof(*sf));
|
||||||
|
if (!sf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (strcmp(subformat, "normal") == 0) {
|
||||||
|
*sf = igloo_FST_NORMAL;
|
||||||
|
} else if (strcmp(subformat, "full") == 0) {
|
||||||
|
*sf = igloo_FST_FULL;
|
||||||
|
} else if (strcmp(subformat, "old") == 0) {
|
||||||
|
*sf = igloo_FST_OLD;
|
||||||
|
} else {
|
||||||
|
free(sf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
objecthandler = igloo_objecthandler_new(&igloo_logmsg_formarter_ifdesc, NULL, sf, name, associated);
|
||||||
|
if (!objecthandler) {
|
||||||
|
free(sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (igloo_objecthandler_set_backend(objecthandler, backend) != 0) {
|
||||||
|
igloo_ro_unref(objecthandler);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return objecthandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
igloo_loglevel_t level_min;
|
||||||
|
igloo_loglevel_t level_max;
|
||||||
|
igloo_logmsg_opt_t options_required;
|
||||||
|
igloo_logmsg_opt_t options_absent;
|
||||||
|
struct timespec ts_min;
|
||||||
|
struct timespec ts_max;
|
||||||
|
char *cat;
|
||||||
|
} igloo_logmsg_filter_mask_t;
|
||||||
|
|
||||||
|
static inline int __gt_timespec(struct timespec *a, struct timespec *b)
|
||||||
|
{
|
||||||
|
return a->tv_sec > b->tv_sec || (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static igloo_filter_result_t __test(igloo_INTERFACE_BASIC_ARGS, igloo_ro_t object)
|
||||||
|
{
|
||||||
|
igloo_logmsg_t *msg = igloo_RO_TO_TYPE(object, igloo_logmsg_t);
|
||||||
|
igloo_logmsg_filter_mask_t *mask = *backend_userdata;
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
if (msg->level < mask->level_min || msg->level > mask->level_max)
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
if ((msg->options & mask->options_required) != mask->options_required || (msg->options & mask->options_absent))
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
if (__gt_timespec(&(mask->ts_min), &(msg->ts)) || __gt_timespec(&(msg->ts), &(mask->ts_max)))
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
if (mask->cat) {
|
||||||
|
if (!msg->cat)
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
|
||||||
|
if (strcmp(msg->cat, mask->cat) != 0)
|
||||||
|
return igloo_FILTER_RESULT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return igloo_FILTER_RESULT_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const igloo_filter_ifdesc_t igloo_logmsg_filter_ifdesc = {
|
||||||
|
igloo_INTERFACE_DESCRIPTION_BASE(igloo_filter_ifdesc_t),
|
||||||
|
.test = __test
|
||||||
|
};
|
||||||
|
|
||||||
|
igloo_filter_t * igloo_logmsg_filter(igloo_loglevel_t level_min, igloo_loglevel_t level_max, igloo_logmsg_opt_t options_required, igloo_logmsg_opt_t options_absent, const struct timespec * ts_min, const struct timespec * ts_max, const char *cat, const char *name, igloo_ro_t associated)
|
||||||
|
{
|
||||||
|
igloo_filter_t *filter;
|
||||||
|
igloo_logmsg_filter_mask_t *mask = calloc(1, sizeof(*mask));
|
||||||
|
|
||||||
|
if (!mask)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mask->level_min = level_min;
|
||||||
|
mask->level_max = level_max;
|
||||||
|
mask->options_required = options_required;
|
||||||
|
mask->options_absent = options_absent;
|
||||||
|
|
||||||
|
/* No else needed, as {0, 0} is already in the past. */
|
||||||
|
if (ts_min)
|
||||||
|
mask->ts_min = *ts_min;
|
||||||
|
|
||||||
|
if (ts_max) {
|
||||||
|
mask->ts_max = *ts_max;
|
||||||
|
} else {
|
||||||
|
/* BEFORE YEAR 2038 IMPORTANT REWRITE: Update date. */
|
||||||
|
mask->ts_max.tv_sec = 2145916800; /* this is 2038-01-01 */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cat) {
|
||||||
|
mask->cat = strdup(cat);
|
||||||
|
if (!mask->cat) {
|
||||||
|
free(mask);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = igloo_filter_new(&igloo_logmsg_filter_ifdesc, igloo_RO_NULL, mask, name, associated);
|
||||||
|
if (!filter) {
|
||||||
|
free(mask);
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
@ -31,6 +31,9 @@ static void __free(igloo_ro_t self)
|
|||||||
igloo_objecthandler_t *handler = igloo_RO_TO_TYPE(self, igloo_objecthandler_t);
|
igloo_objecthandler_t *handler = igloo_RO_TO_TYPE(self, igloo_objecthandler_t);
|
||||||
|
|
||||||
igloo_thread_rwlock_wlock(&(handler->rwlock));
|
igloo_thread_rwlock_wlock(&(handler->rwlock));
|
||||||
|
igloo_ro_unref(handler->filter_a);
|
||||||
|
igloo_ro_unref(handler->filter_b);
|
||||||
|
igloo_ro_unref(handler->filter_list);
|
||||||
igloo_thread_rwlock_unlock(&(handler->rwlock));
|
igloo_thread_rwlock_unlock(&(handler->rwlock));
|
||||||
igloo_thread_rwlock_destroy(&(handler->rwlock));
|
igloo_thread_rwlock_destroy(&(handler->rwlock));
|
||||||
|
|
||||||
|
233
src/private.c
Normal file
233
src/private.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/* Icecast
|
||||||
|
*
|
||||||
|
* This program is distributed under the GNU General Public License, version 2.
|
||||||
|
* A copy of this license is included with this source.
|
||||||
|
*
|
||||||
|
* Copyright 2019, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "private.h"
|
||||||
|
|
||||||
|
static inline int __vsnprintf__is_print(int c, int allow_space)
|
||||||
|
{
|
||||||
|
if ((c <= '"' || c == '`' || c == '\\') && !(allow_space && c == ' ')) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t __vsnprintf__strlen(const char *str, int is_alt, int allow_space)
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
if (is_alt) {
|
||||||
|
return strlen("-");
|
||||||
|
} else {
|
||||||
|
return strlen("(null)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; *str; str++) {
|
||||||
|
if (__vsnprintf__is_print(*str, allow_space)) {
|
||||||
|
ret += 1;
|
||||||
|
} else {
|
||||||
|
ret += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_alt) {
|
||||||
|
ret += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void igloo_private__vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
static const char hextable[] = "0123456789abcdef";
|
||||||
|
int in_block = 0;
|
||||||
|
int block_size = 0;
|
||||||
|
int block_len = 0;
|
||||||
|
int block_space = 0;
|
||||||
|
int block_alt = 0;
|
||||||
|
const char * arg;
|
||||||
|
char buf[80];
|
||||||
|
|
||||||
|
for (; *format && size; format++)
|
||||||
|
{
|
||||||
|
if ( !in_block )
|
||||||
|
{
|
||||||
|
if ( *format == '%' ) {
|
||||||
|
in_block = 1;
|
||||||
|
block_size = 0;
|
||||||
|
block_len = 0;
|
||||||
|
block_space = 0;
|
||||||
|
block_alt = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(str++) = *format;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: %l*[sdupi] as well as %.4080s and "%.*s
|
||||||
|
arg = NULL;
|
||||||
|
switch (*format)
|
||||||
|
{
|
||||||
|
case 'l':
|
||||||
|
block_size++;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
block_size = 'z';
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
// just ignore '.'. If somebody cares: fix it.
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
block_len = va_arg(ap, int);
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
block_space = 1;
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
block_alt = 1;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
block_len = atoi(format);
|
||||||
|
for (; *format >= '0' && *format <= '9'; format++);
|
||||||
|
format--;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
snprintf(buf, sizeof(buf), "%p", (void*)va_arg(ap, void *));
|
||||||
|
arg = buf;
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
case 'u':
|
||||||
|
if (!arg)
|
||||||
|
{
|
||||||
|
switch (block_size)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (*format == 'u')
|
||||||
|
snprintf(buf, sizeof(buf), "%u", (unsigned int)va_arg(ap, unsigned int));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "%i", (int)va_arg(ap, int));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (*format == 'u')
|
||||||
|
snprintf(buf, sizeof(buf), "%lu", (unsigned long int)va_arg(ap, unsigned long int));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "%li", (long int)va_arg(ap, long int));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (*format == 'u')
|
||||||
|
snprintf(buf, sizeof(buf), "%llu", (unsigned long long int)va_arg(ap, unsigned long long int));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "%lli", (long long int)va_arg(ap, long long int));
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
/* We do not use 'z' type of snprintf() here as it is not safe to use on a few outdated platforms. */
|
||||||
|
if (*format == 'u')
|
||||||
|
snprintf(buf, sizeof(buf), "%llu", (unsigned long long int)va_arg(ap, size_t));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof(buf), "%lli", (long long int)va_arg(ap, ssize_t));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(buf, sizeof(buf), "<<<invalid>>>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
arg = buf;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
case 'H':
|
||||||
|
// TODO.
|
||||||
|
if (!arg)
|
||||||
|
arg = va_arg(ap, const char *);
|
||||||
|
if (*format != 'H') {
|
||||||
|
block_alt = 0;
|
||||||
|
}
|
||||||
|
if (!arg && !block_alt)
|
||||||
|
arg = "(null)";
|
||||||
|
if (!block_len) {
|
||||||
|
block_len = __vsnprintf__strlen(arg, block_alt, block_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the if() is the outer structure so the inner for()
|
||||||
|
// is branch optimized.
|
||||||
|
if (*format == 'H' && !arg)
|
||||||
|
{
|
||||||
|
if (size && block_len) {
|
||||||
|
*(str++) = '-';
|
||||||
|
size--;
|
||||||
|
block_len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*format == 'H')
|
||||||
|
{
|
||||||
|
if (block_alt && size && block_len) {
|
||||||
|
*(str++) = '"';
|
||||||
|
size--;
|
||||||
|
block_len--;
|
||||||
|
}
|
||||||
|
for (; *arg && block_len && size; arg++, size--, block_len--)
|
||||||
|
{
|
||||||
|
if (!__vsnprintf__is_print(*arg, block_space)) {
|
||||||
|
if (size < 4 || block_len < 4) {
|
||||||
|
/* Use old system if we do not have space for new one */
|
||||||
|
*(str++) = '.';
|
||||||
|
} else {
|
||||||
|
*(str++) = '\\';
|
||||||
|
*(str++) = 'x';
|
||||||
|
*(str++) = hextable[(*arg >> 0) & 0x0F];
|
||||||
|
*(str++) = hextable[(*arg >> 4) & 0x0F];
|
||||||
|
/* Also count the additional chars for string size and block length */
|
||||||
|
size -= 3;
|
||||||
|
block_len -= 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*(str++) = *arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (block_alt && size && block_len) {
|
||||||
|
*(str++) = '"';
|
||||||
|
size--;
|
||||||
|
block_len--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; *arg && block_len && size; arg++, size--, block_len--)
|
||||||
|
*(str++) = *arg;
|
||||||
|
}
|
||||||
|
in_block = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !size )
|
||||||
|
str--;
|
||||||
|
|
||||||
|
*str = 0;
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,10 @@
|
|||||||
#ifndef _LIBIGLOO__PRIVATE_H_
|
#ifndef _LIBIGLOO__PRIVATE_H_
|
||||||
#define _LIBIGLOO__PRIVATE_H_
|
#define _LIBIGLOO__PRIVATE_H_
|
||||||
|
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
#include <stdarg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <igloo/interface.h>
|
#include <igloo/interface.h>
|
||||||
|
|
||||||
/* init/shutdown of the library */
|
/* init/shutdown of the library */
|
||||||
@ -55,4 +59,6 @@ void igloo_interface_base_free(igloo_ro_t self);
|
|||||||
igloo_ro_t igloo_interface_base_new_real(const igloo_ro_type_t *type, size_t description_length, const igloo_interface_base_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated);
|
igloo_ro_t igloo_interface_base_new_real(const igloo_ro_type_t *type, size_t description_length, const igloo_interface_base_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated);
|
||||||
#define igloo_interface_base_new(type, ifdesc, backend_object, backend_userdata, name, associated) igloo_RO_TO_TYPE(igloo_interface_base_new_real(igloo_ro__type__ ## type, sizeof(*(ifdesc)), (const igloo_interface_base_ifdesc_t*)(ifdesc), (backend_object), (backend_userdata), (name), (associated)), type)
|
#define igloo_interface_base_new(type, ifdesc, backend_object, backend_userdata, name, associated) igloo_RO_TO_TYPE(igloo_interface_base_new_real(igloo_ro__type__ ## type, sizeof(*(ifdesc)), (const igloo_interface_base_ifdesc_t*)(ifdesc), (backend_object), (backend_userdata), (name), (associated)), type)
|
||||||
|
|
||||||
|
void igloo_private__vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,5 +55,19 @@ ctest_reportxml_test_LDADD = libice_ctest.la \
|
|||||||
src/reportxml.o
|
src/reportxml.o
|
||||||
check_PROGRAMS += ctest_reportxml.test
|
check_PROGRAMS += ctest_reportxml.test
|
||||||
|
|
||||||
|
ctest_logmsg_test_SOURCES = %reldir%/ctest_logmsg.c
|
||||||
|
ctest_logmsg_test_LDADD = libice_ctest.la \
|
||||||
|
thread/libicethread.la \
|
||||||
|
avl/libiceavl.la \
|
||||||
|
src/private.o \
|
||||||
|
src/ro.o \
|
||||||
|
src/io.o \
|
||||||
|
src/list.o \
|
||||||
|
src/interface.o \
|
||||||
|
src/objecthandler.o \
|
||||||
|
src/filter.o \
|
||||||
|
src/logmsg.o
|
||||||
|
check_PROGRAMS += ctest_logmsg.test
|
||||||
|
|
||||||
# Add all programs to TESTS
|
# Add all programs to TESTS
|
||||||
TESTS = $(check_PROGRAMS)
|
TESTS = $(check_PROGRAMS)
|
||||||
|
131
src/tests/ctest_logmsg.c
Normal file
131
src/tests/ctest_logmsg.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/* Icecast
|
||||||
|
*
|
||||||
|
* This program is distributed under the GNU General Public License, version 2.
|
||||||
|
* A copy of this license is included with this source.
|
||||||
|
*
|
||||||
|
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ctest_lib.h"
|
||||||
|
|
||||||
|
#include <igloo/logmsg.h>
|
||||||
|
#include <igloo/filter.h>
|
||||||
|
|
||||||
|
static void test_create_unref(void)
|
||||||
|
{
|
||||||
|
igloo_logmsg_t *msg;
|
||||||
|
igloo_objecthandler_t *formater;
|
||||||
|
igloo_filter_t *filter;
|
||||||
|
|
||||||
|
msg = igloo_logmsg_new(NULL, igloo_RO_NULL, NULL, NULL, NULL, NULL, -1, NULL, igloo_LOGLEVEL__NONE, igloo_LOGMSG_OPT_NONE, NULL, "test");
|
||||||
|
ctest_test("logmsg created", !igloo_RO_IS_NULL(msg));
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(msg) == 0);
|
||||||
|
|
||||||
|
formater = igloo_logmsg_formarter(igloo_RO_NULL, NULL, NULL, igloo_RO_NULL);
|
||||||
|
ctest_test("formater created", !igloo_RO_IS_NULL(formater));
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(formater) == 0);
|
||||||
|
|
||||||
|
filter = igloo_logmsg_filter(igloo_LOGLEVEL__NONE, igloo_LOGLEVEL__NONE, igloo_LOGMSG_OPT_NONE, igloo_LOGMSG_OPT_NONE, NULL, NULL, NULL, NULL, igloo_RO_NULL);
|
||||||
|
ctest_test("filter created", !igloo_RO_IS_NULL(filter));
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(filter) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_logmsg(void)
|
||||||
|
{
|
||||||
|
static const struct timespec tv_in = {.tv_sec = -4242134, .tv_nsec = 1234789};
|
||||||
|
igloo_logmsg_t *msg;
|
||||||
|
const char *msgid_out, *cat_out, *func_out, *codefile_out, *string_out;
|
||||||
|
ssize_t codeline_out;
|
||||||
|
struct timespec tv_out;
|
||||||
|
igloo_loglevel_t level_out;
|
||||||
|
igloo_logmsg_opt_t options_out;
|
||||||
|
igloo_list_t *referenced_out;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
msg = igloo_logmsg_new("name", igloo_RO_NULL, "msgid", "cat", "func", "codefile", 13374242, &tv_in, igloo_LOGLEVEL_INFO, igloo_LOGMSG_OPT_ASKACK, NULL, "test %i %s", 5, "msg");
|
||||||
|
ctest_test("logmsg created", !igloo_RO_IS_NULL(msg));
|
||||||
|
|
||||||
|
ctest_test("got context", (ret = igloo_logmsg_get_context(msg, &msgid_out, &cat_out, &func_out, &codefile_out, &codeline_out, &tv_out)) == 0);
|
||||||
|
if (ret == 0) {
|
||||||
|
ctest_test("got msgid", msgid_out != NULL && strcmp(msgid_out, "msgid") == 0);
|
||||||
|
ctest_test("got cat", cat_out != NULL && strcmp(cat_out, "cat") == 0);
|
||||||
|
ctest_test("got func", func_out != NULL && strcmp(func_out, "func") == 0);
|
||||||
|
ctest_test("got codefile", codefile_out != NULL && strcmp(codefile_out, "codefile") == 0);
|
||||||
|
ctest_test("got codeline", codeline_out == 13374242);
|
||||||
|
ctest_test("got ts", tv_out.tv_sec == -4242134 && tv_out.tv_nsec == 1234789);
|
||||||
|
} else {
|
||||||
|
ctest_test("got msgid", 0);
|
||||||
|
ctest_test("got cat", 0);
|
||||||
|
ctest_test("got func", 0);
|
||||||
|
ctest_test("got codefile", 0);
|
||||||
|
ctest_test("got codeline", 0);
|
||||||
|
ctest_test("got ts", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctest_test("got message", (ret = igloo_logmsg_get_message(msg, &level_out, &string_out)) == 0);
|
||||||
|
if (ret == 0) {
|
||||||
|
ctest_test("got level", level_out == igloo_LOGLEVEL_INFO);
|
||||||
|
ctest_test("got string", string_out != NULL && strcmp(string_out, "test 5 msg") == 0);
|
||||||
|
} else {
|
||||||
|
ctest_test("got level", 0);
|
||||||
|
ctest_test("got string", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctest_test("got extra", (ret = igloo_logmsg_get_extra(msg, &options_out, &referenced_out)) == 0);
|
||||||
|
if (ret == 0) {
|
||||||
|
ctest_test("got options", options_out == igloo_LOGMSG_OPT_ASKACK);
|
||||||
|
ctest_test("got referenced", referenced_out == NULL);
|
||||||
|
} else {
|
||||||
|
ctest_test("got options", 0);
|
||||||
|
ctest_test("got referenced", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(msg) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_filter(void)
|
||||||
|
{
|
||||||
|
igloo_filter_t *filter;
|
||||||
|
igloo_logmsg_t *msg;
|
||||||
|
igloo_ro_base_t *base;
|
||||||
|
|
||||||
|
filter = igloo_logmsg_filter(igloo_LOGLEVEL_ERROR, igloo_LOGLEVEL_WARN, igloo_LOGMSG_OPT_NONE, igloo_LOGMSG_OPT_NONE, NULL, NULL, NULL, NULL, igloo_RO_NULL);
|
||||||
|
ctest_test("filter created", !igloo_RO_IS_NULL(filter));
|
||||||
|
|
||||||
|
base = igloo_ro_new(igloo_ro_base_t);
|
||||||
|
ctest_test("base created", base != NULL);
|
||||||
|
ctest_test("droping base", igloo_filter_test(filter, base) == igloo_FILTER_RESULT_DROP);
|
||||||
|
ctest_test("base un-referenced", igloo_ro_unref(base) == 0);
|
||||||
|
|
||||||
|
msg = igloo_logmsg_new(NULL, igloo_RO_NULL, NULL, NULL, NULL, NULL, -1, NULL, igloo_LOGLEVEL_INFO, igloo_LOGMSG_OPT_NONE, NULL, "test");
|
||||||
|
ctest_test("logmsg created", !igloo_RO_IS_NULL(msg));
|
||||||
|
ctest_test("droping logmsg", igloo_filter_test(filter, msg) == igloo_FILTER_RESULT_DROP);
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(msg) == 0);
|
||||||
|
|
||||||
|
msg = igloo_logmsg_new(NULL, igloo_RO_NULL, NULL, NULL, NULL, NULL, -1, NULL, igloo_LOGLEVEL_WARN, igloo_LOGMSG_OPT_NONE, NULL, "test");
|
||||||
|
ctest_test("logmsg created", !igloo_RO_IS_NULL(msg));
|
||||||
|
ctest_test("passing logmsg", igloo_filter_test(filter, msg) == igloo_FILTER_RESULT_PASS);
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(msg) == 0);
|
||||||
|
|
||||||
|
ctest_test("un-referenced", igloo_ro_unref(filter) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
ctest_init();
|
||||||
|
|
||||||
|
test_create_unref();
|
||||||
|
|
||||||
|
test_logmsg();
|
||||||
|
test_filter();
|
||||||
|
|
||||||
|
ctest_fin();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user