rosconsole icon indicating copy to clipboard operation
rosconsole copied to clipboard

Logging to journald?

Open mgrrx opened this issue 6 years ago • 3 comments

We are currently looking into rosconsole to find a way to directly write to the system journal using sd_journal_send. One could of course simply use the builtin feature of log4cxx to log to syslog and use the compatibility layer of systemd for syslog, but this comes with one big limitation: Syslog uses the program_invocation_short_name to identify the sender, which is not the perfect way to identify a program in a ROS context, especially when one has two instances of the same binary with different node names.

The big benefit of systemd's journal is that one can set the SYSLOG_IDENTIFIER. The obvious idea is to set this value to the node name which makes it really convenient to read the journal and I have code ready that does exactly this. Sadly this can't be done given the current dependency structure since the node name is only available in ros/this_node.h in roscpp which is a downstream package.

...

void SystemJournalAppender::append(const log4cxx::spi::LoggingEventPtr& event,
                                   log4cxx::helpers::Pool&)
{
  const log4cxx::spi::LocationInfo& location_info = event->getLocationInformation();
  ::sd_journal_send(
    "MESSAGE=%s", event->getMessage().c_str(),
    "PRIORITY=%i", event->getLevel()->getSyslogEquivalent(),
    "CODE_FILE=%s", location_info.getFileName(),
    "CODE_LINE=%i", location_info.getLineNumber(),
    "CODE_FUNC=%s", location_info.getMethodName().c_str(),
    "SYSLOG_IDENTIFIER=%s", ros::this_node::getName().c_str(),
    NULL);
}

I'm opening this ticket to ask for advice on how to continue here. I've two suggestions:

  1. Add the node name as an argument to ROSCONSOLE_AUTOINIT and ros::console::initialize. This internally sets a global variable which can be used in the log appender.
  2. Use pluginlib to load additional plugins during runtime, just before the log4cxx configuration is parsed log4cxx::PropertyConfigurator::configure(config_file). This requires some additional work to make pluginlib use console_bridge instead of rosconsole (https://github.com/ros/pluginlib/issues/81). The advantage would be that it allows others to implement their own custom log appenders.

I personally prefer solution 2 but this would of course be a significant change.

mgrrx avatar Sep 05 '18 21:09 mgrrx

I started implementing what is needed for solution 2:

  1. https://github.com/magazino/rosconsole/tree/log4cxx-appender registers the ROSConsoleStdioAppender class as a log4cxx appender which can be configured using the log4cxx config file. This would allow me to disable the print to stdout/stderr.
  2. https://github.com/magazino/pluginlib/tree/kinetic-console-bridge (not yet ported to melodic) replaces rosconsole with console bridge. This is required to use pluginlib in rosconsole.
  3. https://github.com/magazino/rosconsole/tree/custom-appenders adds pluginlib as a dependency and loads all available ronsconsole log4cxx plugins right before the config file is parsed. This sets the basis to write custom log appenders.
  4. https://github.com/magazino/systemd_ros adds a custom log4cxx appender which writes to the journal.

I don't know where to call REGISTER_ROSCONSOLE_BRIDGE and add rosconsole_bridge to forward the console bridge output of pluginlib. I was wondering why rosconsole_bridge is a separate package at all and not part of rosconsole.

Would be great to get some feedback on my ideas and how to move forward.

mgrrx avatar Sep 22 '18 20:09 mgrrx

Any updates here? This would be very useful!

flixr avatar Jun 07 '20 07:06 flixr

This would be very nice! As a backup solution, wouldn't it be possible to create a node that subscribes to /rosout and copy the logs to Journald?

Hugal31 avatar Jul 29 '21 09:07 Hugal31