Skip to content

Commit

Permalink
Allow configuring logging directory through environment variables (#70)
Browse files Browse the repository at this point in the history
* Added ability to set log dir from env var

Signed-off-by: tgreier <[email protected]>

* Updated tests

Signed-off-by: tgreier <[email protected]>

* Fixed depends

Signed-off-by: tgreier <[email protected]>
  • Loading branch information
tgreier authored Jan 7, 2021
1 parent 72fa46d commit 6ad3966
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 73 deletions.
2 changes: 2 additions & 0 deletions rcl_logging_spdlog/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ find_package(ament_cmake_ros REQUIRED)
find_package(rcutils REQUIRED)
find_package(spdlog_vendor REQUIRED) # Provides spdlog 1.3.1 on platforms without it.
find_package(spdlog REQUIRED)
find_package(rcpputils REQUIRED)

if(NOT WIN32)
add_compile_options(-Wall -Wextra -Wpedantic)
Expand All @@ -29,6 +30,7 @@ target_link_libraries(${PROJECT_NAME} spdlog::spdlog)
ament_target_dependencies(${PROJECT_NAME}
rcutils
spdlog
rcpputils
)

target_compile_definitions(${PROJECT_NAME} PRIVATE "RCL_LOGGING_BUILDING_DLL")
Expand Down
23 changes: 23 additions & 0 deletions rcl_logging_spdlog/include/rcl_logging_spdlog/logging_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,29 @@ RCL_LOGGING_PUBLIC
RCUTILS_WARN_UNUSED
rcl_logging_ret_t rcl_logging_external_set_logger_level(const char * name, int level);

/// Get the logging directory.
/**
* Uses various environment variables to construct a logging directory path.
*
* Use $ROS_LOG_DIR if ROS_LOG_DIR is set and not empty.
* Otherwise, use $ROS_HOME/log, using ~/.ros for ROS_HOME if not set or if empty.
*
* It also expands an initial '~' to the current user's home directory,
* and converts the path separator if necessary.
*
* If successful, the directory C string should be deallocated using the given allocator when it is
* no longer needed.
*
* \param[in] allocator The allocator to use for memory allocation.
* \param[out] directory The C string pointer at which to write the directory path.
* Only meaningful if the call is successful. Must not be nullptr and must point to nullptr.
* \return RCL_LOGGING_RET_OK if successful, or
* \return RCL_LOGGING_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return RCL_LOGGING_RET_ERROR if an unspecified error occurs.
*/
RCL_LOGGING_PUBLIC
rcl_logging_ret_t
rcl_logging_get_logging_directory(rcutils_allocator_t allocator, char ** directory);

#ifdef __cplusplus
} /* extern "C" */
Expand Down
2 changes: 1 addition & 1 deletion rcl_logging_spdlog/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
<build_depend>spdlog</build_depend>

<depend>rcutils</depend>
<depend>rcpputils</depend>

<exec_depend>spdlog_vendor</exec_depend>
<exec_depend>spdlog</exec_depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>performance_test_fixture</test_depend>
<test_depend>rcpputils</test_depend>

<member_of_group>rcl_logging_packages</member_of_group>

Expand Down
142 changes: 113 additions & 29 deletions rcl_logging_spdlog/src/rcl_logging_spdlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <rcpputils/filesystem_helper.hpp>
#include <rcutils/allocator.h>
#include <rcutils/filesystem.h>
#include <rcutils/get_env.h>
#include <rcutils/logging.h>
#include <rcutils/process.h>
#include <rcutils/snprintf.h>
#include <rcutils/time.h>
#include <rcutils/strdup.h>
#include <rcutils/format_string.h>

#include <cerrno>
#include <cinttypes>
Expand Down Expand Up @@ -82,36 +85,20 @@ rcl_logging_ret_t rcl_logging_external_initialize(
// To be compatible with ROS 1, we construct a default filename of
// the form ~/.ros/log/<exe>_<pid>_<milliseconds-since-epoch>.log

// First get the home directory.
const char * homedir = rcutils_get_home_dir();
if (homedir == nullptr) {
// We couldn't get the home directory; it is not really going to be
// possible to do logging properly, so get out of here without setting
// up logging.
RCUTILS_SET_ERROR_MSG("Failed to get users home directory");
return RCL_LOGGING_RET_ERROR;
}

// SPDLOG doesn't automatically create the log directories, so make them
// by hand here.
char name_buffer[4096] = {0};
int print_ret = rcutils_snprintf(name_buffer, sizeof(name_buffer), "%s/.ros", homedir);
if (print_ret < 0) {
RCUTILS_SET_ERROR_MSG("Failed to create home directory string");
return RCL_LOGGING_RET_ERROR;
}
if (!rcutils_mkdir(name_buffer)) {
RCUTILS_SET_ERROR_MSG("Failed to create user .ros directory");
char * logdir = nullptr;
rcl_logging_ret_t dir_ret = rcl_logging_get_logging_directory(allocator, &logdir);
if (RCL_LOGGING_RET_OK != dir_ret) {
// We couldn't get the log directory, so get out of here without setting up
// logging.
RCUTILS_SET_ERROR_MSG("Failed to get logging directory");
return RCL_LOGGING_RET_ERROR;
}

print_ret = rcutils_snprintf(name_buffer, sizeof(name_buffer), "%s/.ros/log", homedir);
if (print_ret < 0) {
RCUTILS_SET_ERROR_MSG("Failed to create log directory string");
return RCL_LOGGING_RET_ERROR;
}
if (!rcutils_mkdir(name_buffer)) {
RCUTILS_SET_ERROR_MSG("Failed to create user log directory");
// SPDLOG doesn't automatically create the log directories, so create them
rcpputils::fs::path logdir_path(logdir);
if (!rcpputils::fs::create_directories(logdir_path)) {
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING("Failed to create log directory: %s", logdir);
allocator.deallocate(logdir, allocator.state);
return RCL_LOGGING_RET_ERROR;
}

Expand All @@ -135,10 +122,12 @@ rcl_logging_ret_t rcl_logging_external_initialize(
return RCL_LOGGING_RET_ERROR;
}

print_ret = rcutils_snprintf(
char name_buffer[4096] = {0};
int print_ret = rcutils_snprintf(
name_buffer, sizeof(name_buffer),
"%s/.ros/log/%s_%i_%" PRId64 ".log", homedir,
"%s/%s_%i_%" PRId64 ".log", logdir,
basec, rcutils_get_pid(), ms_since_epoch);
allocator.deallocate(logdir, allocator.state);
allocator.deallocate(basec, allocator.state);
if (print_ret < 0) {
RCUTILS_SET_ERROR_MSG("Failed to create log file name string");
Expand Down Expand Up @@ -175,6 +164,101 @@ rcl_logging_ret_t rcl_logging_external_set_logger_level(const char * name, int l
return RCL_LOGGING_RET_OK;
}


static char *
rcl_expand_user(const char * path, rcutils_allocator_t allocator)
{
if (NULL == path) {
return NULL;
}

if ('~' != path[0]) {
return rcutils_strdup(path, allocator);
}

const char * homedir = rcutils_get_home_dir();
if (NULL == homedir) {
return NULL;
}
return rcutils_format_string_limit(
allocator,
strlen(homedir) + strlen(path),
"%s%s",
homedir,
path + 1);
}

rcl_logging_ret_t
rcl_logging_get_logging_directory(rcutils_allocator_t allocator, char ** directory)
{
if (NULL == directory) {
RCUTILS_SET_ERROR_MSG("directory argument must not be null");
return RCL_LOGGING_RET_ERROR;
}
if (NULL != *directory) {
RCUTILS_SET_ERROR_MSG("directory argument must point to null");
return RCL_LOGGING_RET_ERROR;
}

const char * log_dir_env;
const char * err = rcutils_get_env("ROS_LOG_DIR", &log_dir_env);
if (NULL != err) {
RCUTILS_SET_ERROR_MSG("rcutils_get_env failed");
return RCL_LOGGING_RET_ERROR;
}
if ('\0' != *log_dir_env) {
*directory = rcutils_strdup(log_dir_env, allocator);
if (NULL == *directory) {
RCUTILS_SET_ERROR_MSG("rcutils_strdup failed");
return RCL_LOGGING_RET_ERROR;
}
} else {
const char * ros_home_dir_env;
err = rcutils_get_env("ROS_HOME", &ros_home_dir_env);
if (NULL != err) {
RCUTILS_SET_ERROR_MSG("rcutils_get_env failed");
return RCL_LOGGING_RET_ERROR;
}
char * ros_home_dir;
if ('\0' == *ros_home_dir_env) {
ros_home_dir = rcutils_join_path("~", ".ros", allocator);
if (NULL == ros_home_dir) {
RCUTILS_SET_ERROR_MSG("rcutils_join_path failed");
return RCL_LOGGING_RET_ERROR;
}
} else {
ros_home_dir = rcutils_strdup(ros_home_dir_env, allocator);
if (NULL == ros_home_dir) {
RCUTILS_SET_ERROR_MSG("rcutils_strdup failed");
return RCL_LOGGING_RET_ERROR;
}
}
*directory = rcutils_join_path(ros_home_dir, "log", allocator);
allocator.deallocate(ros_home_dir, allocator.state);
if (NULL == *directory) {
RCUTILS_SET_ERROR_MSG("rcutils_join_path failed");
return RCL_LOGGING_RET_ERROR;
}
}

char * directory_maybe_not_expanded = *directory;
*directory = rcl_expand_user(directory_maybe_not_expanded, allocator);
allocator.deallocate(directory_maybe_not_expanded, allocator.state);
if (NULL == *directory) {
RCUTILS_SET_ERROR_MSG("rcutils_expand_user failed");
return RCL_LOGGING_RET_ERROR;
}

char * directory_maybe_not_native = *directory;
*directory = rcutils_to_native_path(directory_maybe_not_native, allocator);
allocator.deallocate(directory_maybe_not_native, allocator.state);
if (NULL == *directory) {
RCUTILS_SET_ERROR_MSG("rcutils_to_native_path failed");
return RCL_LOGGING_RET_ERROR;
}
return RCL_LOGGING_RET_OK;
}

#ifdef __cplusplus
} /* extern "C" */
#endif
Loading

0 comments on commit 6ad3966

Please sign in to comment.