Make logging config per-domain

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2019-07-17 22:03:19 +02:00 committed by eboasson
parent 7190bb3d3e
commit 966ec0dda7
70 changed files with 2052 additions and 1718 deletions

View file

@ -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)

View file

@ -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)
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);