Logging

DQCsim provides a centralized logging interface for plugins. This ensures that log messages are processed in a consistent way among different plugins. It also makes sure that messages don't print "through" each other, as they would when stdout/stderr were used directly (these are not thread-safe).

The logging interface is only available from within threads that are hosting a plugin (or the main thread of a plugin process) and the thread which started the simulation.

Log levels

Every message has a severity level associated with it. These severities should be interpreted as follows:

  • trace is intended for reporting debugging information useful for debugging the internals of the originating plugin, but not necessarily for debugging the plugins around it. Such messages would normally only be generated by debug builds, to prevent them from impacting performance under normal circumstances.
  • debug is intended for reporting debugging information which may also be useful when debugging the plugins around it, such as the arguments with which a public API function was called.
  • info is intended for reporting information that was not explicitly requested by the user, such as a plugin starting up or shutting down.
  • note is intended for reporting information that was explicitly requested by the user/API caller, such as the result of an API function requested through the command line, or an explicitly captured stdout/stderr stream. It may also be used for reporting events that the user may not be expecting, but are not exceptional enough to warrent issuing a warning.
  • warn is intended for reporting that a third party did something unexpected, but that an attempt will be made to work around the problem, such as a failed connection attempt that we're going to retry.
  • error is intended for reporting or propagating a non-fatal error, such as a third party requesting usage of an unimplemented function.
  • fatal is intended for reporting fatal errors, such as a third party reporting an error for something that we really needed.

Sending log messages

The preferred way for C programs to submit log messages is through the following macros. These automatically add information such as line number and source filename through the C preprocessor. They also fall back to writing to stderr if logging fails for some reason. Their interface is just like printf, but the final newline is implicit.

dqcs_log_trace()

Convenience macro for calling dqcs_log_format() with trace loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_trace(fmt, ...)                \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_TRACE,    \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_debug()

Convenience macro for calling dqcs_log_format() with debug loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_debug(fmt, ...)                \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_DEBUG,    \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_info()

Convenience macro for calling dqcs_log_format() with info loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_info(fmt, ...)                 \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_INFO,     \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_note()

Convenience macro for calling dqcs_log_format() with note loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_note(fmt, ...)                 \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_NOTE,     \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_warn()

Convenience macro for calling dqcs_log_format() with warn loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_warn(fmt, ...)                 \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_WARN,     \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_error()

Convenience macro for calling dqcs_log_format() with error loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_error(fmt, ...)                \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_ERROR,    \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )
dqcs_log_fatal()

Convenience macro for calling dqcs_log_format() with fatal loglevel and automatically determined function name, filename, and line number.

#define dqcs_log_fatal(fmt, ...)                \
  dqcs_log_format(                              \
    _DQCSIM_LOGLEVEL_PREFIX_ DQCS_LOG_FATAL,    \
    _DQCSIM_LANGUAGE_,                          \
    __FILE__,                                   \
    __LINE__,                                   \
    fmt,                                        \
    ##__VA_ARGS__                               \
  )

To get more control over the metadata or to set the loglevel programmatically, you can use the following function.

dqcs_log_format()

Sends a log message using the current logger using printf-like formatting.

static void dqcs_log_format(
    dqcs_loglevel_t level,
    const char *module,
    const char *file,
    uint32_t line,
    const char *fmt,
    ...
)

This function is identical to dqcs_log_raw(), except instead of a single string it takes a printf-like format string and varargs to compose the message.

The above macros and functions ultimately call dqcs_log_raw(). This function does not fall back to stderr if logging fails, and does not support printf-style format strings. The latter may be useful for interfacing with languages that don't support calling variadic functions.

dqcs_log_raw()

Primitive API for sending a log message using the current logger.

dqcs_return_t dqcs_log_raw(
    dqcs_loglevel_t level,
    const char *module,
    const char *file,
    uint32_t line_nr,
    const char *message
)

Returns DQCS_SUCCESS if logging was successful, or DQCS_FAILURE if no logger is available in the current thread or one of the arguments could not be converted. Loggers are available in the simulation host thread and in threads running plugins.

Formatting and fallback to stderr

As an alternative to this function, you can also use dqcs_log_format(). This function differs from dqcs_log_raw() in two ways:

  • Instead of the message string, a printf-style format string and associated varargs are passed to construct the message.
  • When logging fails, this function falls back to writing to stderr instead of returning the errors.

Macros

From C and C++, these functions are normally not called directly. Instead, the following macros are used:

dqcs_log_trace("trace message!");
dqcs_log_debug("debug message!");
dqcs_log_info("info message!");
dqcs_log_note("notice!");
dqcs_log_warn("warning!");
dqcs_log_error("error!");
dqcs_log_fatal("fatal error!");

These macros automatically set file to the C source filename and line to the line number. module is hardcoded to "C" or "CPP" depending on source file language. They use dqcs_log_format(), so they also support printf-style formatting. For instance:

dqcs_note("answer to %s: %d", "ultimate question", 42);

stdout and stderr

By default, DQCsim will capture the stdout and stderr streams of the plugin processes it launches. Each received line will simply be turned into a log message. This is particularly useful for logging problems related to connecting to DQCsim.