diff --git a/rcl/include/rcl/logging.h b/rcl/include/rcl/logging.h
index 9175c6f95..1304e65a4 100644
--- a/rcl/include/rcl/logging.h
+++ b/rcl/include/rcl/logging.h
@@ -21,11 +21,14 @@
#include "rcl/types.h"
#include "rcl/visibility_control.h"
+#include "rcutils/logging.h"
+
#ifdef __cplusplus
extern "C"
{
#endif
+typedef rcutils_logging_output_handler_t rcl_logging_output_handler_t;
/// Configure the logging system.
/**
@@ -53,6 +56,34 @@ rcl_logging_configure(
const rcl_arguments_t * global_args,
const rcl_allocator_t * allocator);
+/// Configure the logging system with the provided output handler.
+/**
+ * Similar to rcl_logging_configure, but it uses the provided output handler.
+ * \sa rcl_logging_configure
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | Yes
+ * Thread-Safe | No
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ *
+ * \param global_args The global arguments for the system
+ * \param allocator Used to allocate memory used by the logging system
+ * \param output_handler Output handler to be installed
+ * \return `RCL_RET_OK` if successful, or
+ * \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
+ * \return `RCL_RET_ERR` if a general error occurs
+ */
+RCL_PUBLIC
+RCL_WARN_UNUSED
+rcl_ret_t
+rcl_logging_configure_with_output_handler(
+ const rcl_arguments_t * global_args,
+ const rcl_allocator_t * allocator,
+ rcl_logging_output_handler_t output_handler);
+
/**
* This function should be called to tear down the logging setup by the configure function.
*
@@ -90,6 +121,28 @@ RCL_PUBLIC
RCL_WARN_UNUSED
bool rcl_logging_rosout_enabled();
+/// Default output handler used by rcl.
+/**
+ * This function can be wrapped in a language specific client library,
+ * adding the necessary mutual exclusion protection there, and then use
+ * `rcl_logging_configure_with_output_handler` instead of
+ * `rcl_logging_configure`.
+ *
+ *
+ * Attribute | Adherence
+ * ------------------ | -------------
+ * Allocates Memory | No
+ * Thread-Safe | Yes
+ * Uses Atomics | No
+ * Lock-Free | Yes
+ */
+RCL_PUBLIC
+void
+rcl_logging_multiple_output_handler(
+ const rcutils_log_location_t * location,
+ int severity, const char * name, rcutils_time_point_value_t timestamp,
+ const char * format, va_list * args);
+
#ifdef __cplusplus
}
#endif
diff --git a/rcl/src/rcl/logging.c b/rcl/src/rcl/logging.c
index cce406560..71c778388 100644
--- a/rcl/src/rcl/logging.c
+++ b/rcl/src/rcl/logging.c
@@ -43,16 +43,6 @@ static bool g_rcl_logging_stdout_enabled = false;
static bool g_rcl_logging_rosout_enabled = false;
static bool g_rcl_logging_ext_lib_enabled = false;
-/**
- * An output function that sends to multiple output appenders.
- */
-static
-void
-rcl_logging_multiple_output_handler(
- const rcutils_log_location_t * location,
- int severity, const char * name, rcutils_time_point_value_t timestamp,
- const char * format, va_list * args);
-
/**
* An output function that sends to the external logger library.
*/
@@ -64,7 +54,10 @@ rcl_logging_ext_lib_output_handler(
const char * format, va_list * args);
rcl_ret_t
-rcl_logging_configure(const rcl_arguments_t * global_args, const rcl_allocator_t * allocator)
+rcl_logging_configure_with_output_handler(
+ const rcl_arguments_t * global_args,
+ const rcl_allocator_t * allocator,
+ rcl_logging_output_handler_t output_handler)
{
RCL_CHECK_ARGUMENT_FOR_NULL(global_args, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
@@ -106,10 +99,17 @@ rcl_logging_configure(const rcl_arguments_t * global_args, const rcl_allocator_t
rcl_logging_ext_lib_output_handler;
}
}
- rcutils_logging_set_output_handler(rcl_logging_multiple_output_handler);
+ rcutils_logging_set_output_handler(output_handler);
return status;
}
+rcl_ret_t
+rcl_logging_configure(const rcl_arguments_t * global_args, const rcl_allocator_t * allocator)
+{
+ return rcl_logging_configure_with_output_handler(
+ global_args, allocator, &rcl_logging_multiple_output_handler);
+}
+
rcl_ret_t rcl_logging_fini()
{
rcl_ret_t status = RCL_RET_OK;
@@ -130,7 +130,6 @@ bool rcl_logging_rosout_enabled()
return g_rcl_logging_rosout_enabled;
}
-static
void
rcl_logging_multiple_output_handler(
const rcutils_log_location_t * location,