Skip to content

Commit 712cf40

Browse files
committed
Add rotating logger
1 parent 014239d commit 712cf40

File tree

1 file changed

+96
-1
lines changed

1 file changed

+96
-1
lines changed

rcl_logging_spdlog/src/rcl_logging_spdlog.cpp

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <algorithm>
1516
#include <cerrno>
1617
#include <chrono>
1718
#include <cinttypes>
@@ -23,19 +24,26 @@
2324
#include "rcpputils/filesystem_helper.hpp"
2425
#include "rcpputils/env.hpp"
2526
#include "rcutils/allocator.h"
27+
#include "rcutils/env.h"
2628
#include "rcutils/logging.h"
2729
#include "rcutils/process.h"
2830
#include "rcutils/snprintf.h"
2931
#include "rcutils/time.h"
3032

3133
#include "spdlog/spdlog.h"
3234
#include "spdlog/sinks/basic_file_sink.h"
35+
#include "spdlog/sinks/rotating_file_sink.h"
3336

3437
#include "rcl_logging_interface/rcl_logging_interface.h"
3538

3639
static std::mutex g_logger_mutex;
3740
static std::shared_ptr<spdlog::logger> g_root_logger = nullptr;
3841

42+
constexpr std::size_t DEFAULT_ROTATING_FILE_SIZE_BYTES = 100 * 1024 * 1024;
43+
constexpr std::size_t DEFAULT_ROTATING_MAX_NUM_FILES = 5;
44+
45+
using std::size_t;
46+
3947
static spdlog::level::level_enum map_external_log_level_to_library_level(int external_level)
4048
{
4149
spdlog::level::level_enum level = spdlog::level::level_enum::off;
@@ -91,6 +99,78 @@ get_should_use_old_flushing_behavior()
9199

92100
} // namespace
93101

102+
static std::string get_string_env_var(const char * env_var_name)
103+
{
104+
const char * env_var_value;
105+
const char * error_str;
106+
error_str = rcutils_get_env(env_var_name, &env_var_value);
107+
if (error_str != nullptr) {
108+
throw std::runtime_error(
109+
std::string(
110+
"Failed to get env var '") + env_var_name + "': " + error_str);
111+
}
112+
return env_var_value; // Returns empty string for unset or empty env vars
113+
}
114+
115+
static bool contained_in(
116+
const std::vector<std::string> & check_strings,
117+
const std::string & value_str)
118+
{
119+
return std::find(check_strings.begin(), check_strings.end(), value_str) != check_strings.end();
120+
}
121+
122+
static std::string join_quoted(
123+
const std::string & sep, const std::string & quote_chars,
124+
const std::vector<std::string> & list)
125+
{
126+
if (list.empty()) {
127+
return "";
128+
}
129+
130+
std::string joined = quote_chars + *(list.begin()) + quote_chars;
131+
std::for_each(
132+
list.begin() + 1, list.end(),
133+
[&](const auto & entry) {joined += sep + quote_chars + entry + quote_chars;});
134+
135+
return joined;
136+
}
137+
138+
static bool get_bool_env_var(const char * env_var_name)
139+
{
140+
std::string value_str = get_string_env_var(env_var_name);
141+
std::vector<std::string> true_strings = {"1", "true", "TRUE"};
142+
std::vector<std::string> false_strings = {"0", "false", "FALSE", ""};
143+
144+
if (contained_in(false_strings, value_str)) {
145+
return false;
146+
} else if (contained_in(true_strings, value_str)) {
147+
return true;
148+
} else {
149+
throw std::runtime_error(
150+
std::string(
151+
"Unrecognized value for '") + env_var_name + "': '" + value_str + "'. " +
152+
"Valid truthy values: " + join_quoted(", ", "'", true_strings) + ". " +
153+
"Valid falsy values: " + join_quoted(", ", "'", false_strings) + ". "
154+
);
155+
}
156+
}
157+
158+
static size_t get_size_t_env_var(const char * env_var_name, const size_t default_val)
159+
{
160+
std::string value_str = get_string_env_var(env_var_name);
161+
if (value_str.empty()) {
162+
return default_val;
163+
} else {
164+
int value = std::stoi(value_str);
165+
if (value < 0) {
166+
throw std::runtime_error(
167+
std::string("Env var must be positive '") + env_var_name + "': '" + value_str + "'. "
168+
);
169+
}
170+
return value;
171+
}
172+
}
173+
94174
rcl_logging_ret_t rcl_logging_external_initialize(
95175
const char * config_file,
96176
rcutils_allocator_t allocator)
@@ -174,7 +254,22 @@ rcl_logging_ret_t rcl_logging_external_initialize(
174254
return RCL_LOGGING_RET_ERROR;
175255
}
176256

177-
auto sink = std::make_unique<spdlog::sinks::basic_file_sink_mt>(name_buffer, false);
257+
std::unique_ptr<spdlog::sinks::sink> sink;
258+
if (get_bool_env_var("RCL_LOGGING_SPDLOG_ROTATE_FILES") == true) {
259+
size_t max_size =
260+
get_size_t_env_var(
261+
"RCL_LOGGING_SPDLOG_ROTATING_FILE_SIZE_BYTES",
262+
DEFAULT_ROTATING_FILE_SIZE_BYTES);
263+
size_t max_files =
264+
get_size_t_env_var(
265+
"RCL_LOGGING_SPDLOG_MAX_NUM_FILES",
266+
DEFAULT_ROTATING_MAX_NUM_FILES);
267+
sink =
268+
std::make_unique<spdlog::sinks::rotating_file_sink_mt>(name_buffer, max_size, max_files);
269+
} else {
270+
sink = std::make_unique<spdlog::sinks::basic_file_sink_mt>(name_buffer, false);
271+
}
272+
178273
g_root_logger = std::make_shared<spdlog::logger>("root", std::move(sink));
179274
if (!should_use_old_flushing_behavior) {
180275
// in this case we should do the new thing (until config files are supported)

0 commit comments

Comments
 (0)