Make logging config per-domain
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
7190bb3d3e
commit
966ec0dda7
70 changed files with 2052 additions and 1718 deletions
|
@ -100,6 +100,10 @@ ddsrt_nonnull_all;
|
|||
* The result string should be freed with ddsrt_free().
|
||||
*
|
||||
* @param[in] string String to expand.
|
||||
* @param[in] domid Domain id that this is relevant to
|
||||
* UINT32_MAX means none (see logging)
|
||||
* also made available as
|
||||
* ${CYCLONEDDS_DOMAIN_ID}
|
||||
*
|
||||
* @returns Allocated char*.
|
||||
*
|
||||
|
@ -111,7 +115,8 @@ ddsrt_nonnull_all;
|
|||
*/
|
||||
DDS_EXPORT char*
|
||||
ddsrt_expand_envvars(
|
||||
const char *string);
|
||||
const char *string,
|
||||
uint32_t domid);
|
||||
|
||||
/**
|
||||
* @brief Expand environment variables within string.
|
||||
|
@ -133,7 +138,8 @@ ddsrt_expand_envvars(
|
|||
*/
|
||||
DDS_EXPORT char*
|
||||
ddsrt_expand_envvars_sh(
|
||||
const char *string);
|
||||
const char *string,
|
||||
uint32_t domid);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
|
|
@ -92,6 +92,8 @@ extern "C" {
|
|||
typedef struct {
|
||||
/** Log category the message falls into. */
|
||||
uint32_t priority;
|
||||
/** Log domain id, UINT32_MAX is global. */
|
||||
uint32_t domid;
|
||||
/** Filename where message was generated. */
|
||||
const char *file;
|
||||
/** Line number in file where message was generated. */
|
||||
|
@ -102,11 +104,29 @@ typedef struct {
|
|||
const char *message;
|
||||
/** Size of log message. */
|
||||
size_t size;
|
||||
/** Default log message header length */
|
||||
size_t hdrsize;
|
||||
} dds_log_data_t;
|
||||
|
||||
/** Function signature that log and trace callbacks must adhere too. */
|
||||
typedef void(*dds_log_write_fn_t)(void *, const dds_log_data_t *);
|
||||
|
||||
/** Semi-opaque type for log/trace configuration. */
|
||||
struct ddsrt_log_cfg_common {
|
||||
uint32_t mask;
|
||||
uint32_t domid;
|
||||
};
|
||||
|
||||
typedef struct ddsrt_log_cfg {
|
||||
struct ddsrt_log_cfg_common c;
|
||||
union {
|
||||
dds_log_write_fn_t fnptr;
|
||||
void *ptr;
|
||||
uint32_t u32;
|
||||
unsigned char pad[72];
|
||||
} u;
|
||||
} ddsrt_log_cfg_t;
|
||||
|
||||
DDS_EXPORT extern uint32_t *const dds_log_mask;
|
||||
|
||||
/**
|
||||
|
@ -186,7 +206,77 @@ dds_set_trace_sink(
|
|||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Write a log or trace message.
|
||||
* @brief Initialize a struct ddsrt_log_cfg for use with dds_log_cfg
|
||||
*
|
||||
* Callbacks registered to handle log messages will receive messages of type
|
||||
* info, warning, error and fatal. Messages that fall into the trace category
|
||||
* will never be delivered to the callback.
|
||||
*
|
||||
* Callbacks registered to handle trace messages will receive messages of type
|
||||
* info, warning, error and fatal as well as all message types that fall into
|
||||
* the trace category depending on the log mask.
|
||||
*
|
||||
* This operation is synchronous and only returns once the operation is
|
||||
* registered with all threads. Meaning that neither callback or
|
||||
* userdata will be referenced by the DDS stack on return.
|
||||
*
|
||||
* @param[out] cfg On return, initialised to make dds_log_cfg invoked
|
||||
* with this config object behave as specified by the
|
||||
* other parameters.
|
||||
* @param[in] domid Numerical identifier in log/trace, UINT32_MAX is
|
||||
* reserved for global logging.
|
||||
* @param[in] mask Mask determining what to log/trace.
|
||||
* @param[in] log_fp File for default sink.
|
||||
* @param[in] trace_fp File for default sink.
|
||||
*/
|
||||
DDS_EXPORT void
|
||||
dds_log_cfg_init(
|
||||
struct ddsrt_log_cfg *cfg,
|
||||
uint32_t domid,
|
||||
uint32_t mask,
|
||||
FILE *log_fp,
|
||||
FILE *trace_fp);
|
||||
|
||||
/**
|
||||
* @brief Write a log or trace message for a specific logging configuraiton
|
||||
* (categories, id, sinks).
|
||||
*
|
||||
* Direct use of #dds_log is discouraged. Use #DDS_CINFO, #DDS_CWARNING,
|
||||
* #DDS_CERROR, #DDS_CTRACE or #DDS_CLOG instead.
|
||||
*/
|
||||
DDS_EXPORT int
|
||||
dds_log_cfg(
|
||||
const struct ddsrt_log_cfg *cfg,
|
||||
uint32_t prio,
|
||||
const char *file,
|
||||
uint32_t line,
|
||||
const char *func,
|
||||
const char *fmt,
|
||||
...)
|
||||
ddsrt_attribute_format((__printf__, 6, 7));
|
||||
|
||||
/**
|
||||
* @brief Write a log or trace message to the global configuration but with
|
||||
* specific domain (intended solely for use during domain start-up, while
|
||||
* the domain-specific logging/tracing hasn't been set yet).
|
||||
*
|
||||
* Write a log or trace message to one (or both) of the currently active sinks.
|
||||
*
|
||||
* Direct use of #dds_log_id is discouraged. Use #DDS_ILOG instead.
|
||||
*/
|
||||
DDS_EXPORT int
|
||||
dds_log_id(
|
||||
uint32_t prio,
|
||||
uint32_t domid,
|
||||
const char *file,
|
||||
uint32_t line,
|
||||
const char *func,
|
||||
const char *fmt,
|
||||
...)
|
||||
ddsrt_attribute_format((__printf__, 6, 7));
|
||||
|
||||
/**
|
||||
* @brief Write a log or trace message to the global log/trace.
|
||||
*
|
||||
* Write a log or trace message to one (or both) of the currently active sinks.
|
||||
*
|
||||
|
@ -279,23 +369,70 @@ dds_log(
|
|||
*/
|
||||
#define DDS_LOG(cat, ...) \
|
||||
((dds_get_log_mask() & (cat)) ? \
|
||||
dds_log(cat, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
|
||||
dds_log((cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
|
||||
|
||||
/** Write a log message of type #DDS_LC_INFO. */
|
||||
/**
|
||||
* @brief Write a log message with a domain id override.
|
||||
*
|
||||
* Write a log or trace message to the currently active log and/or trace sinks
|
||||
* if the log category is enabled. Whether or not the category is enabled is
|
||||
* checked before any dds_log-related activities to save a couple of % CPU.
|
||||
*
|
||||
* Only messages that fall into one of the log categories are passed onto
|
||||
* dds_log. While messages that fall into a trace category could have been
|
||||
* passed just as easily, they are rejected so that tracing is kept entirely
|
||||
* separate from logging, if only cosmetic.
|
||||
*/
|
||||
#define DDS_ILOG(cat, domid, ...) \
|
||||
((dds_get_log_mask() & (cat)) ? \
|
||||
dds_log_id((cat), (domid), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
|
||||
|
||||
/**
|
||||
* @brief Write a log message using a specific config.
|
||||
*
|
||||
* Write a log or trace message to the currently active log and/or trace sinks
|
||||
* if the log category is enabled. Whether or not the category is enabled is
|
||||
* checked before any dds_log-related activities to save a couple of % CPU.
|
||||
*
|
||||
* Only messages that fall into one of the log categories are passed onto
|
||||
* dds_log. While messages that fall into a trace category could have been
|
||||
* passed just as easily, they are rejected so that tracing is kept entirely
|
||||
* separate from logging, if only cosmetic.
|
||||
*/
|
||||
#define DDS_CLOG(cat, cfg, ...) \
|
||||
(((cfg)->c.mask & (cat)) ? \
|
||||
dds_log_cfg((cfg), (cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0)
|
||||
|
||||
/** Write a log message of type #DDS_LC_INFO into global log. */
|
||||
#define DDS_INFO(...) \
|
||||
DDS_LOG(DDS_LC_INFO, __VA_ARGS__)
|
||||
/** Write a log message of type #DDS_LC_WARNING. */
|
||||
/** Write a log message of type #DDS_LC_WARNING into global log. */
|
||||
#define DDS_WARNING(...) \
|
||||
DDS_LOG(DDS_LC_WARNING, __VA_ARGS__)
|
||||
/** Write a log message of type #DDS_LC_ERROR. */
|
||||
/** Write a log message of type #DDS_LC_ERROR into global log. */
|
||||
#define DDS_ERROR(...) \
|
||||
DDS_LOG(DDS_LC_ERROR, __VA_ARGS__)
|
||||
/** Write a log message of type #DDS_LC_ERROR and abort. */
|
||||
/** Write a log message of type #DDS_LC_ERROR into global log and abort. */
|
||||
#define DDS_FATAL(...) \
|
||||
dds_log(DDS_LC_FATAL, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__)
|
||||
/** Write a #DDS_LC_TRACE message. */
|
||||
#define DDS_TRACE(...) \
|
||||
DDS_LOG(DDS_LC_TRACE, __VA_ARGS__)
|
||||
|
||||
/* MSVC mishandles __VA_ARGS__ while claiming to be conforming -- and even
|
||||
if they have a defensible implement, they still differ from every other
|
||||
compiler out there. An extra layer of macro expansion works around it. */
|
||||
#define DDS_CLOG_MSVC_WORKAROUND(x) x
|
||||
|
||||
/** Write a log message of type #DDS_LC_INFO using specific logging config. */
|
||||
#define DDS_CINFO(...) \
|
||||
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_INFO, __VA_ARGS__))
|
||||
/** Write a log message of type #DDS_LC_WARNING using specific logging config. */
|
||||
#define DDS_CWARNING(...) \
|
||||
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_WARNING, __VA_ARGS__))
|
||||
/** Write a log message of type #DDS_LC_ERROR using specific logging config. */
|
||||
#define DDS_CERROR(...) \
|
||||
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_ERROR, __VA_ARGS__))
|
||||
/** Write a #DDS_LC_TRACE message using specific logging config. */
|
||||
#define DDS_CTRACE(...) \
|
||||
DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_TRACE, __VA_ARGS__))
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "dds/ddsrt/string.h"
|
||||
#include "dds/ddsrt/process.h"
|
||||
|
||||
typedef char * (*expand_fn)(const char *src0);
|
||||
typedef char * (*expand_fn)(const char *src0, uint32_t domid);
|
||||
|
||||
static void expand_append (char **dst, size_t *sz, size_t *pos, char c)
|
||||
{
|
||||
|
@ -33,16 +33,20 @@ static void expand_append (char **dst, size_t *sz, size_t *pos, char c)
|
|||
(*pos)++;
|
||||
}
|
||||
|
||||
static char *expand_env (const char *name, char op, const char *alt, expand_fn expand)
|
||||
static char *expand_env (const char *name, char op, const char *alt, expand_fn expand, uint32_t domid)
|
||||
{
|
||||
char pidstr[20];
|
||||
char idstr[20];
|
||||
char *env = NULL;
|
||||
dds_return_t ret;
|
||||
|
||||
if (name[0] == '$' && name[1] == 0) {
|
||||
snprintf (pidstr, sizeof (pidstr), "%"PRIdPID, ddsrt_getpid ());
|
||||
env = pidstr;
|
||||
} else {
|
||||
(void) ddsrt_getenv (name, &env);
|
||||
if ((ret = ddsrt_getenv (name, &env)) == DDS_RETCODE_OK) {
|
||||
/* ok */
|
||||
} else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) {
|
||||
snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ());
|
||||
env = idstr;
|
||||
} else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0) {
|
||||
snprintf (idstr, sizeof (idstr), "%"PRIu32, domid);
|
||||
env = idstr;
|
||||
}
|
||||
|
||||
switch (op)
|
||||
|
@ -50,25 +54,25 @@ static char *expand_env (const char *name, char op, const char *alt, expand_fn e
|
|||
case 0:
|
||||
return ddsrt_strdup (env ? env : "");
|
||||
case '-':
|
||||
return env && *env ? ddsrt_strdup (env) : expand (alt);
|
||||
return env && *env ? ddsrt_strdup (env) : expand (alt, domid);
|
||||
case '?':
|
||||
if (env && *env) {
|
||||
return ddsrt_strdup (env);
|
||||
} else {
|
||||
char *altx = expand (alt);
|
||||
DDS_ERROR("%s: %s\n", name, altx);
|
||||
char *altx = expand (alt, domid);
|
||||
DDS_ILOG (DDS_LC_ERROR, domid, "%s: %s\n", name, altx);
|
||||
ddsrt_free (altx);
|
||||
return NULL;
|
||||
}
|
||||
case '+':
|
||||
return env && *env ? expand (alt) : ddsrt_strdup ("");
|
||||
return env && *env ? expand (alt, domid) : ddsrt_strdup ("");
|
||||
default:
|
||||
abort ();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static char *expand_envbrace (const char **src, expand_fn expand)
|
||||
static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid)
|
||||
{
|
||||
const char *start = *src + 1;
|
||||
char *name, *x;
|
||||
|
@ -85,7 +89,7 @@ static char *expand_envbrace (const char **src, expand_fn expand)
|
|||
name[*src - start] = 0;
|
||||
if (**src == '}') {
|
||||
(*src)++;
|
||||
x = expand_env (name, 0, NULL, expand);
|
||||
x = expand_env (name, 0, NULL, expand, domid);
|
||||
ddsrt_free (name);
|
||||
return x;
|
||||
} else {
|
||||
|
@ -129,7 +133,7 @@ static char *expand_envbrace (const char **src, expand_fn expand)
|
|||
memcpy (alt, altstart, (size_t) (*src - altstart));
|
||||
alt[*src - altstart] = 0;
|
||||
(*src)++;
|
||||
x = expand_env (name, op, alt, expand);
|
||||
x = expand_env (name, op, alt, expand, domid);
|
||||
ddsrt_free (alt);
|
||||
ddsrt_free (name);
|
||||
return x;
|
||||
|
@ -139,7 +143,7 @@ err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static char *expand_envsimple (const char **src, expand_fn expand)
|
||||
static char *expand_envsimple (const char **src, expand_fn expand, uint32_t domid)
|
||||
{
|
||||
const char *start = *src;
|
||||
char *name, *x;
|
||||
|
@ -150,22 +154,22 @@ static char *expand_envsimple (const char **src, expand_fn expand)
|
|||
name = ddsrt_malloc ((size_t) (*src - start) + 1);
|
||||
memcpy (name, start, (size_t) (*src - start));
|
||||
name[*src - start] = 0;
|
||||
x = expand_env (name, 0, NULL, expand);
|
||||
x = expand_env (name, 0, NULL, expand, domid);
|
||||
ddsrt_free (name);
|
||||
return x;
|
||||
}
|
||||
|
||||
static char *expand_envchar (const char **src, expand_fn expand)
|
||||
static char *expand_envchar (const char **src, expand_fn expand, uint32_t domid)
|
||||
{
|
||||
char name[2];
|
||||
assert (**src);
|
||||
name[0] = **src;
|
||||
name[1] = 0;
|
||||
(*src)++;
|
||||
return expand_env (name, 0, NULL, expand);
|
||||
return expand_env (name, 0, NULL, expand, domid);
|
||||
}
|
||||
|
||||
char *ddsrt_expand_envvars_sh (const char *src0)
|
||||
char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid)
|
||||
{
|
||||
/* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */
|
||||
const char *src = src0;
|
||||
|
@ -188,11 +192,11 @@ char *ddsrt_expand_envvars_sh (const char *src0)
|
|||
ddsrt_free(dst);
|
||||
return NULL;
|
||||
} else if (*src == '{') {
|
||||
x = expand_envbrace (&src, &ddsrt_expand_envvars_sh);
|
||||
x = expand_envbrace (&src, &ddsrt_expand_envvars_sh, domid);
|
||||
} else if (isalnum ((unsigned char) *src) || *src == '_') {
|
||||
x = expand_envsimple (&src, &ddsrt_expand_envvars_sh);
|
||||
x = expand_envsimple (&src, &ddsrt_expand_envvars_sh, domid);
|
||||
} else {
|
||||
x = expand_envchar (&src, &ddsrt_expand_envvars_sh);
|
||||
x = expand_envchar (&src, &ddsrt_expand_envvars_sh, domid);
|
||||
}
|
||||
if (x == NULL) {
|
||||
ddsrt_free(dst);
|
||||
|
@ -211,7 +215,7 @@ char *ddsrt_expand_envvars_sh (const char *src0)
|
|||
return dst;
|
||||
}
|
||||
|
||||
char *ddsrt_expand_envvars (const char *src0)
|
||||
char *ddsrt_expand_envvars (const char *src0, uint32_t domid)
|
||||
{
|
||||
/* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */
|
||||
const char *src = src0;
|
||||
|
@ -221,7 +225,7 @@ char *ddsrt_expand_envvars (const char *src0)
|
|||
if (*src == '$' && *(src + 1) == '{') {
|
||||
char *x, *xp;
|
||||
src++;
|
||||
x = expand_envbrace (&src, &ddsrt_expand_envvars);
|
||||
x = expand_envbrace (&src, &ddsrt_expand_envvars, domid);
|
||||
if (x == NULL) {
|
||||
ddsrt_free(dst);
|
||||
return NULL;
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
#include "dds/ddsrt/log.h"
|
||||
#include "dds/ddsrt/sync.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/static_assert.h"
|
||||
|
||||
#define MAX_ID_LEN (10)
|
||||
#define MAX_TIMESTAMP_LEN (10 + 1 + 6)
|
||||
#define MAX_TID_LEN (10)
|
||||
#define HDR_LEN (MAX_TIMESTAMP_LEN + 1 + MAX_TID_LEN + 2)
|
||||
#define HDR_LEN (MAX_TIMESTAMP_LEN + 2 + MAX_ID_LEN + 2 + MAX_TID_LEN + 2)
|
||||
|
||||
#define BUF_OFFSET HDR_LEN
|
||||
|
||||
|
@ -41,18 +43,23 @@ static ddsrt_thread_local log_buffer_t log_buffer;
|
|||
static ddsrt_once_t lock_inited = DDSRT_ONCE_INIT;
|
||||
static ddsrt_rwlock_t lock;
|
||||
|
||||
static uint32_t log_mask = DDS_LC_ERROR | DDS_LC_WARNING;
|
||||
struct ddsrt_log_cfg_impl {
|
||||
struct ddsrt_log_cfg_common c;
|
||||
FILE *sink_fps[2];
|
||||
};
|
||||
|
||||
static void default_sink(void *ptr, const dds_log_data_t *data)
|
||||
DDSRT_STATIC_ASSERT (sizeof (struct ddsrt_log_cfg_impl) <= sizeof (struct ddsrt_log_cfg));
|
||||
|
||||
static void default_sink (void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
fwrite(data->message - HDR_LEN, 1, HDR_LEN + data->size + 1, (FILE *)ptr);
|
||||
fflush((FILE *)ptr);
|
||||
fwrite (data->message - data->hdrsize, 1, data->hdrsize + data->size + 1, (FILE *) ptr);
|
||||
fflush ((FILE *) ptr);
|
||||
}
|
||||
|
||||
static void nop_sink(void *ptr, const dds_log_data_t *data)
|
||||
static void nop_sink (void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)data;
|
||||
(void) ptr;
|
||||
(void) data;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,30 +68,38 @@ static void nop_sink(void *ptr, const dds_log_data_t *data)
|
|||
#define USE (0)
|
||||
#define SET (1)
|
||||
|
||||
static log_sink_t sinks[] = {
|
||||
/* Log */
|
||||
{ .funcs = { default_sink, default_sink }, .ptr = NULL, .out = NULL },
|
||||
/* Trace */
|
||||
{ .funcs = { nop_sink, default_sink }, .ptr = NULL, .out = NULL }
|
||||
static struct ddsrt_log_cfg_impl logconfig = {
|
||||
.c = {
|
||||
.mask = DDS_LC_ERROR | DDS_LC_WARNING,
|
||||
.domid = UINT32_MAX
|
||||
},
|
||||
.sink_fps = {
|
||||
[LOG] = NULL,
|
||||
[TRACE] = NULL
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t *const dds_log_mask = &log_mask;
|
||||
static log_sink_t sinks[2] = {
|
||||
[LOG] = { .funcs = { [USE] = default_sink, [SET] = default_sink }, .ptr = NULL, .out = NULL },
|
||||
[TRACE] = { .funcs = { [USE] = default_sink, [SET] = default_sink }, .ptr = NULL, .out = NULL }
|
||||
};
|
||||
|
||||
#define RDLOCK (1)
|
||||
#define WRLOCK (2)
|
||||
uint32_t *const dds_log_mask = &logconfig.c.mask;
|
||||
|
||||
static void init_lock(void)
|
||||
static void init_lock (void)
|
||||
{
|
||||
ddsrt_rwlock_init(&lock);
|
||||
ddsrt_rwlock_init (&lock);
|
||||
sinks[LOG].ptr = sinks[TRACE].ptr = stderr;
|
||||
sinks[LOG].out = sinks[TRACE].out = stderr;
|
||||
logconfig.sink_fps[LOG] = sinks[LOG].ptr;
|
||||
logconfig.sink_fps[TRACE] = sinks[TRACE].ptr;
|
||||
}
|
||||
|
||||
static void lock_sink(int type)
|
||||
{
|
||||
assert(type == RDLOCK || type == WRLOCK);
|
||||
ddsrt_once(&lock_inited, &init_lock);
|
||||
enum lock_type { RDLOCK, WRLOCK };
|
||||
|
||||
static void lock_sink (enum lock_type type)
|
||||
{
|
||||
ddsrt_once (&lock_inited, &init_lock);
|
||||
if (type == RDLOCK) {
|
||||
ddsrt_rwlock_read(&lock);
|
||||
} else {
|
||||
|
@ -92,143 +107,136 @@ static void lock_sink(int type)
|
|||
}
|
||||
}
|
||||
|
||||
static void unlock_sink(void)
|
||||
static void unlock_sink (void)
|
||||
{
|
||||
ddsrt_rwlock_unlock(&lock);
|
||||
ddsrt_rwlock_unlock (&lock);
|
||||
}
|
||||
|
||||
static void set_active_log_sinks(void)
|
||||
static void set_active_log_sinks (void)
|
||||
{
|
||||
if (dds_get_log_mask() & DDS_LOG_MASK) {
|
||||
sinks[LOG].funcs[USE] = sinks[LOG].funcs[SET];
|
||||
} else {
|
||||
sinks[LOG].funcs[USE] = nop_sink;
|
||||
}
|
||||
if (dds_get_log_mask() & DDS_TRACE_MASK) {
|
||||
sinks[TRACE].funcs[USE] = sinks[TRACE].funcs[SET];
|
||||
} else {
|
||||
sinks[TRACE].funcs[USE] = nop_sink;
|
||||
}
|
||||
if (sinks[LOG].funcs[USE] == sinks[TRACE].funcs[USE] &&
|
||||
sinks[LOG].ptr == sinks[TRACE].ptr)
|
||||
sinks[LOG].funcs[USE] = sinks[LOG].funcs[SET];
|
||||
sinks[TRACE].funcs[USE] = sinks[TRACE].funcs[SET];
|
||||
if (sinks[LOG].funcs[USE] == sinks[TRACE].funcs[USE])
|
||||
{
|
||||
sinks[LOG].funcs[USE] = nop_sink;
|
||||
if (sinks[LOG].funcs[USE] != default_sink && sinks[LOG].ptr == sinks[TRACE].ptr)
|
||||
sinks[LOG].funcs[USE] = nop_sink;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_log_sink(
|
||||
log_sink_t *sink,
|
||||
dds_log_write_fn_t func,
|
||||
void *ptr)
|
||||
static void set_log_sink (log_sink_t *sink, dds_log_write_fn_t func, void *ptr)
|
||||
{
|
||||
assert(sink != NULL);
|
||||
assert (sink != NULL);
|
||||
assert (sink == &sinks[0] || sink == &sinks[1]);
|
||||
|
||||
/* No life cycle management is done for log sinks, the caller is
|
||||
responsible for that. Ensure this operation is deterministic and that on
|
||||
return, no thread in the DDS stack still uses the deprecated sink. */
|
||||
lock_sink(WRLOCK);
|
||||
|
||||
if (func == 0) {
|
||||
sink->funcs[SET] = default_sink;
|
||||
sink->ptr = sink->out;
|
||||
} else {
|
||||
sink->funcs[SET] = func;
|
||||
sink->ptr = ptr;
|
||||
}
|
||||
|
||||
set_active_log_sinks();
|
||||
unlock_sink();
|
||||
lock_sink (WRLOCK);
|
||||
sink->funcs[SET] = (func != 0) ? func : default_sink;
|
||||
sink->ptr = ptr;
|
||||
set_active_log_sinks ();
|
||||
unlock_sink ();
|
||||
}
|
||||
|
||||
/* dds_set_log_file must be considered private. */
|
||||
void dds_set_log_file(FILE *file)
|
||||
void dds_set_log_file (FILE *file)
|
||||
{
|
||||
lock_sink(WRLOCK);
|
||||
sinks[LOG].out = (file == NULL ? stderr : file);
|
||||
if (sinks[LOG].funcs[SET] == default_sink) {
|
||||
sinks[LOG].ptr = sinks[LOG].out;
|
||||
}
|
||||
set_active_log_sinks();
|
||||
unlock_sink();
|
||||
lock_sink (WRLOCK);
|
||||
logconfig.sink_fps[LOG] = (file == NULL ? stderr : file);
|
||||
set_active_log_sinks ();
|
||||
unlock_sink ();
|
||||
}
|
||||
|
||||
void dds_set_trace_file(FILE *file)
|
||||
void dds_set_trace_file (FILE *file)
|
||||
{
|
||||
lock_sink(WRLOCK);
|
||||
sinks[TRACE].out = (file == NULL ? stderr : file);
|
||||
if (sinks[TRACE].funcs[SET] == default_sink) {
|
||||
sinks[TRACE].ptr = sinks[TRACE].out;
|
||||
}
|
||||
set_active_log_sinks();
|
||||
unlock_sink();
|
||||
lock_sink (WRLOCK);
|
||||
logconfig.sink_fps[TRACE] = (file == NULL ? stderr : file);
|
||||
set_active_log_sinks ();
|
||||
unlock_sink ();
|
||||
}
|
||||
|
||||
void dds_set_log_sink(
|
||||
dds_log_write_fn_t callback,
|
||||
void *userdata)
|
||||
void dds_set_log_sink (dds_log_write_fn_t callback, void *userdata)
|
||||
{
|
||||
set_log_sink(&sinks[LOG], callback, userdata);
|
||||
set_log_sink (&sinks[LOG], callback, userdata);
|
||||
}
|
||||
|
||||
void dds_set_trace_sink(
|
||||
dds_log_write_fn_t callback,
|
||||
void *userdata)
|
||||
void dds_set_trace_sink (dds_log_write_fn_t callback, void *userdata)
|
||||
{
|
||||
set_log_sink(&sinks[TRACE], callback, userdata);
|
||||
set_log_sink (&sinks[TRACE], callback, userdata);
|
||||
}
|
||||
|
||||
extern inline uint32_t
|
||||
dds_get_log_mask(void);
|
||||
extern inline uint32_t dds_get_log_mask (void);
|
||||
|
||||
void
|
||||
dds_set_log_mask(uint32_t cats)
|
||||
void dds_set_log_mask (uint32_t cats)
|
||||
{
|
||||
lock_sink(WRLOCK);
|
||||
lock_sink (WRLOCK);
|
||||
*dds_log_mask = (cats & (DDS_LOG_MASK | DDS_TRACE_MASK));
|
||||
set_active_log_sinks();
|
||||
unlock_sink();
|
||||
set_active_log_sinks ();
|
||||
unlock_sink ();
|
||||
}
|
||||
|
||||
static void print_header(char *str)
|
||||
void dds_log_cfg_init (struct ddsrt_log_cfg *cfg, uint32_t domid, uint32_t mask, FILE *log_fp, FILE *trace_fp)
|
||||
{
|
||||
int cnt;
|
||||
struct ddsrt_log_cfg_impl *cfgimpl = (struct ddsrt_log_cfg_impl *) cfg;
|
||||
assert (domid != UINT32_MAX); /* because that's reserved for global use */
|
||||
memset (cfgimpl, 0, sizeof (*cfgimpl));
|
||||
cfgimpl->c.mask = mask;
|
||||
cfgimpl->c.domid = domid;
|
||||
cfgimpl->sink_fps[LOG] = log_fp;
|
||||
cfgimpl->sink_fps[TRACE] = trace_fp;
|
||||
}
|
||||
|
||||
static size_t print_header (char *str, uint32_t id)
|
||||
{
|
||||
int cnt, off;
|
||||
char *tid, buf[MAX_TID_LEN+1] = { 0 };
|
||||
static const char fmt[] = "%10u.%06d/%*.*s:";
|
||||
static const char fmt_no_id[] = "%10u.%06d [] %*.*s:";
|
||||
static const char fmt_with_id[] = "%10u.%06d [%"PRIu32"] %*.*s:";
|
||||
dds_time_t time;
|
||||
unsigned sec;
|
||||
int usec;
|
||||
|
||||
(void)ddsrt_thread_getname(buf, sizeof(buf));
|
||||
(void) ddsrt_thread_getname (buf, sizeof (buf));
|
||||
tid = (buf[0] == '\0' ? "(anon)" : buf);
|
||||
time = dds_time();
|
||||
sec = (unsigned)(time / DDS_NSECS_IN_SEC);
|
||||
usec = (int)((time % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC);
|
||||
time = dds_time ();
|
||||
sec = (unsigned) (time / DDS_NSECS_IN_SEC);
|
||||
usec = (int) ((time % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC);
|
||||
|
||||
cnt = snprintf(
|
||||
str, HDR_LEN, fmt, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid);
|
||||
assert(cnt == (HDR_LEN - 1));
|
||||
str[cnt] = ' '; /* Replace snprintf null byte by space. */
|
||||
if (id == UINT32_MAX)
|
||||
{
|
||||
off = MAX_ID_LEN;
|
||||
cnt = snprintf (str + off, HDR_LEN, fmt_no_id, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* low domain ids tend to be most used from what I have seen */
|
||||
off = 9;
|
||||
if (id >= 10)
|
||||
for (uint32_t thres = 10; off > 0 && id >= thres; off--, thres *= 10);
|
||||
cnt = snprintf (str + off, HDR_LEN, fmt_with_id, sec, usec, id, MAX_TID_LEN, MAX_TID_LEN, tid);
|
||||
}
|
||||
assert (off + cnt == (HDR_LEN - 1));
|
||||
str[off + cnt] = ' '; /* Replace snprintf null byte by space. */
|
||||
return (size_t) cnt;
|
||||
}
|
||||
|
||||
static void vlog(
|
||||
uint32_t cat,
|
||||
const char *file,
|
||||
uint32_t line,
|
||||
const char *func,
|
||||
const char *fmt,
|
||||
va_list ap)
|
||||
static void vlog (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t domid, const char *file, uint32_t line, const char *func, const char *fmt, va_list ap)
|
||||
{
|
||||
int n, trunc = 0;
|
||||
size_t nrem;
|
||||
log_buffer_t *lb;
|
||||
dds_log_data_t data;
|
||||
|
||||
/* id can be used to override the id in logconfig, so that the global
|
||||
logging configuration can be used for reporting errors while inlcuding
|
||||
a domain id. This simply verifies that the id override is only ever
|
||||
used with the global one. */
|
||||
assert (domid == cfg->c.domid || cfg == &logconfig);
|
||||
|
||||
if (*fmt == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock_sink(RDLOCK);
|
||||
lb = &log_buffer;
|
||||
|
||||
/* Thread-local buffer is always initialized with all zeroes. The pos
|
||||
|
@ -239,7 +247,7 @@ static void vlog(
|
|||
}
|
||||
nrem = sizeof (lb->buf) - lb->pos;
|
||||
if (nrem > 0) {
|
||||
n = vsnprintf(lb->buf + lb->pos, nrem, fmt, ap);
|
||||
n = vsnprintf (lb->buf + lb->pos, nrem, fmt, ap);
|
||||
if (n >= 0 && (size_t) n < nrem) {
|
||||
lb->pos += (size_t) n;
|
||||
} else {
|
||||
|
@ -249,14 +257,14 @@ static void vlog(
|
|||
if (trunc) {
|
||||
static const char msg[] = "(trunc)\n";
|
||||
const size_t msglen = sizeof (msg) - 1;
|
||||
assert(lb->pos <= sizeof (lb->buf));
|
||||
assert(lb->pos >= msglen);
|
||||
memcpy(lb->buf + lb->pos - msglen, msg, msglen);
|
||||
assert (lb->pos <= sizeof (lb->buf));
|
||||
assert (lb->pos >= msglen);
|
||||
memcpy (lb->buf + lb->pos - msglen, msg, msglen);
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt[strlen (fmt) - 1] == '\n') {
|
||||
print_header(lb->buf);
|
||||
size_t hdrsize = print_header (lb->buf, domid);
|
||||
|
||||
data.priority = cat;
|
||||
data.file = file;
|
||||
|
@ -264,39 +272,83 @@ static void vlog(
|
|||
data.line = line;
|
||||
data.message = lb->buf + BUF_OFFSET;
|
||||
data.size = strlen(data.message) - 1;
|
||||
data.hdrsize = hdrsize;
|
||||
|
||||
dds_log_write_fn_t f = 0;
|
||||
void *f_arg = NULL;
|
||||
for (size_t i = (cat & DDS_LOG_MASK) ? LOG : TRACE;
|
||||
i < sizeof(sinks) / sizeof(sinks[0]);
|
||||
i < sizeof (sinks) / sizeof (sinks[0]);
|
||||
i++)
|
||||
{
|
||||
sinks[i].funcs[USE](sinks[i].ptr, &data);
|
||||
if (sinks[i].funcs[USE] != default_sink) {
|
||||
if (sinks[i].funcs[USE] != f || sinks[i].ptr != f_arg) {
|
||||
assert (sinks[i].funcs[USE]);
|
||||
sinks[i].funcs[USE] (sinks[i].ptr, &data);
|
||||
f = sinks[i].funcs[USE]; f_arg = sinks[i].ptr;
|
||||
}
|
||||
} else if (cfg->sink_fps[i]) {
|
||||
if (default_sink != f || cfg->sink_fps[i] != f_arg) {
|
||||
default_sink (cfg->sink_fps[i], &data);
|
||||
f = default_sink; f_arg = cfg->sink_fps[i];
|
||||
}
|
||||
} else if (logconfig.sink_fps[i]) {
|
||||
if (default_sink != f || logconfig.sink_fps[i] != f_arg) {
|
||||
default_sink (logconfig.sink_fps[i], &data);
|
||||
f = default_sink; f_arg = logconfig.sink_fps[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lb->pos = BUF_OFFSET;
|
||||
lb->buf[lb->pos] = 0;
|
||||
}
|
||||
|
||||
unlock_sink();
|
||||
}
|
||||
|
||||
int
|
||||
dds_log(
|
||||
uint32_t cat,
|
||||
const char *file,
|
||||
uint32_t line,
|
||||
const char *func,
|
||||
const char *fmt,
|
||||
...)
|
||||
int dds_log_cfg (const struct ddsrt_log_cfg *cfg, uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...)
|
||||
{
|
||||
if ((dds_get_log_mask() & cat) || (cat & DDS_LC_FATAL)) {
|
||||
const struct ddsrt_log_cfg_impl *cfgimpl = (const struct ddsrt_log_cfg_impl *) cfg;
|
||||
if ((cfgimpl->c.mask & cat) || (cat & DDS_LC_FATAL)) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vlog(cat, file, line, func, fmt, ap);
|
||||
va_end(ap);
|
||||
va_start (ap, fmt);
|
||||
lock_sink (RDLOCK);
|
||||
vlog (cfgimpl, cat, cfgimpl->c.domid, file, line, func, fmt, ap);
|
||||
unlock_sink ();
|
||||
va_end (ap);
|
||||
}
|
||||
if (cat & DDS_LC_FATAL) {
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dds_log_id (uint32_t cat, uint32_t id, const char *file, uint32_t line, const char *func, const char *fmt, ...)
|
||||
{
|
||||
if ((dds_get_log_mask () & cat) || (cat & DDS_LC_FATAL)) {
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
lock_sink (RDLOCK);
|
||||
vlog (&logconfig, cat, id, file, line, func, fmt, ap);
|
||||
unlock_sink ();
|
||||
va_end (ap);
|
||||
}
|
||||
if (cat & DDS_LC_FATAL) {
|
||||
abort ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dds_log (uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...)
|
||||
{
|
||||
if ((dds_get_log_mask () & cat) || (cat & DDS_LC_FATAL)) {
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
lock_sink (RDLOCK);
|
||||
vlog (&logconfig, cat, UINT32_MAX, file, line, func, fmt, ap);
|
||||
unlock_sink ();
|
||||
va_end (ap);
|
||||
}
|
||||
if (cat & DDS_LC_FATAL) {
|
||||
abort ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -302,7 +302,6 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
|
|||
|
||||
NOTE: Error codes returned by getaddrinfo map directly onto Windows
|
||||
Socket error codes and WSAGetLastError can be used instead. */
|
||||
DDS_TRACE("getaddrinfo for %s returned %d\n", name, gai_err);
|
||||
switch (gai_err) {
|
||||
#if defined(EAI_AGAIN)
|
||||
case EAI_AGAIN:
|
||||
|
@ -371,7 +370,7 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp)
|
|||
freeaddrinfo(res);
|
||||
} break;
|
||||
default:
|
||||
DDS_ERROR("getaddrinfo returned unkown error %d\n", gai_err);
|
||||
DDS_ERROR ("getaddrinfo returned unkown error %d\n", gai_err);
|
||||
return DDS_RETCODE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand)
|
|||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
/* Expand a string with available environment variables. */
|
||||
ptr = ddsrt_expand_envvars(var);
|
||||
ptr = ddsrt_expand_envvars(var,UINT32_MAX);
|
||||
if (ptr) {
|
||||
/* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
|
||||
CU_ASSERT_STRING_EQUAL(ptr, expect);
|
||||
|
@ -183,7 +183,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh)
|
|||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
/* Expand a string with available environment variables. */
|
||||
ptr = ddsrt_expand_envvars_sh(var);
|
||||
ptr = ddsrt_expand_envvars_sh(var,UINT32_MAX);
|
||||
if (ptr) {
|
||||
/* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */
|
||||
CU_ASSERT_STRING_EQUAL(ptr, expect);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue