ROS 2 rclcpp + rcl - rolling  rolling-e7363f10
ROS 2 C++ Client Library with ROS Client Library
logging.c
1 // Copyright 2018 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include <stdarg.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 
25 #include "./arguments_impl.h"
26 #include "rcl/allocator.h"
27 #include "rcl/error_handling.h"
28 #include "rcl/logging.h"
29 #include "rcl/logging_rosout.h"
30 #include "rcl/types.h"
31 #include "rcl_logging_interface/rcl_logging_interface.h"
32 #include "rcutils/error_handling.h"
33 #include "rcutils/logging.h"
34 #include "rcutils/time.h"
35 #include "rcutils/types/char_array.h"
36 #include "rcutils/types/rcutils_ret.h"
37 
38 #define RCL_LOGGING_MAX_OUTPUT_FUNCS (4)
39 
40 static rcutils_logging_output_handler_t
41  g_rcl_logging_out_handlers[RCL_LOGGING_MAX_OUTPUT_FUNCS] = {0};
42 
43 static uint8_t g_rcl_logging_num_out_handlers = 0;
44 static rcl_allocator_t g_logging_allocator;
45 static bool g_rcl_logging_stdout_enabled = false;
46 static bool g_rcl_logging_rosout_enabled = false;
47 static bool g_rcl_logging_ext_lib_enabled = false;
48 
52 static
53 void
54 rcl_logging_ext_lib_output_handler(
55  const rcutils_log_location_t * location,
56  int severity, const char * name, rcutils_time_point_value_t timestamp,
57  const char * format, va_list * args);
58 
61  const rcl_arguments_t * global_args,
62  const rcl_allocator_t * allocator,
63  rcl_logging_output_handler_t output_handler)
64 {
65  RCL_CHECK_ARGUMENT_FOR_NULL(global_args, RCL_RET_INVALID_ARGUMENT);
66  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
67  RCL_CHECK_ARGUMENT_FOR_NULL(output_handler, RCL_RET_INVALID_ARGUMENT);
68  RCUTILS_LOGGING_AUTOINIT_WITH_ALLOCATOR(*allocator);
69  g_logging_allocator = *allocator;
70  int default_level = -1;
71  rcl_log_levels_t * log_levels = &global_args->impl->log_levels;
72  const char * file_name_prefix = global_args->impl->external_log_file_name_prefix;
73  const char * config_file = global_args->impl->external_log_config_file;
74  g_rcl_logging_stdout_enabled = !global_args->impl->log_stdout_disabled;
75  g_rcl_logging_rosout_enabled = !global_args->impl->log_rosout_disabled;
76  g_rcl_logging_ext_lib_enabled = !global_args->impl->log_ext_lib_disabled;
77  rcl_ret_t status = RCL_RET_OK;
78  g_rcl_logging_num_out_handlers = 0;
79 
80  if (log_levels) {
81  if (log_levels->default_logger_level != RCUTILS_LOG_SEVERITY_UNSET) {
82  default_level = (int)log_levels->default_logger_level;
83  rcutils_logging_set_default_logger_level(default_level);
84  }
85 
86  for (size_t i = 0; i < log_levels->num_logger_settings; ++i) {
87  rcutils_ret_t rcutils_status = rcutils_logging_set_logger_level(
88  log_levels->logger_settings[i].name,
89  (int)log_levels->logger_settings[i].level);
90  if (RCUTILS_RET_OK != rcutils_status) {
91  return RCL_RET_ERROR;
92  }
93  }
94  }
95  if (g_rcl_logging_stdout_enabled) {
96  g_rcl_logging_out_handlers[g_rcl_logging_num_out_handlers++] =
97  rcutils_logging_console_output_handler;
98  }
99  if (g_rcl_logging_rosout_enabled) {
100  status = rcl_logging_rosout_init(allocator);
101  if (RCL_RET_OK == status) {
102  g_rcl_logging_out_handlers[g_rcl_logging_num_out_handlers++] =
104  }
105  }
106  if (g_rcl_logging_ext_lib_enabled) {
107  status = rcl_logging_external_initialize(
108  file_name_prefix, config_file, g_logging_allocator);
109  if (RCL_RET_OK == status) {
110  rcl_logging_ret_t logging_status = rcl_logging_external_set_logger_level(
111  NULL, default_level);
112  if (RCL_LOGGING_RET_OK != logging_status) {
113  status = RCL_RET_ERROR;
114  }
115  g_rcl_logging_out_handlers[g_rcl_logging_num_out_handlers++] =
116  rcl_logging_ext_lib_output_handler;
117  }
118  }
119  rcutils_logging_set_output_handler(output_handler);
120  return status;
121 }
122 
123 rcl_ret_t
124 rcl_logging_configure(const rcl_arguments_t * global_args, const rcl_allocator_t * allocator)
125 {
127  global_args, allocator, &rcl_logging_multiple_output_handler);
128 }
129 
131 {
132  rcl_ret_t status = RCL_RET_OK;
133  rcutils_logging_set_output_handler(rcutils_logging_console_output_handler);
134  // In order to output log message to `rcutils_logging_console_output_handler`
135  // and `rcl_logging_ext_lib_output_handler` is not called after `rcl_logging_fini`,
136  // in addition to calling `rcutils_logging_set_output_handler`,
137  // the `g_rcl_logging_num_out_handlers` and `g_rcl_logging_out_handlers` must be updated.
138  g_rcl_logging_num_out_handlers = 1;
139  g_rcl_logging_out_handlers[0] = rcutils_logging_console_output_handler;
140 
141  if (g_rcl_logging_rosout_enabled) {
142  status = rcl_logging_rosout_fini();
143  }
144  if (RCL_RET_OK == status && g_rcl_logging_ext_lib_enabled) {
145  status = rcl_logging_external_shutdown();
146  }
147 
148  return status;
149 }
150 
152 {
153  return g_rcl_logging_rosout_enabled;
154 }
155 
156 void
158  const rcutils_log_location_t * location,
159  int severity, const char * name, rcutils_time_point_value_t timestamp,
160  const char * format, va_list * args)
161 {
162  for (uint8_t i = 0;
163  i < g_rcl_logging_num_out_handlers && NULL != g_rcl_logging_out_handlers[i]; ++i)
164  {
165  g_rcl_logging_out_handlers[i](location, severity, name, timestamp, format, args);
166  }
167 }
168 
169 static
170 void
171 rcl_logging_ext_lib_output_handler(
172  const rcutils_log_location_t * location,
173  int severity,
174  const char * name,
175  rcutils_time_point_value_t timestamp,
176  const char * format,
177  va_list * args)
178 {
179  rcl_ret_t status;
180  char msg_buf[1024] = "";
181  rcutils_char_array_t msg_array = {
182  .buffer = msg_buf,
183  .owns_buffer = false,
184  .buffer_length = 0u,
185  .buffer_capacity = sizeof(msg_buf),
186  .allocator = g_logging_allocator
187  };
188 
189  char output_buf[1024] = "";
190  rcutils_char_array_t output_array = {
191  .buffer = output_buf,
192  .owns_buffer = false,
193  .buffer_length = 0u,
194  .buffer_capacity = sizeof(output_buf),
195  .allocator = g_logging_allocator
196  };
197 
198  status = rcutils_char_array_vsprintf(&msg_array, format, *args);
199 
200  if (RCL_RET_OK == status) {
201  status = rcutils_logging_format_message(
202  location, severity, name, timestamp, msg_array.buffer, &output_array);
203  if (RCL_RET_OK != status) {
204  RCUTILS_SAFE_FWRITE_TO_STDERR("failed to format log message: ");
205  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
206  rcl_reset_error();
207  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
208  }
209  } else {
210  RCUTILS_SAFE_FWRITE_TO_STDERR("failed to format user log message: ");
211  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
212  rcl_reset_error();
213  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
214  }
215  rcl_logging_external_log(severity, name, output_array.buffer);
216  status = rcutils_char_array_fini(&msg_array);
217  if (RCL_RET_OK != status) {
218  RCUTILS_SAFE_FWRITE_TO_STDERR("failed to finalize char array: ");
219  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
220  rcl_reset_error();
221  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
222  }
223  status = rcutils_char_array_fini(&output_array);
224  if (RCL_RET_OK != status) {
225  RCUTILS_SAFE_FWRITE_TO_STDERR("failed to finalize char array: ");
226  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
227  rcl_reset_error();
228  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
229  }
230 }
231 
232 #ifdef __cplusplus
233 }
234 #endif
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_logging_rosout_enabled(void)
See if logging rosout is enabled.
Definition: logging.c:151
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_configure(const rcl_arguments_t *global_args, const rcl_allocator_t *allocator)
Configure the logging system.
Definition: logging.c:124
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_fini(void)
Definition: logging.c:130
rcutils_logging_output_handler_t rcl_logging_output_handler_t
The function signature to log messages.
Definition: logging.h:38
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)
Default output handler used by rcl.
Definition: logging.c:157
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)
Configure the logging system with the provided output handler.
Definition: logging.c:60
RCL_PUBLIC void rcl_logging_rosout_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)
The output handler outputs log messages to rosout topics.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_rosout_fini(void)
Uninitializes the rcl_logging_rosout features.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_logging_rosout_init(const rcl_allocator_t *allocator)
Initializes the rcl_logging_rosout features.
char * external_log_config_file
A file used to configure the external logging library.
rcl_log_levels_t log_levels
Log levels parsed from arguments.
bool log_rosout_disabled
A boolean value indicating if the rosout topic handler should be used for log output.
bool log_stdout_disabled
A boolean value indicating if the standard out handler should be used for log output.
bool log_ext_lib_disabled
A boolean value indicating if the external lib handler should be used for log output.
char * external_log_file_name_prefix
A prefix used to external log file name.
Hold output of parsing command line arguments.
Definition: arguments.h:36
rcl_arguments_impl_t * impl
Private implementation pointer.
Definition: arguments.h:38
Hold default logger level and other logger setting.
Definition: log_level.h:46
rcl_logger_setting_t * logger_settings
Array of logger setting.
Definition: log_level.h:50
rcl_log_severity_t default_logger_level
Minimum default logger level severity.
Definition: log_level.h:48
size_t num_logger_settings
Number of logger settings.
Definition: log_level.h:52
rcl_log_severity_t level
Minimum log level severity of the logger.
Definition: log_level.h:41
const char * name
Name for the logger.
Definition: log_level.h:39
#define RCL_RET_OK
Success return code.
Definition: types.h:28
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:36
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:30
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:25