log: dynamically load the logger API

This commit is contained in:
Wim Taymans 2017-06-06 16:53:16 +02:00
parent b4fdcbd322
commit 0af8377d10
14 changed files with 134 additions and 200 deletions

View file

@ -37,6 +37,8 @@
struct context { struct context {
struct pw_context this; struct pw_context this;
struct spa_support support[3];
bool no_proxy; bool no_proxy;
int fd; int fd;
@ -437,10 +439,20 @@ struct pw_context *pw_context_new(struct pw_loop *loop,
pw_fill_context_properties(properties); pw_fill_context_properties(properties);
this->properties = properties; this->properties = properties;
this->loop = loop;
pw_type_init(&this->type); pw_type_init(&this->type);
spa_debug_set_type_map(this->type.map); spa_debug_set_type_map(this->type.map);
this->loop = loop; impl->support[0].type = SPA_TYPE__TypeMap;
impl->support[0].data = this->type.map;
impl->support[1].type = SPA_TYPE_LOOP__MainLoop;
impl->support[1].data = this->loop->loop;
impl->support[2].type = SPA_TYPE__Log;
impl->support[2].data = pw_log_get(impl->support, 2);
this->support = impl->support;
this->n_support = 3;
impl->flush_event = pw_loop_add_event(loop, do_flush_event, impl); impl->flush_event = pw_loop_add_event(loop, do_flush_event, impl);

View file

@ -144,6 +144,9 @@ struct pw_context {
struct pw_loop *loop; /**< the loop */ struct pw_loop *loop; /**< the loop */
struct spa_support *support; /**< support for spa plugins */
uint32_t n_support; /**< number of support items */
struct pw_proxy *core_proxy; /**< proxy for the core object */ struct pw_proxy *core_proxy; /**< proxy for the core object */
struct pw_proxy *registry_proxy; /**< proxy for the registry object. Can struct pw_proxy *registry_proxy; /**< proxy for the registry object. Can
* be NULL when \ref PW_CONTEXT_FLAG_NO_PROXY * be NULL when \ref PW_CONTEXT_FLAG_NO_PROXY

View file

@ -20,147 +20,100 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/eventfd.h> #include <dlfcn.h>
#include <spa/ringbuffer.h> #include <spa/log.h>
#include <pipewire/client/log.h> #include <pipewire/client/log.h>
#include <pipewire/client/type.h>
#define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_ERROR #define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_ERROR
enum spa_log_level pw_log_level = DEFAULT_LOG_LEVEL; enum spa_log_level pw_log_level = DEFAULT_LOG_LEVEL;
/** \cond */ static struct spa_log *global_log = NULL;
#define TRACE_BUFFER (16*1024)
struct debug_log { struct spa_log *pw_spa_log_load(const char *lib,
struct spa_log log; const char *factory_name,
struct spa_ringbuffer trace_rb; struct spa_support *support,
uint8_t trace_data[TRACE_BUFFER]; uint32_t n_support)
bool have_source;
struct spa_source source;
};
/** \endcond */
static void
do_logv(struct spa_log *log,
enum spa_log_level level,
const char *file,
int line,
const char *func,
const char *fmt,
va_list args)
{ {
struct debug_log *l = SPA_CONTAINER_OF(log, struct debug_log, log); int res;
char text[1024], location[1024]; struct spa_handle *handle;
static const char *levels[] = { "-", "E", "W", "I", "D", "T", "*T*" }; void *hnd;
int size; uint32_t index, type_log;
bool do_trace; spa_handle_factory_enum_func_t enum_func;
const struct spa_handle_factory *factory;
void *iface;
struct spa_type_map *map = NULL;
vsnprintf(text, sizeof(text), fmt, args); for (index = 0; index < n_support; index++) {
if (strcmp(support[index].type, SPA_TYPE__TypeMap) == 0)
map = support[index].data;
}
if (map == NULL) {
fprintf(stderr, "no type map");
return NULL;
}
if ((do_trace = (level == SPA_LOG_LEVEL_TRACE && l->have_source))) type_log = spa_type_map_get_id(map, SPA_TYPE__Log);
level++;
size = snprintf(location, sizeof(location), "[%s][%s:%i %s()] %s\n", if ((hnd = dlopen(lib, RTLD_NOW)) == NULL) {
levels[level], strrchr(file, '/') + 1, line, func, text); fprintf(stderr, "can't load %s: %s", lib, dlerror());
return NULL;
}
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
fprintf(stderr, "can't find enum function");
goto no_symbol;
}
if (SPA_UNLIKELY(do_trace)) { for (index = 0;; index++) {
uint32_t index; if ((res = enum_func(&factory, index)) < 0) {
uint64_t count = 1; if (res != SPA_RESULT_ENUM_END)
fprintf(stderr, "can't enumerate factories: %d", res);
goto enum_failed;
}
if (strcmp(factory->name, factory_name) == 0)
break;
}
spa_ringbuffer_get_write_index(&l->trace_rb, &index); handle = calloc(1, factory->size);
spa_ringbuffer_write_data(&l->trace_rb, l->trace_data, if ((res = spa_handle_factory_init(factory,
index & l->trace_rb.mask, location, size); handle, NULL, support, n_support)) < 0) {
spa_ringbuffer_write_update(&l->trace_rb, index + size); fprintf(stderr, "can't make factory instance: %d", res);
goto init_failed;
}
if ((res = spa_handle_get_interface(handle, type_log, &iface)) < 0) {
fprintf(stderr, "can't get log interface %d", res);
goto interface_failed;
}
return iface;
write(l->source.fd, &count, sizeof(uint64_t)); interface_failed:
} else spa_handle_clear(handle);
fputs(location, stdout); init_failed:
free(handle);
enum_failed:
no_symbol:
dlclose(hnd);
return NULL;
} }
static void
do_log(struct spa_log *log,
enum spa_log_level level,
const char *file,
int line,
const char *func,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
do_logv(log, level, file, line, func, fmt, args);
va_end(args);
}
static void on_trace_event(struct spa_source *source)
{
struct debug_log *l = source->data;
int32_t avail;
uint32_t index;
uint64_t count;
if (read(source->fd, &count, sizeof(uint64_t)) != sizeof(uint64_t))
fprintf(stderr, "failed to read event fd: %s", strerror(errno));
while ((avail = spa_ringbuffer_get_read_index(&l->trace_rb, &index)) > 0) {
uint32_t offset, first;
if (avail > l->trace_rb.size) {
fprintf(stderr, "\n** trace overflow ** %d\n", avail);
index += avail - l->trace_rb.size;
avail = l->trace_rb.size;
}
offset = index & l->trace_rb.mask;
first = SPA_MIN(avail, l->trace_rb.size - offset);
fwrite(l->trace_data + offset, first, 1, stderr);
if (SPA_UNLIKELY(avail > first)) {
fwrite(l->trace_data, avail - first, 1, stderr);
}
spa_ringbuffer_read_update(&l->trace_rb, index + avail);
}
}
static void
do_set_loop(struct spa_log *log, struct spa_loop *loop)
{
struct debug_log *l = SPA_CONTAINER_OF(log, struct debug_log, log);
if (l->have_source) {
spa_loop_remove_source(l->source.loop, &l->source);
close(l->source.fd);
l->have_source = false;
}
if (loop) {
l->source.func = on_trace_event;
l->source.data = l;
l->source.fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
l->source.mask = SPA_IO_IN;
l->source.rmask = 0;
spa_loop_add_source(loop, &l->source);
l->have_source = true;
}
}
static struct debug_log log = {
{sizeof(struct spa_log),
NULL,
DEFAULT_LOG_LEVEL,
do_log,
do_logv,
do_set_loop,
},
{0, 0, TRACE_BUFFER, TRACE_BUFFER - 1},
};
/** Get the global log interface /** Get the global log interface
* \return the global log * \return the global log
* \memberof pw_log * \memberof pw_log
*/ */
struct spa_log *pw_log_get(void) struct spa_log *pw_log_get(struct spa_support *support,
uint32_t n_support)
{ {
return &log.log; if (global_log == NULL) {
global_log = pw_spa_log_load("build/spa/plugins/logger/libspa-logger.so",
"logger",
support,
n_support);
global_log->level = pw_log_level;
}
return global_log;
} }
/** Set the global log level /** Set the global log level
@ -170,19 +123,8 @@ struct spa_log *pw_log_get(void)
void pw_log_set_level(enum spa_log_level level) void pw_log_set_level(enum spa_log_level level)
{ {
pw_log_level = level; pw_log_level = level;
log.log.level = level; if (global_log)
} global_log->level = level;
/** Set the trace loop
* \param loop the trace loop
*
* Trace logging will be done in this loop.
*
* \memberof pw_log
*/
void pw_log_set_loop(struct spa_loop *loop)
{
do_set_loop(&log.log, loop);
} }
/** Log a message /** Log a message
@ -202,10 +144,10 @@ pw_log_log(enum spa_log_level level,
const char *func, const char *func,
const char *fmt, ...) const char *fmt, ...)
{ {
if (SPA_UNLIKELY(pw_log_level_enabled(level))) { if (SPA_UNLIKELY(pw_log_level_enabled(level) && global_log)) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
do_logv(&log.log, level, file, line, func, fmt, args); global_log->logv(global_log, level, file, line, func, fmt, args);
va_end(args); va_end(args);
} }
} }
@ -228,8 +170,8 @@ pw_log_logv(enum spa_log_level level,
const char *fmt, const char *fmt,
va_list args) va_list args)
{ {
if (SPA_UNLIKELY(pw_log_level_enabled(level))) { if (SPA_UNLIKELY(pw_log_level_enabled(level) && global_log)) {
do_logv(&log.log, level, file, line, func, fmt, args); global_log->logv(global_log, level, file, line, func, fmt, args);
} }
} }

View file

@ -39,14 +39,11 @@ extern "C" {
/** The global log level */ /** The global log level */
extern enum spa_log_level pw_log_level; extern enum spa_log_level pw_log_level;
struct spa_log *pw_log_get(void); struct spa_log *pw_log_get(struct spa_support *support, uint32_t n_support);
void void
pw_log_set_level(enum spa_log_level level); pw_log_set_level(enum spa_log_level level);
void
pw_log_set_loop(struct spa_loop *loop);
void void
pw_log_log(enum spa_log_level level, pw_log_log(enum spa_log_level level,

View file

@ -58,7 +58,7 @@ libpipewire = shared_library('pipewire', pipewire_sources,
include_directories : [configinc, spa_inc], include_directories : [configinc, spa_inc],
link_with : spalib, link_with : spalib,
install : true, install : true,
dependencies : [dbus_dep, mathlib, pthread_lib], dependencies : [dbus_dep, dl_lib, mathlib, pthread_lib],
) )
pipewire_dep = declare_dependency(link_with : libpipewire, pipewire_dep = declare_dependency(link_with : libpipewire,

View file

@ -67,7 +67,7 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context, uint32_t id, uint32_t
spa_list_insert(&this->context->proxy_list, &this->link); spa_list_insert(&this->context->proxy_list, &this->link);
pw_log_trace("proxy %p: new %u", this, this->id); pw_log_debug("proxy %p: new %u", this, this->id);
return this; return this;
@ -89,7 +89,7 @@ void pw_proxy_destroy(struct pw_proxy *proxy)
{ {
struct proxy *impl = SPA_CONTAINER_OF(proxy, struct proxy, this); struct proxy *impl = SPA_CONTAINER_OF(proxy, struct proxy, this);
pw_log_trace("proxy %p: destroy %u", proxy, proxy->id); pw_log_debug("proxy %p: destroy %u", proxy, proxy->id);
pw_signal_emit(&proxy->destroy_signal, proxy); pw_signal_emit(&proxy->destroy_signal, proxy);
pw_map_remove(&proxy->context->objects, proxy->id); pw_map_remove(&proxy->context->objects, proxy->id);

View file

@ -48,6 +48,7 @@ void pw_type_init(struct pw_type *type)
type->client_node = spa_type_map_get_id(type->map, PIPEWIRE_TYPE__ClientNode); type->client_node = spa_type_map_get_id(type->map, PIPEWIRE_TYPE__ClientNode);
type->module = spa_type_map_get_id(type->map, PIPEWIRE_TYPE__Module); type->module = spa_type_map_get_id(type->map, PIPEWIRE_TYPE__Module);
type->spa_log = spa_type_map_get_id(type->map, SPA_TYPE__Log);
type->spa_node = spa_type_map_get_id(type->map, SPA_TYPE__Node); type->spa_node = spa_type_map_get_id(type->map, SPA_TYPE__Node);
type->spa_clock = spa_type_map_get_id(type->map, SPA_TYPE__Clock); type->spa_clock = spa_type_map_get_id(type->map, SPA_TYPE__Clock);
type->spa_monitor = spa_type_map_get_id(type->map, SPA_TYPE__Monitor); type->spa_monitor = spa_type_map_get_id(type->map, SPA_TYPE__Monitor);

View file

@ -67,6 +67,7 @@ struct pw_type {
uint32_t client_node; uint32_t client_node;
uint32_t module; uint32_t module;
uint32_t spa_log;
uint32_t spa_node; uint32_t spa_node;
uint32_t spa_clock; uint32_t spa_clock;
uint32_t spa_monitor; uint32_t spa_monitor;

View file

@ -41,7 +41,6 @@ int main(int argc, char *argv[])
} }
loop = pw_main_loop_new(); loop = pw_main_loop_new();
pw_log_set_loop(loop->loop->loop);
core = pw_core_new(loop, NULL); core = pw_core_new(loop, NULL);

View file

@ -993,7 +993,9 @@ static const struct spa_node proxy_node = {
static int static int
proxy_init(struct proxy *this, proxy_init(struct proxy *this,
struct spa_dict *info, const struct spa_support *support, uint32_t n_support) struct spa_dict *info,
const struct spa_support *support,
uint32_t n_support)
{ {
uint32_t i; uint32_t i;
@ -1005,7 +1007,7 @@ proxy_init(struct proxy *this,
else if (strcmp(support[i].type, SPA_TYPE_LOOP__DataLoop) == 0) else if (strcmp(support[i].type, SPA_TYPE_LOOP__DataLoop) == 0)
this->data_loop = support[i].data; this->data_loop = support[i].data;
} }
if (this->data_loop == NULL) { if (this->main_loop == NULL) {
spa_log_error(this->log, "a main-loop is needed"); spa_log_error(this->log, "a main-loop is needed");
} }
if (this->data_loop == NULL) { if (this->data_loop == NULL) {

View file

@ -365,12 +365,12 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties
impl->support[0].type = SPA_TYPE__TypeMap; impl->support[0].type = SPA_TYPE__TypeMap;
impl->support[0].data = this->type.map; impl->support[0].data = this->type.map;
impl->support[1].type = SPA_TYPE__Log; impl->support[1].type = SPA_TYPE_LOOP__DataLoop;
impl->support[1].data = pw_log_get(); impl->support[1].data = this->data_loop->loop->loop;
impl->support[2].type = SPA_TYPE_LOOP__DataLoop; impl->support[2].type = SPA_TYPE_LOOP__MainLoop;
impl->support[2].data = this->data_loop->loop->loop; impl->support[2].data = this->main_loop->loop->loop;
impl->support[3].type = SPA_TYPE_LOOP__MainLoop; impl->support[3].type = SPA_TYPE__Log;
impl->support[3].data = this->main_loop->loop->loop; impl->support[3].data = pw_log_get(impl->support, 3);
this->support = impl->support; this->support = impl->support;
this->n_support = 4; this->n_support = 4;

View file

@ -55,10 +55,6 @@ static inline void spa_log_impl_log(struct spa_log *log,
va_end(args); va_end(args);
} }
static inline void spa_log_impl_set_loop(struct spa_log *log, struct spa_loop *loop)
{
}
#define SPA_LOG_IMPL_DEFINE(name) \ #define SPA_LOG_IMPL_DEFINE(name) \
struct { \ struct { \
struct spa_log log; \ struct spa_log log; \
@ -69,8 +65,7 @@ struct { \
NULL, \ NULL, \
SPA_LOG_LEVEL_INFO, \ SPA_LOG_LEVEL_INFO, \
spa_log_impl_log, \ spa_log_impl_log, \
spa_log_impl_logv, \ spa_log_impl_logv,} }
spa_log_impl_set_loop,} }
#define SPA_LOG_IMPL(name) \ #define SPA_LOG_IMPL(name) \
SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT SPA_LOG_IMPL_DEFINE(name) = SPA_LOG_IMPL_INIT

View file

@ -103,21 +103,8 @@ struct spa_log {
const char *func, const char *func,
const char *fmt, const char *fmt,
va_list args) SPA_PRINTF_FUNC(6, 0); va_list args) SPA_PRINTF_FUNC(6, 0);
/**
* Set the loop for trace logging
* \param log the logger
* \param loop the loop for trace logging
*
* Trace logging will be done to a ringbuffer and written to
* the console/device from \a loop to ensure no blocking operations
* are done from the realtime thread.
*/
void (*set_loop) (struct spa_log *log,
struct spa_loop *loop);
}; };
#define spa_log_set_loop(l,...) (l)->set_loop((l),__VA_ARGS__)
#define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev)) #define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev))
#if __STDC_VERSION__ >= 199901L #if __STDC_VERSION__ >= 199901L

View file

@ -38,7 +38,7 @@
#define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_INFO #define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_INFO
#define TRACE_BUFFER 4096 #define TRACE_BUFFER (16*1024)
struct type { struct type {
uint32_t log; uint32_t log;
@ -142,33 +142,12 @@ static void on_trace_event(struct spa_source *source)
} }
} }
static void
impl_log_set_loop(struct spa_log *log, struct spa_loop *loop)
{
struct impl *impl = SPA_CONTAINER_OF(log, struct impl, log);
if (impl->have_source) {
spa_loop_remove_source(impl->source.loop, &impl->source);
close(impl->source.fd);
impl->have_source = false;
}
if (loop) {
impl->source.func = on_trace_event;
impl->source.data = impl;
impl->source.fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
impl->source.mask = SPA_IO_IN;
impl->source.rmask = 0;
spa_loop_add_source(loop, &impl->source);
impl->have_source = true;
}
}
static const struct spa_log impl_log = { static const struct spa_log impl_log = {
sizeof(struct spa_log), sizeof(struct spa_log),
NULL, NULL,
DEFAULT_LOG_LEVEL, DEFAULT_LOG_LEVEL,
impl_log_log, impl_log_log,
impl_log_logv, impl_log_logv,
impl_log_set_loop,
}; };
static int impl_get_interface(struct spa_handle *handle, uint32_t interface_id, void **interface) static int impl_get_interface(struct spa_handle *handle, uint32_t interface_id, void **interface)
@ -196,8 +175,11 @@ static int impl_clear(struct spa_handle *handle)
this = (struct impl *) handle; this = (struct impl *) handle;
impl_log_set_loop(&this->log, NULL); if (this->have_source) {
spa_loop_remove_source(this->source.loop, &this->source);
close(this->source.fd);
this->have_source = false;
}
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -210,6 +192,7 @@ impl_init(const struct spa_handle_factory *factory,
{ {
struct impl *this; struct impl *this;
uint32_t i; uint32_t i;
struct spa_loop *loop = NULL;
spa_return_val_if_fail(factory != NULL, SPA_RESULT_INVALID_ARGUMENTS); spa_return_val_if_fail(factory != NULL, SPA_RESULT_INVALID_ARGUMENTS);
spa_return_val_if_fail(handle != NULL, SPA_RESULT_INVALID_ARGUMENTS); spa_return_val_if_fail(handle != NULL, SPA_RESULT_INVALID_ARGUMENTS);
@ -224,6 +207,8 @@ impl_init(const struct spa_handle_factory *factory,
for (i = 0; i < n_support; i++) { for (i = 0; i < n_support; i++) {
if (strcmp(support[i].type, SPA_TYPE__TypeMap) == 0) if (strcmp(support[i].type, SPA_TYPE__TypeMap) == 0)
this->map = support[i].data; this->map = support[i].data;
if (strcmp(support[i].type, SPA_TYPE_LOOP__MainLoop) == 0)
loop = support[i].data;
} }
if (this->map == NULL) { if (this->map == NULL) {
spa_log_error(&this->log, "a type-map is needed"); spa_log_error(&this->log, "a type-map is needed");
@ -231,6 +216,16 @@ impl_init(const struct spa_handle_factory *factory,
} }
init_type(&this->type, this->map); init_type(&this->type, this->map);
if (loop) {
this->source.func = on_trace_event;
this->source.data = this;
this->source.fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
this->source.mask = SPA_IO_IN;
this->source.rmask = 0;
spa_loop_add_source(loop, &this->source);
this->have_source = true;
}
spa_ringbuffer_init(&this->trace_rb, TRACE_BUFFER); spa_ringbuffer_init(&this->trace_rb, TRACE_BUFFER);
spa_log_info(&this->log, NAME " %p: initialized", this); spa_log_info(&this->log, NAME " %p: initialized", this);