(This document/code contribution attached is provided under the terms of
agreement LES-LTM-21309)
I contribute a proposal for a log API for ODP to stimulate further
discussion.
Some comments:
Header file missing compile-time selection of log/severity levels, left as
an exercise to the mailing list.
Implementation is not thread safe but that should be easy to fix,
thread-unsafe operations are not performance critical so some coarse
locking should be fine.
Example usage in log_example.c. This is really the important part.
Build with
gcc -std=c99 -Wall odp_log.c log_example.c -o log_example
There might be one thing that is GCC-specific, see if you can find it.
-- Ola
/* Copyright (c) 2013, Linaro Limited
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file
*
* Simplistic ODP logging, lacks mutual exclusion for multithreading
*/
#include <limits.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "odp_log.h"
static odp_log_source_t *first = NULL;
static odp_log_callback_t callback = NULL;
static ODP_LOG_SOURCE(odp_log);
void odp_log_init(void)
{
ODP_LOG_REGISTER(odp_log);
odp_log_set_mask("odp_log", ODP_LOG_MASK_ALL);
}
/* Register a log source with the specified name */
int odp_log_register_source(odp_log_source_t *src, const char *name)
{
odp_log_source_t **pptr = &first;
while (*pptr != NULL)
{
/* Is new element smaller than existing? */
if (strcmp(name, (*pptr)->name) < 0)
{
insert:
src->next = *pptr;
src->name = name;
src->mask = ODP_LOG_SEV_FATAL | ODP_LOG_SEV_ERROR |
ODP_LOG_SEV_INFORM;
*pptr = src;
return 0;
}
pptr = &(*pptr)->next;
}
/* Traversed whole list, insert at end */
goto insert;
}
/* Unregister a log source */
void odp_log_unregister_source(odp_log_source_t *src)
{
odp_log_source_t **pptr = &first;
while (*pptr != NULL)
{
if (*pptr == src)
{
*pptr = src->next;
src->next = NULL;
return;
}
pptr = &(*pptr)->next;
}
/* Else unknown source */
ODP_LOG_WARNING(odp_log, "Attempt to unregister unknown source %s\n",
src->name);
}
/* Report a log message */
void odp_log_printf(const char *name, odp_log_mask_t sev, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (callback != NULL)
{
callback(name, sev, fmt, ap);
}
else
{
fprintf(stderr, "%s/%c: ", name, " FEWIDxyz"[ffs(sev & 0xFFU)]);
vfprintf(stderr, fmt, ap);
}
va_end(ap);
}
/* Set the log mask for a source identified by name */
int odp_log_set_mask(const char *name, odp_log_mask_t mask)
{
odp_log_source_t *ptr = first;
while (ptr != NULL)
{
if (strcmp(ptr->name, name) == 0)
{
ODP_LOG_DEBUG(odp_log, "Set log mask for source %s to 0x%x\n",
name, mask);
ptr->mask = mask;
return 0;
}
ptr = ptr->next;
}
/* Named source not found */
return -1;
}
/* Install a user-defined call-back for handling log messages */
void odp_log_set_callback(odp_log_callback_t cb)
{
callback = cb;
}
/* Iterate through all registered log sources */
int odp_log_next_source(char name[ODP_NAME_MAX + 1], odp_log_mask_t *mask)
{
odp_log_source_t *ptr = first;
while (ptr != NULL)
{
if (strncmp(ptr->name, name, ODP_NAME_MAX) > 0)
{
strncpy(name, ptr->name, ODP_NAME_MAX);
name[ODP_NAME_MAX] = 0;
*mask = ptr->mask;
return 0;
}
ptr = ptr->next;
}
return -1;
}
/* Copyright (c) 2013, Linaro Limited
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file
*
* ODP logging
*/
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "odp_log.h"
static const char *severity[] =
{
"fatal", "error", "warning", "informational", "debug"
};
void my_vprintf(const char *name, odp_log_mask_t sev, const char *fmt, va_list ap)
{
printf("%s/%s: ", name, severity[ffs(sev) - 1]);
vprintf(fmt, ap);
}
int main()
{
odp_log_init();
ODP_LOG_SOURCE(odp_queue);
//Register log source and set default log mask
ODP_LOG_REGISTER(odp_queue);
//Log a message with severity error
ODP_LOG_ERROR(odp_queue, "Failed to create queue, param=%u\n", 242);
//Set log mask for a source to log everything
(void)odp_log_set_mask("odp_queue", ODP_LOG_MASK_ALL);
//Install a custom vprintf function to handle log messages
odp_log_set_callback(my_vprintf);
ODP_LOG_INFORM(odp_queue, "Message printed using user-defined call-back\n");
//Add some source out-of-alphabetical order
ODP_LOG_SOURCE(b); ODP_LOG_REGISTER(b);
ODP_LOG_SOURCE(a); ODP_LOG_REGISTER(a);
ODP_LOG_SOURCE(c); ODP_LOG_REGISTER(c);
//List all registered log sources
char name[ODP_NAME_MAX + 1];
odp_log_mask_t mask;
strcpy(name, ""); //Empty name is before all other names
while (odp_log_next_source(name, &mask) == 0)
{
printf("Log source %s, log mask 0x%x\n", name, mask);
}
//We are done, unregister source
ODP_LOG_UNREGISTER(odp_queue);
//A redundant unregister, just for fun
ODP_LOG_UNREGISTER(odp_queue);
return 0;
}
/* Copyright (c) 2013, Linaro Limited
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/**
* @file
*
* ODP logging
*/
#ifndef ODP_LOG_H_
#define ODP_LOG_H_
#include <limits.h>
#include <stdint.h>
#include <stdarg.h>
#if 0
#include "odp_hints.h"
#else
#define odp_likely(x) (x)
#define odp_unlikely(x) (x)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Severity types */
#define ODP_LOG_SEV_FATAL (1U << 0U) /* Fatal for application, may not return */
#define ODP_LOG_SEV_ERROR (1U << 1U) /* Error but caller should be able to recover */
#define ODP_LOG_SEV_WARNING (1U << 2U) /* Warning but recovered locally */
#define ODP_LOG_SEV_INFORM (1U << 3U) /* Informational message intended for user */
#define ODP_LOG_SEV_DEBUG (1U << 4U) /* Debug message intended for developer */
/* These symbols are used to specify what types should be logged */
#define ODP_LOG_MASK_NONE 0
#define ODP_LOG_MASK_ALL ((odp_log_mask_t)~0U)
/* Declare a log source */
#define ODP_LOG_SOURCE(NAME) odp_log_source_t odp_log_source_ ## NAME;
/* Register a log source with the log manager */
#define ODP_LOG_REGISTER(NAME) odp_log_register_source(&odp_log_source_ ## NAME, #NAME)
/* Unregister a log source */
#define ODP_LOG_UNREGISTER(NAME) odp_log_unregister_source(&odp_log_source_ ## NAME)
/* Report a message to the log */
#define ODP_LOG_FATAL(_src, _fmt, ...) \
{ \
odp_log_source_t *__src = &odp_log_source_ ## _src; \
if (odp_unlikely((__src->mask & ODP_LOG_SEV_FATAL) != 0)) \
{ \
odp_log_printf(__src->name, ODP_LOG_SEV_FATAL, (_fmt), ## __VA_ARGS__); \
} \
}
#define ODP_LOG_ERROR(_src, _fmt, ...) \
{ \
odp_log_source_t *__src = &odp_log_source_ ## _src; \
if (odp_unlikely((__src->mask & ODP_LOG_SEV_ERROR) != 0)) \
{ \
odp_log_printf(__src->name, ODP_LOG_SEV_ERROR, (_fmt), ## __VA_ARGS__); \
} \
}
#define ODP_LOG_WARNING(_src, _fmt, ...) \
{ \
odp_log_source_t *__src = &odp_log_source_ ## _src; \
if (odp_unlikely((__src->mask & ODP_LOG_SEV_WARNING) != 0)) \
{ \
odp_log_printf(__src->name, ODP_LOG_SEV_WARNING, (_fmt), ## __VA_ARGS__); \
} \
}
#define ODP_LOG_INFORM(_src, _fmt, ...) \
{ \
odp_log_source_t *__src = &odp_log_source_ ## _src; \
if (odp_unlikely((__src->mask & ODP_LOG_SEV_INFORM) != 0)) \
{ \
odp_log_printf(__src->name, ODP_LOG_SEV_INFORM, (_fmt), ## __VA_ARGS__); \
} \
}
#define ODP_LOG_DEBUG(_src, _fmt, ...) \
{ \
odp_log_source_t *__src = &odp_log_source_ ## _src; \
if (odp_unlikely((__src->mask & ODP_LOG_SEV_DEBUG) != 0)) \
{ \
odp_log_printf(__src->name, ODP_LOG_SEV_DEBUG, (_fmt), ## __VA_ARGS__); \
} \
}
/* Max length of a log source (excluding null char) */
#define ODP_NAME_MAX 80
typedef uint8_t odp_log_mask_t;
struct odp_log_source;
struct odp_log_source
{
struct odp_log_source *next;
const char *name;
odp_log_mask_t mask;
};
typedef struct odp_log_source odp_log_source_t;
/* Call-back type definition for user-defined log facility */
typedef void (*odp_log_callback_t)(const char *name, odp_log_mask_t mask, const char *fmt, va_list ap);
/* Don't use these calls directly, use corresponding macros */
/* Register a log source with the specified name */
int odp_log_register_source(odp_log_source_t *, const char *name);
/* Unregister a log source */
void odp_log_unregister_source(odp_log_source_t *);
/* Report a log message */
void odp_log_printf(const char *, odp_log_mask_t, const char *, ...);
/* Calls used from log management and backend */
void odp_log_init(void);
/* Set the log mask for a source identified by name */
int odp_log_set_mask(const char *name, odp_log_mask_t mask);
/* Install a user-defined call-back for handling log messages */
void odp_log_set_callback(odp_log_callback_t cb);
/* Iterate through all registered log sources */
int odp_log_next_source(char name[ODP_NAME_MAX + 1], odp_log_mask_t *mask);
/* Example usage:
//Declare a log source
ODP_LOG_SOURCE(odp_queue);
//Register log source and set default log mask
ODP_LOG_REGISTER(odp_queue);
//Log a message with severity error
ODP_LOG_ERROR(odp_queue, "Failed to create queue, param=%u\n", 242);
//Set log mask for a source to log everything
(void)odp_log_set_mask("odp_queue", ODP_LOG_MASK_ALL);
//Install a custom vprintf function to handle log messages
odp_log_set_callback(my_vprintf);
ODP_LOG_INFORM(odp_queue, "Message printed using user-defined call-back\n");
//List all registered log sources
char name[ODP_NAME_MAX + 1];
odp_log_mask_t mask;
strcpy(name, ""); //Empty name is before all other names
while (odp_log_next_source(name, &mask) == 0)
{
printf("Log source %s, log mask 0x%x\n", name, mask);
}
//We are done, unregister source
ODP_LOG_UNREGISTER(odp_queue);
*/
#ifdef __cplusplus
}
#endif
#endif
_______________________________________________
lng-odp mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/lng-odp