logger.cpp
Go to the documentation of this file.
1 // Logs all output to a log file for the run
2 // Author: Max Schwarz <max.schwarz@uni-bonn.de>
3 
4 #include "logger.h"
5 #include "fmt/format.h"
6 
7 #include <array>
8 #include <cerrno>
9 #include <cstdio>
10 #include <cstring>
11 #include <ctime>
12 #include <stdexcept>
13 #include <iterator>
14 
15 #include <sys/time.h>
16 
17 #include <fmt/format.h>
18 
19 #include <syslog.h>
20 
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24 
25 namespace rosmon
26 {
27 
28 namespace
29 {
30  int prioFromEventType(LogEvent::Type type)
31  {
32  switch(type)
33  {
34  case LogEvent::Type::Error: return 3;
35  case LogEvent::Type::Warning: return 4;
36  case LogEvent::Type::Info: return 6;
37  case LogEvent::Type::Raw: return 6;
38  case LogEvent::Type::Debug: return 7;
39  }
40 
41  return 6;
42  }
43 }
44 
45 FileLogger::FileLogger(const std::string& path, bool flush)
46  : m_flush{flush}
47 {
48  m_flush = flush;
49  m_file = fopen(path.c_str(), "ae");
50  if(!m_file)
51  {
52  throw std::runtime_error(fmt::format(
53  "Could not open log file: {}", strerror(errno)
54  ));
55  }
56 }
57 
59 {
60  if(m_file)
61  fclose(m_file);
62 }
63 
64 void FileLogger::log(const LogEvent& event)
65 {
66  struct timeval tv;
67  memset(&tv, 0, sizeof(tv));
68  gettimeofday(&tv, nullptr);
69 
70  struct tm btime;
71  memset(&btime, 0, sizeof(tv));
72  localtime_r(&tv.tv_sec, &btime);
73 
74  char timeString[100];
75  strftime(timeString, sizeof(timeString), "%a %F %T", &btime);
76 
77  unsigned int len = event.message.length();
78  while(len != 0 && (event.message[len-1] == '\n' || event.message[len-1] == '\r'))
79  len--;
80 
81  fmt::print(m_file, "{}.{:03d}: {:>20}: ",
82  timeString, tv.tv_usec / 1000,
83  event.source.c_str()
84  );
85  fwrite(event.message.c_str(), 1, len, m_file);
86  fputc('\n', m_file);
87 
88  if(m_flush)
89  fflush(m_file);
90 }
91 
92 
93 SyslogLogger::SyslogLogger(const std::string& launchFileName)
94 {
95  m_tag = fmt::format("rosmon@{}", launchFileName);
96  openlog(m_tag.c_str(), 0, LOG_USER);
97 }
98 
99 void SyslogLogger::log(const LogEvent& event)
100 {
101  syslog(prioFromEventType(event.type), "%20s: %s", event.source.c_str(), event.message.c_str());
102 }
103 
104 
105 SystemdLogger::SystemdLogger(const std::string& launchFileName)
106  : m_launchFileName{launchFileName}
107 {
108  m_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
109  if(m_fd < 0)
110  throw std::runtime_error{fmt::format("Could not create socket: {}", strerror(errno))};
111 
112  int size = 8*1024*1024;
113  if(setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0)
114  perror("WARNING: Could not increase SO_SNDBUF size");
115 
116  sockaddr_un addr{};
117  addr.sun_family = AF_UNIX;
118  strncpy(addr.sun_path, "/run/systemd/journal/socket", sizeof(addr.sun_path)-1);
119 
120  if(connect(m_fd, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) != 0)
121  throw NotAvailable{fmt::format("Systemd Journal not available: {}", strerror(errno))};
122 }
123 
125 {
126  if(m_fd >= 0)
127  close(m_fd);
128 }
129 
130 void SystemdLogger::log(const LogEvent& event)
131 {
132  fmt::memory_buffer buffer;
133 
134  fmt::format_to(std::back_inserter(buffer),
135  "PRIORITY={}\n"
136  "ROSMON_LAUNCH_FILE={}\n"
137  "ROSMON_NODE={}\n"
138  "SYSLOG_IDENTIFIER=rosmon@{}\n",
139  prioFromEventType(event.type),
141  event.source,
143  );
144 
145  std::string msg = fmt::format("{}: {}", event.source, event.message);
146 
147  if(msg.find('\n') == std::string::npos)
148  fmt::format_to(std::back_inserter(buffer), "MESSAGE={}\n", msg);
149  else
150  {
151  buffer.append(std::string{"MESSAGE\n"});
152  std::array<uint8_t, 8> size;
153  uint64_t sizeInt = msg.length();
154  for(int i = 0; i < 8; ++i)
155  {
156  size[i] = sizeInt & 0xFF;
157  sizeInt >>= 8;
158  }
159 
160  buffer.append(size);
161  buffer.append(msg);
162  buffer.append(std::string{"\n"});
163  }
164 
165  if(write(m_fd, buffer.data(), buffer.size()) < 0)
166  fprintf(stderr, "Could not write to systemd log: %s\n", strerror(errno));
167 }
168 
169 }
rosmon::LogEvent::source
std::string source
Definition: log_event.h:60
rosmon::SyslogLogger::m_tag
std::string m_tag
Definition: logger.h:54
rosmon
Definition: diagnostics_publisher.cpp:34
rosmon::LogEvent
Definition: log_event.h:13
rosmon::SystemdLogger::m_fd
int m_fd
Definition: logger.h:78
rosmon::SystemdLogger::log
void log(const LogEvent &event) override
Definition: logger.cpp:130
logger.h
rosmon::LogEvent::Type
Type
Definition: log_event.h:16
rosmon::LogEvent::message
std::string message
Definition: log_event.h:61
rosmon::LogEvent::Type::Info
@ Info
rosmon::SystemdLogger::m_launchFileName
std::string m_launchFileName
Definition: logger.h:77
rosmon::LogEvent::Type::Debug
@ Debug
rosmon::SystemdLogger::SystemdLogger
SystemdLogger(const std::string &launchFileName)
Definition: logger.cpp:105
rosmon::LogEvent::type
Type type
Definition: log_event.h:62
rosmon::FileLogger::log
void log(const LogEvent &event) override
Log message.
Definition: logger.cpp:64
rosmon::SyslogLogger::SyslogLogger
SyslogLogger(const std::string &launchFileName)
Definition: logger.cpp:93
rosmon::SystemdLogger::~SystemdLogger
~SystemdLogger() override
Definition: logger.cpp:124
rosmon::FileLogger::m_flush
bool m_flush
Definition: logger.h:40
rosmon::LogEvent::Type::Warning
@ Warning
rosmon::FileLogger::m_file
FILE * m_file
Definition: logger.h:39
rosmon::FileLogger::FileLogger
FileLogger(const std::string &path, bool flush=false)
Constructor.
Definition: logger.cpp:45
rosmon::LogEvent::Type::Error
@ Error
rosmon::LogEvent::Type::Raw
@ Raw
rosmon::SyslogLogger::log
void log(const LogEvent &event) override
Definition: logger.cpp:99
rosmon::FileLogger::~FileLogger
~FileLogger() override
Definition: logger.cpp:58


rosmon_core
Author(s): Max Schwarz
autogenerated on Wed Feb 21 2024 04:01:14