question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Remove Python from gpilog

See original GitHub issue

The Python logger implementation for the GPI library is located in the gpilog library. This means that users of the GPI that aren’t going to use Python still must link against libpython (this dependency on libpython isn’t listed in cocotb_build_libs.py, but it is a reality). Instead, to support non-Python GPI users we should change the gpilog interface to one where the implementation is registered instead of prescribed.

Desired interface for gpilog:

/**
 * Named log levels.
 * Log levels can be any value, but only these values will be named when using the native logger.
 */
enum gpi_log_levels {
    GPIDebug = 10,
    GPIInfo = 20,
    GPIWarning = 30,
    GPIError = 40,
    GPICritical = 50
};

/**
 * Convenience functions for logging, see #gpi_log for more detail.
 */
#define LOG_DEBUG(...)     gpi_log("cocotb.gpi", GPIDebug,         __FILE__, __func__, __LINE__, __VA_ARGS__);
#define LOG_INFO(...)      gpi_log("cocotb.gpi", GPIInfo,          __FILE__, __func__, __LINE__, __VA_ARGS__);
#define LOG_WARN(...)      gpi_log("cocotb.gpi", GPIWarning,       __FILE__, __func__, __LINE__, __VA_ARGS__);
#define LOG_ERROR(...)     gpi_log("cocotb.gpi", GPIError,         __FILE__, __func__, __LINE__, __VA_ARGS__);
#define LOG_CRITICAL(...)  gpi_log("cocotb.gpi", GPICritical,      __FILE__, __func__, __LINE__, __VA_ARGS__); 

/**
 * A GPI logging handler function.
 * See #gpi_log for other params.
 *
 * @param[in] userdata  State data used by the logging handler
 * @returns boolean representing success (0) or failure (non-0). If there is a failure, `gpi_log` will fall back on the native logger.
 */
typedef int (gpi_log_handler_type)(
    void *userdata,
    const char *name,
    int level,
    const char *pathname,
    const char *funcname,
    long lineno,
    const char *msg,
    va_list args);

/**
 * Log a message.
 * If a user log handler object is set, uses the registered log handler, otherwise uses the native logger.
 * @param[in] name      Name of the logger
 * @param[in] level     Level at which to log a message at
 * @param[in] pathname  Name of the file where the call site is located
 * @param[in] funcname  Name of the function where the call site is located
 * @param[in] lineno    Line number of the call site
 * @param[in] msg       The message to log, uses C-style format specifier
 * @param[in] ...       Additional arguments; formatted at inserted in message according to format specifier in msg argument
 */
void gpi_log(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, ...);

/**
 * Retrieve current custom log handler.
 * @param[out] handler  Custom log handler registered previously, or NULL if no handler was set
 * @param[out] userdata Custom log handler userdata registered previously, or NULL if no handler was set
 */
void gpi_get_log_handler(gpi_log_handler_type **handler, void **userdata);

/**
 * Set custom log handler.
 * @param[in] handler   Handler function to call when the GPI logs a message
 * @param[in] userdata  State data to pass to the handler function when logging a message
 */
void gpi_set_log_handler(gpi_log_handler_type *handler, void *userdata);

/**
 * Clear current custom log handler and use native logger
 */
void gpi_clear_log_handler(void);

/**
 * Builtin logger implementation, used as a fallback when no custom log handler is set.
 * See #gpi_log for details on parameters.
 */
void gpi_native_logger_log(
    const char *name,
    int level,
    const char *pathname,
    const char *funcname,
    long lineno,
    const char *msg,
    ...);

/**
 * Set minimum logging level of the builtin logger implementation.
 * If a logging request occurs where the logging level is lower than the level set by this function, it is not logged.
 * *Only* affects the native logger.
 * @param[in] level     Logging level
 * @return              Previous logging level
 */
int gpi_native_logger_set_level(int level);

gpilog will contain a default implementation, the “native” logger, which will just use stdio. This native logger will be able to log messages and have it’s log level set. Users may register their own loggers using gpi_set_log_handler which takes a handler function and an opaque userdata pointer. This should be sufficient for gpi_embed to register a Python logger implementation after it is loaded and remove the Python dependency in gpilog. The only thing the user may do with the custom log handler is clear it, to continue using the native logger, or retrieve it. The custom logger will not respect the native logger’s log level.

I had thought about merging gpilog into GPI, but this is not possible because cocotb_utils depends upon gpilog. If gpi and gpilog were merged, cocotb_utils would then depend upon gpi. However, gpi depends upon cocotb_utils, so we encounter a loop. Everything could be merged into gpi, but I feel leaving it parsed out for now is fine.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
eric-wiesercommented, Jul 20, 2020

Well that’s 2 agreements. Updated.

Mine was more of an exploratory question. The current approach is perhaps better because it allows:

try:
   do_my_logging(*args)
except:
   do_the_default_logging("inside knowledge about why logging failed")
   do_the_default_logging(*args)

If you switch to a return code, then you can no longer support this approach.

1reaction
ktbarrettcommented, Jul 20, 2020

The idea is that a user could go straight to the native logger instead of using gpi_log. If that’s not necessary, I’d just remove it. There would be a private version that takes a va_list that would be called by gpi_log. If the user isn’t manually calling the native logger as a fall back (gpi_log handles that automatically as recommend above) there isn’t a need to expose a va_list version to the user.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to uninstall Python - Educative.io
Select the Python version that you want to uninstall, then click the “Uninstall” button above the list – this has to be done...
Read more >
GPI Logistics
The GPI Group is a global conglomerate operating in global trade, shipping and energy. GPI employs over 88900 people and is present in...
Read more >
How to Uninstall Python Packages - ActiveState
Click to use the Pip Package Manager to uninstall Python packages.
Read more >
How to Uninstall Python
Windows makes it easy to uninstall Python. You can remove any version of Python installed on your computer in three simple steps. Step...
Read more >
How to remove python from windows which is not found in ...
I think you had two python installations. Try these commands for uninstall python:
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found