(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

Reply via email to