Skip to content

Commit

Permalink
Support syslog facility via environmental variable. (#7)
Browse files Browse the repository at this point in the history
Signed-off-by: Tomoya.Fujita <[email protected]>
  • Loading branch information
fujitatomoya committed Aug 30, 2024
1 parent 6060c6b commit b679682
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 5 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,15 @@ colcon build --symlink-install --cmake-clean-cache --packages-select rcl_logging
[SYSLOG(3)](https://man7.org/linux/man-pages/man3/syslog.3.html) is really simple that does not have much interfaces to control on application side, it just writes the log data on `rsyslog` Unix Domain Socket.
So we need to configure `rsyslog` how it manages the log message with `/etc/rsyslog.conf`, for example file system sink and forward the message to `fluent-bit`.

At this moment, `rcl_logging_syslog` uses syslog facility only `local1`.
More facilities should be supported in the future via environmental variables at `rcl_logging_syslog` initialization, so that user application can use appropriate facility configured by `rsyslog`.
| environmental variable | default | Note |
| :----------------------| :------ | :--- |
| `RCL_LOGGING_SYSLOG_FACILITY` | `LOG_LOCAL1` | [syslog facility](https://man7.org/linux/man-pages/man3/syslog.3.html): either of `LOG_CRON`, `LOG_DAEMON`, `LOG_SYSLOG`, `LOG_USER`, and `LOG_LOCAL0-7`. (`/etc/rsyslog.conf` must be configured accordingly.) |

Examples:

```bash
export RCL_LOGGING_SYSLOG_FACILITY="LOG_LOCAL4"
```

See more details for https://www.rsyslog.com/doc/index.html.

Expand Down
91 changes: 88 additions & 3 deletions src/rcl_logging_syslog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <syslog.h>

#include <memory>
#include <system_error>

#include <rcl_logging_interface/rcl_logging_interface.h>

Expand All @@ -32,12 +33,92 @@
#include <rcutils/strdup.h>
#include <rcutils/time.h>

static const char * facility_env_name = "RCL_LOGGING_SYSLOG_FACILITY";

// see https://codebrowser.dev/glibc/glibc/misc/syslog.c.html#LogTag
// This memory needs to be kept until closelog()
static std::shared_ptr<std::string> syslog_identity;

static const char *logger_name = "rcl_logging_syslog";

typedef struct facility_index {
const char *c_name;
const int c_value;
} FACILITY_INDEX;

const FACILITY_INDEX facility_table[] =
{
{ "LOG_CRON", LOG_CRON },
{ "LOG_DAEMON", LOG_DAEMON },
{ "LOG_SYSLOG", LOG_SYSLOG },
{ "LOG_USER", LOG_USER },
{ "LOG_LOCAL0", LOG_LOCAL0 },
{ "LOG_LOCAL1", LOG_LOCAL1 },
{ "LOG_LOCAL2", LOG_LOCAL2 },
{ "LOG_LOCAL3", LOG_LOCAL3 },
{ "LOG_LOCAL4", LOG_LOCAL4 },
{ "LOG_LOCAL5", LOG_LOCAL5 },
{ "LOG_LOCAL6", LOG_LOCAL6 },
{ "LOG_LOCAL7", LOG_LOCAL7 },
{ NULL, -1 }
};

static const char *get_facility_name(int facility) {
for (auto f = facility_table; f->c_name != NULL; f++) {
if (f->c_value == facility) {
return f->c_name;
}
}
return "Unknown facility";
}

static int get_syslog_facility(void)
{
// default is LOG_LOCAL1
int syslog_facility = LOG_LOCAL1;

try {
std::string facility_string = rcpputils::get_env_var(facility_env_name);
if (facility_string.empty()) {
return syslog_facility;
}

if (!facility_string.compare("LOG_USER")) {
syslog_facility = LOG_USER;
} else if (!facility_string.compare("LOG_DAEMON")) {
syslog_facility = LOG_DAEMON;
} else if (!facility_string.compare("LOG_SYSLOG")) {
syslog_facility = LOG_SYSLOG;
} else if (!facility_string.compare("LOG_CRON")) {
syslog_facility = LOG_CRON;
} else if (!facility_string.compare("LOG_LOCAL0")) {
syslog_facility = LOG_LOCAL0;
} else if (!facility_string.compare("LOG_LOCAL1")) {
syslog_facility = LOG_LOCAL1;
} else if (!facility_string.compare("LOG_LOCAL2")) {
syslog_facility = LOG_LOCAL2;
} else if (!facility_string.compare("LOG_LOCAL3")) {
syslog_facility = LOG_LOCAL3;
} else if (!facility_string.compare("LOG_LOCAL4")) {
syslog_facility = LOG_LOCAL4;
} else if (!facility_string.compare("LOG_LOCAL5")) {
syslog_facility = LOG_LOCAL5;
} else if (!facility_string.compare("LOG_LOCAL6")) {
syslog_facility = LOG_LOCAL6;
} else if (!facility_string.compare("LOG_LOCAL7")) {
syslog_facility = LOG_LOCAL7;
} else {
syslog_facility = LOG_LOCAL1;
}
} catch (const std::runtime_error & error) {
throw std::runtime_error(
std::string("failed to get env var '") + facility_env_name + "': " + error.what()
);
}

return syslog_facility;
}

static int rcutil_to_syslog_level(int rcutil_level)
{
int syslog_level;
Expand Down Expand Up @@ -126,10 +207,14 @@ rcl_logging_ret_t rcl_logging_external_initialize(
});
syslog_identity = std::make_shared<std::string>(basec);

// Check and fetch the syslog facility from environmental variable
int syslog_facility = get_syslog_facility();
RCUTILS_LOG_DEBUG_NAMED(
logger_name,
"syslog facility is set to %s", get_facility_name(syslog_facility));

// Use user specified filename, or executable name to openlog(3) identity.
// TODO(@fujitatomoya): facility should be set by environmental variable,
// so that user can control the log facility as it set on rsyslog.conf.
openlog(syslog_identity->c_str(), LOG_PID, LOG_LOCAL1);
openlog(syslog_identity->c_str(), LOG_PID, syslog_facility);

return RCL_LOGGING_RET_OK;
}
Expand Down

0 comments on commit b679682

Please sign in to comment.