On Fri, Aug 15, 2014 at 04:17:22PM +0100, Ola Liljedahl wrote:
> (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.
Is there a prize?
##__VAR_ARGS__ ?
>
> -- 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);
> }
I find the semantics unusual, in particular the scope of odp_log and the
fact that it's initialised unquoted and then used quoted.
The code above is not so bad due to the global scope of odp_log, but in
the example with local scope it's not clear whether you're registering
with a global handler or initialising a local variable.
To me something like this would be more natural;
static odp_log_source_t *odp_log;
odp_log = odp_log_register("odp_log");
ODP_LOG_INFORM(odp_log, "bleh bleh\n");
>
> /* 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;
> }
That's a weird use of goto, it would be clearer to move stuff within the
strcmp block after the loop, reverse the logic of the strcmp and break.
[...]
> /* 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);
Using a mask makes this valid;
ODP_LOG_SEV_FATAL & ODP_LOG_SEV_DEBUG
Which could be pretty confusing when looking through the logs some time
later (where'd the ERROR logs go?). I think levels are better.
> //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
I don't understand the above comment, does that mean "" is a valid log
source? can I print to it?
> while (odp_log_next_source(name, &mask) == 0)
> {
> printf("Log source %s, log mask 0x%x\n", name, mask);
> }
>
I can't think why you'd want to iterate through the log sources.
> //We are done, unregister source
> ODP_LOG_UNREGISTER(odp_queue);
> //A redundant unregister, just for fun
> ODP_LOG_UNREGISTER(odp_queue);
>
What about ODP_LOG_UNSOURCE()?.. just kidding, I know there isn't one as
it just goes out of scope, but it does make the function look unbalanced.
ODP_LOG_SOURCE(odp_queue);
ODP_LOG_REGISTER(odp_queue);
..
ODP_LOG_UNREGISTER(odp_queue);
> return 0;
> }
--
Stuart.
_______________________________________________
lng-odp mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/lng-odp