Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward log level to custom vprintf #3070

Conversation

eloparco
Copy link
Contributor

@eloparco eloparco commented Jan 22, 2024

Follow-up on #2907.
The log level is needed in the embedded to better integrate with the embedder's logger.

@eloparco eloparco force-pushed the eloparco/add-log-level-in-vprintf-override branch 3 times, most recently from 1508155 to 8e80eda Compare January 22, 2024 14:31
@eloparco eloparco force-pushed the eloparco/add-log-level-in-vprintf-override branch from 8e80eda to 1a00803 Compare January 22, 2024 15:07
@@ -51,7 +51,7 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...)
os_printf("%s, line %d, ", file, line);

va_start(ap, fmt);
os_vprintf(fmt, ap);
os_vprintf(log_level, fmt, ap);
Copy link
Contributor

@wenyongh wenyongh Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eloparco this change introduces lots of code changes, and it makes the code structure a little strange, the platform layer seems to rely on the shared/util layer, and the prototype of os_vprintf is inconsistent with vprintf.
Per my understanding, you want to take control the log dump in your code, how about introducing another macro BH_VLOG like BH_VPRINTF, and call it when it is defined:

    va_start(ap, fmt);
#if defined(BH_VLOG)
    BH_VLOG(log_level, fmt, ap);
#else
    os_vprintf(fmt, ap);
#endif

Or just defined BH_LOG to replace bh_log function:

#ifndef BH_LOG
void
bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...)
{
    ...
}
#endif

and in bh_log.h
#ifndef BH_LOG
void
bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...);
#else
void
BH_LOG(LogLevel log_level, const char *file, int line, const char *fmt, ...);
#define bh_log BH_LOG
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried that just to make sure, but it doesn't allow to forward the wasm output, coming from os_printf,

err = wasmtime_ssp_fd_write(exec_env, curfds, fd, ciovec_begin, iovs_len,
to the embedder (e.g. the output here
printf("calling into WASM function: %s\n", __FUNCTION__);
goes through os_printf but not bh_log).
What I mean is, overriding bh_log only allows to take control of the runtime output, not the wasm one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you define both BH_LOG and BH_VPRINTF? It will forward both bh_log and os_printf.

@loganek
Copy link
Collaborator

loganek commented Jan 23, 2024

Rather than making ad-hoc changes to unblock some usecases, I'd rather take a step back and refine how do we log in WAMR in general. I think we already have solid foundations to improve logging - we have a bunch of macros (LOG_*) and bh_log function that I think we should use in WAMR instead of calling vprintf() directly.
We can then introduce a concept of log listener that registers to the logger and gets called with various parameters (log level, line, file, message etc.) Then it's up to the user to define its own log handler, where the default one can be the vprintf().

So in high level we'd have something like:

typedef void (*bh_log_listener)(int level, int line, const char* file, const char *message, void *ud); // and other fields like timestamp or whatever we think is appropriate

void bh_log_register_listener(bh_log_listener, void *ud);

void bh_log_default_listener(int level, int line, const char *file, const char *message, void *_ud)
{
    printf(....);
}

So the bh_log() would call the registered listener (or listeners, if we allow having multiple ones) and the listener decides what to do.

@wenyongh let me know your thoughts.

@wenyongh
Copy link
Contributor

Rather than making ad-hoc changes to unblock some usecases, I'd rather take a step back and refine how do we log in WAMR in general. I think we already have solid foundations to improve logging - we have a bunch of macros (LOG_*) and bh_log function that I think we should use in WAMR instead of calling vprintf() directly. We can then introduce a concept of log listener that registers to the logger and gets called with various parameters (log level, line, file, message etc.) Then it's up to the user to define its own log handler, where the default one can be the vprintf().

So in high level we'd have something like:

typedef void (*bh_log_listener)(int level, int line, const char* file, const char *message, void *ud); // and other fields like timestamp or whatever we think is appropriate

void bh_log_register_listener(bh_log_listener, void *ud);

void bh_log_default_listener(int level, int line, const char *file, const char *message, void *_ud)
{
    printf(....);
}

So the bh_log() would call the registered listener (or listeners, if we allow having multiple ones) and the listener decides what to do.

@wenyongh let me know your thoughts.

@loganek using a listener (or callback) is good to me, but I have two concerns:
one is about the prototype, if using argument const char *message, then in bh_log function, runtime should output the log to a message buffer, and then call bh_log_default_listener with the buffer, I am not sure how much the buffer should be. Is it better to use const char *format, va_list ap like os_vprintf? Like:

void bh_log_default_listener(int level, const char *file, int line, const char *fmt, va_list ap, void *user_data)

another is whether it can meet the requirement from @eloparco, he wants to forward the log of os_printf also, but in os_printf, we had better not call the listener directly and also the argument level/file/line cannot be passed to it. Should we add the listener in libc-builtin and libc-wasi which eventually call os_printf, liike:
https://github.com/wenyongh/wasm-micro-runtime/blob/update_build_wamr_doc/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c#L1119-L1141

@loganek
Copy link
Collaborator

loganek commented Jan 23, 2024

one is about the prototype

The prototype was just an example, we can tune it. It was mainly just to present a high-level concept

he wants to forward the log of os_printf also

I'd separate os_printf and bh_log - those are two separate ones IMO. We should probably keep the existing mechanism for os_printf and change only the logging. Also, I think there's a few places where os_printf is used in the runtime where actually we should bh_log - I think we can gradually update the code to fully migrate to bh_log instead.

@wenyongh
Copy link
Contributor

one is about the prototype

The prototype was just an example, we can tune it. It was mainly just to present a high-level concept

he wants to forward the log of os_printf also

I'd separate os_printf and bh_log - those are two separate ones IMO. We should probably keep the existing mechanism for os_printf and change only the logging. Also, I think there's a few places where os_printf is used in the runtime where actually we should bh_log - I think we can gradually update the code to fully migrate to bh_log instead.

But os_printf and bh_log are difference, bh_log outputs more info, e.g. timestamp and thread id, and some developers may feel that os_printf is more convenient since sometimes we are not sure what we should call for bh_log - LOG_ERROR, LOG_WARNING, LOG_DEBUG or LOG_VERBOSE.

@loganek
Copy link
Collaborator

loganek commented Jan 23, 2024

one is about the prototype

The prototype was just an example, we can tune it. It was mainly just to present a high-level concept

he wants to forward the log of os_printf also

I'd separate os_printf and bh_log - those are two separate ones IMO. We should probably keep the existing mechanism for os_printf and change only the logging. Also, I think there's a few places where os_printf is used in the runtime where actually we should bh_log - I think we can gradually update the code to fully migrate to bh_log instead.

But os_printf and bh_log are difference, bh_log outputs more info, e.g. timestamp and thread id, and some developers may feel that os_printf is more convenient since sometimes we are not sure what we should call for bh_log - LOG_ERROR, LOG_WARNING, LOG_DEBUG or LOG_VERBOSE.

I see why using os_printf is more appealing as it doesn't require thinking about the log level. I'd still encourage developers to use bh_log as it allows filtering the output, even if sometimes it's not easy to decide the level.

Having said that, I feel like this is a separate discussion, independent on the goal that @eloparco is trying to achieve here. I'd keep BH_VPRINTF as it is today, and introduce log listener or BH_LOG as suggested by @wenyongh (I don't have strong opinion on that, I think both approaches have pros and cons).

@@ -338,6 +338,9 @@ endif ()
if (DEFINED WAMR_BH_VPRINTF)
add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF})
endif ()
if (DEFINED WAMR_BH_LOG)
add_definitions (-DBH_LOG=1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to be similar with WAMR_BH_VPRINTF:

if (DEFINED WAMR_BH_LOG)
  add_defintions (-DBH_LOG=${WAMR_BH_LOG})
endif ()

So we only introduce macro BH_LOG to the code, and can use it as a flag to control the code, and developer can define the function with the name he wants.
In bh_log.h:

#ifndef BH_LOG
void
bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...);
#else
void
BH_LOG(uint32 log_level, const char *file, int line, const char *fmt, ...);
#define bh_log BH_LOG
#endif

We can also use WASM_LOG, e.g. add_defintions (-DWASM_LOG=${WAMR_BH_LOG}), but it seems that BH_LOG is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, good point, updated

core/shared/utils/bh_log.h Outdated Show resolved Hide resolved
doc/build_wamr.md Outdated Show resolved Hide resolved
@@ -21,7 +21,7 @@ echo "#####################build basic project"
cd ${CURR_DIR}
mkdir -p cmake_build
cd cmake_build
cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake .. -DCMAKE_BUILD_TYPE=Debug -DWAMR_BH_VPRINTF=my_vprintf -DWAMR_BH_LOG=1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about -DWAMR_BH_LOG=my_log

@eloparco eloparco force-pushed the eloparco/add-log-level-in-vprintf-override branch from 1bc6618 to 41e2acc Compare January 24, 2024 01:57
Copy link
Contributor

@wenyongh wenyongh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wenyongh wenyongh merged commit 3fcd798 into bytecodealliance:main Jan 24, 2024
405 checks passed
victoryang00 pushed a commit to victoryang00/wamr-aot-gc-checkpoint-restore that referenced this pull request May 27, 2024
…#3070)

Follow-up on bytecodealliance#2907. The log level is needed in the host embedder to
better integrate with the embedder's logger.

Allow the developer to customize his bh_log callback with
`cmake -DWAMR_BH_LOG=<log_callback>`,
and update sample/basic to show the usage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants