EtcPal  0.3.0
ETC Platform Abstraction Layer (EtcPal)
View other versions:
log.h
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright 2020 ETC Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************
16  * This file is a part of EtcPal. For more information, go to:
17  * https://github.com/ETCLabs/EtcPal
18  ******************************************************************************/
19 
22 
23 #ifndef ETCPAL_CPP_LOG_H_
24 #define ETCPAL_CPP_LOG_H_
25 
26 #include <cstdarg>
27 #include <cstdio>
28 #include <cstring>
29 #include <memory>
30 #include <queue>
31 #include <string>
32 #include "etcpal/common.h"
33 #include "etcpal/log.h"
34 #include "etcpal/cpp/common.h"
35 #include "etcpal/cpp/lock.h"
36 #include "etcpal/cpp/thread.h"
37 
38 namespace etcpal
39 {
116 
121 {
122 public:
124  LogTimestamp() = default;
125  constexpr LogTimestamp(unsigned int year,
126  unsigned int month,
127  unsigned int day,
128  unsigned int hour,
129  unsigned int minute,
130  unsigned int second,
131  unsigned int msec = 0,
132  int utc_offset = 0);
133 
134  bool IsValid() const noexcept;
135 
136  constexpr const EtcPalLogTimestamp& get() const noexcept;
138 
139  static LogTimestamp Invalid();
140 
141 private:
142  EtcPalLogTimestamp timestamp_{};
143 };
144 
154 constexpr LogTimestamp::LogTimestamp(unsigned int year,
155  unsigned int month,
156  unsigned int day,
157  unsigned int hour,
158  unsigned int minute,
159  unsigned int second,
160  unsigned int msec,
161  int utc_offset)
162  : timestamp_{year, month, day, hour, minute, second, msec, utc_offset}
163 {
164 }
165 
167 inline bool LogTimestamp::IsValid() const noexcept
168 {
169  return etcpal_validate_log_timestamp(&timestamp_);
170 }
171 
173 constexpr const EtcPalLogTimestamp& LogTimestamp::get() const noexcept
174 {
175  return timestamp_;
176 }
177 
180 {
181  return timestamp_;
182 }
183 
186 {
187  return LogTimestamp{};
188 }
189 
197 {
198 public:
199  virtual LogTimestamp GetLogTimestamp();
200 
211  virtual void HandleLogMessage(const EtcPalLogStrings& strings) = 0;
212 };
213 
217 {
218  return LogTimestamp::Invalid();
219 }
220 
224 {
225  Direct,
226  Queued
227 };
228 
234 class Logger
235 {
236 public:
237  Logger();
238 
239  bool Startup(LogMessageHandler& message_handler);
240  void Shutdown();
241 
242  bool CanLog(int pri) const noexcept;
243  void Log(int pri, const char* format, ...);
244 
247  void Debug(const char* format, ...);
248  void Info(const char* format, ...);
249  void Notice(const char* format, ...);
250  void Warning(const char* format, ...);
251  void Error(const char* format, ...);
252  void Critical(const char* format, ...);
253  void Alert(const char* format, ...);
254  void Emergency(const char* format, ...);
256 
259  LogDispatchPolicy dispatch_policy() const noexcept;
260  int log_mask() const noexcept;
261  int log_action() const noexcept;
262  int syslog_facility() const noexcept;
263  const char* syslog_hostname() const noexcept;
264  const char* syslog_app_name() const noexcept;
265  const char* syslog_procid() const noexcept;
266  const EtcPalLogParams& log_params() const noexcept;
268 
271  Logger& SetDispatchPolicy(LogDispatchPolicy new_policy) noexcept;
272  Logger& SetLogMask(int log_mask) noexcept;
273  Logger& SetLogAction(int log_action) noexcept;
274  Logger& SetSyslogFacility(int facility) noexcept;
275  Logger& SetSyslogHostname(const char* hostname) noexcept;
276  Logger& SetSyslogHostname(const std::string& hostname) noexcept;
277  Logger& SetSyslogAppName(const char* app_name) noexcept;
278  Logger& SetSyslogAppName(const std::string& app_name) noexcept;
279  Logger& SetSyslogProcId(const char* proc_id) noexcept;
280  Logger& SetSyslogProcId(const std::string& proc_id) noexcept;
281  Logger& SetSyslogProcId(int proc_id) noexcept;
283 
284 private:
285  void LogInternal(int pri, const char* format, std::va_list args);
286  void LogThreadRun();
287  void EmptyLogQueue();
288 
290  EtcPalLogParams log_params_{};
291 
292  struct LogMessage
293  {
294  int pri;
295  char buf[ETCPAL_RAW_LOG_MSG_MAX_LEN];
296  };
297 
298  // Used when dispatch_policy_ == Queued
299  // This implementation will become more elegant with the addition of new queue APIs. This is
300  // being tracked with ETCPAL-43 and ETCPAL-46.
301  std::queue<LogMessage> msg_q_;
302  std::unique_ptr<etcpal::Signal> signal_;
303  std::unique_ptr<etcpal::Mutex> mutex_;
304  etcpal::Thread thread_;
305  bool running_{false};
306 };
307 
309 
310 extern "C" inline void LogCallbackFn(void* context, const EtcPalLogStrings* strings)
311 {
312  if (context && strings)
313  {
314  static_cast<LogMessageHandler*>(context)->HandleLogMessage(*strings);
315  }
316 }
317 
318 extern "C" inline void LogTimestampFn(void* context, EtcPalLogTimestamp* timestamp)
319 {
320  if (context && timestamp)
321  {
322  *timestamp = static_cast<LogMessageHandler*>(context)->GetLogTimestamp().get();
323  }
324 }
325 
327 
328 inline Logger::Logger()
329 {
330  // Default logging parameters
332  log_params_.log_fn = LogCallbackFn;
334  log_params_.time_fn = LogTimestampFn;
335  log_params_.context = nullptr;
336 }
337 
344 inline bool Logger::Startup(LogMessageHandler& message_handler)
345 {
347  return false;
348 
349  if (!etcpal_validate_log_params(&log_params_))
350  {
352  return false;
353  }
354 
355  log_params_.context = &message_handler;
356 
357  if (dispatch_policy_ == LogDispatchPolicy::Queued)
358  {
359  // Start the log dispatch thread
360  running_ = true;
361  signal_.reset(new etcpal::Signal);
362  mutex_.reset(new etcpal::Mutex);
363  if (thread_.SetName("EtcPalLoggerThread").Start(&Logger::LogThreadRun, this))
364  {
365  return true;
366  }
367  else
368  {
370  return false;
371  }
372  }
373  else
374  {
375  running_ = true;
376  return true;
377  }
378 }
379 
384 inline void Logger::Shutdown()
385 {
386  if (running_)
387  {
388  running_ = false;
389  if (dispatch_policy_ == LogDispatchPolicy::Queued)
390  {
391  signal_->Notify();
392  thread_.Join();
393  }
395  log_params_.context = nullptr;
396  }
397 }
398 
402 inline bool Logger::CanLog(int pri) const noexcept
403 {
404  return etcpal_can_log(&log_params_, pri);
405 }
406 
414 inline void Logger::Log(int pri, const char* format, ...)
415 {
416  std::va_list args;
417  va_start(args, format);
418  LogInternal(pri, format, args);
419  va_end(args);
420 }
421 
423 inline void Logger::Debug(const char* format, ...)
424 {
425  std::va_list args;
426  va_start(args, format);
427  LogInternal(ETCPAL_LOG_DEBUG, format, args);
428  va_end(args);
429 }
430 
432 inline void Logger::Info(const char* format, ...)
433 {
434  std::va_list args;
435  va_start(args, format);
436  LogInternal(ETCPAL_LOG_INFO, format, args);
437  va_end(args);
438 }
439 
441 inline void Logger::Notice(const char* format, ...)
442 {
443  std::va_list args;
444  va_start(args, format);
445  LogInternal(ETCPAL_LOG_NOTICE, format, args);
446  va_end(args);
447 }
448 
450 inline void Logger::Warning(const char* format, ...)
451 {
452  std::va_list args;
453  va_start(args, format);
454  LogInternal(ETCPAL_LOG_WARNING, format, args);
455  va_end(args);
456 }
457 
459 inline void Logger::Error(const char* format, ...)
460 {
461  std::va_list args;
462  va_start(args, format);
463  LogInternal(ETCPAL_LOG_ERR, format, args);
464  va_end(args);
465 }
466 
468 inline void Logger::Critical(const char* format, ...)
469 {
470  std::va_list args;
471  va_start(args, format);
472  LogInternal(ETCPAL_LOG_CRIT, format, args);
473  va_end(args);
474 }
475 
477 inline void Logger::Alert(const char* format, ...)
478 {
479  std::va_list args;
480  va_start(args, format);
481  LogInternal(ETCPAL_LOG_ALERT, format, args);
482  va_end(args);
483 }
484 
486 inline void Logger::Emergency(const char* format, ...)
487 {
488  std::va_list args;
489  va_start(args, format);
490  LogInternal(ETCPAL_LOG_EMERG, format, args);
491  va_end(args);
492 }
493 
496 {
497  return dispatch_policy_;
498 }
499 
501 inline int Logger::log_mask() const noexcept
502 {
503  return log_params_.log_mask;
504 }
505 
507 inline int Logger::log_action() const noexcept
508 {
509  return log_params_.action;
510 }
511 
513 inline int Logger::syslog_facility() const noexcept
514 {
515  return log_params_.syslog_params.facility;
516 }
517 
519 inline const char* Logger::syslog_hostname() const noexcept
520 {
521  return log_params_.syslog_params.hostname;
522 }
523 
525 inline const char* Logger::syslog_app_name() const noexcept
526 {
527  return log_params_.syslog_params.app_name;
528 }
529 
531 inline const char* Logger::syslog_procid() const noexcept
532 {
533  return log_params_.syslog_params.procid;
534 }
535 
541 inline const EtcPalLogParams& Logger::log_params() const noexcept
542 {
543  return log_params_;
544 }
545 
552 {
553  dispatch_policy_ = new_policy;
554  return *this;
555 }
556 
564 inline Logger& Logger::SetLogMask(int log_mask) noexcept
565 {
566  log_params_.log_mask = log_mask;
567  return *this;
568 }
569 
571 inline Logger& Logger::SetLogAction(int log_action) noexcept
572 {
573  log_params_.action = log_action;
574  return *this;
575 }
576 
578 inline Logger& Logger::SetSyslogFacility(int facility) noexcept
579 {
580  log_params_.syslog_params.facility = facility;
581  return *this;
582 }
583 
585 inline Logger& Logger::SetSyslogHostname(const char* hostname) noexcept
586 {
587  ETCPAL_MSVC_NO_DEP_WRN strncpy(log_params_.syslog_params.hostname, hostname, ETCPAL_LOG_HOSTNAME_MAX_LEN - 1);
588  log_params_.syslog_params.hostname[ETCPAL_LOG_HOSTNAME_MAX_LEN - 1] = '\0';
589  return *this;
590 }
591 
593 inline Logger& Logger::SetSyslogHostname(const std::string& hostname) noexcept
594 {
595  SetSyslogHostname(hostname.c_str());
596  return *this;
597 }
598 
600 inline Logger& Logger::SetSyslogAppName(const char* app_name) noexcept
601 {
602  ETCPAL_MSVC_NO_DEP_WRN strncpy(log_params_.syslog_params.app_name, app_name, ETCPAL_LOG_APP_NAME_MAX_LEN - 1);
603  log_params_.syslog_params.app_name[ETCPAL_LOG_APP_NAME_MAX_LEN - 1] = '\0';
604  return *this;
605 }
606 
608 inline Logger& Logger::SetSyslogAppName(const std::string& app_name) noexcept
609 {
610  SetSyslogAppName(app_name.c_str());
611  return *this;
612 }
613 
615 inline Logger& Logger::SetSyslogProcId(const char* proc_id) noexcept
616 {
617  ETCPAL_MSVC_NO_DEP_WRN strncpy(log_params_.syslog_params.procid, proc_id, ETCPAL_LOG_PROCID_MAX_LEN - 1);
618  log_params_.syslog_params.procid[ETCPAL_LOG_PROCID_MAX_LEN - 1] = '\0';
619  return *this;
620 }
621 
623 inline Logger& Logger::SetSyslogProcId(const std::string& proc_id) noexcept
624 {
625  SetSyslogProcId(proc_id.c_str());
626  return *this;
627 }
628 
630 inline Logger& Logger::SetSyslogProcId(int proc_id) noexcept
631 {
632  ETCPAL_MSVC_NO_DEP_WRN sprintf(log_params_.syslog_params.procid, "%d", proc_id);
633  return *this;
634 }
635 
636 // Private functions
637 
638 inline void Logger::LogInternal(int pri, const char* format, std::va_list args)
639 {
640  if (running_)
641  {
642  if (dispatch_policy_ == LogDispatchPolicy::Direct)
643  {
644  etcpal_vlog(&log_params_, pri, format, args);
645  }
646  else
647  {
648  {
649  etcpal::MutexGuard lock(*mutex_);
650  msg_q_.emplace();
651  msg_q_.back().pri = pri;
652  vsnprintf(msg_q_.back().buf, ETCPAL_RAW_LOG_MSG_MAX_LEN, format, args);
653  }
654  signal_->Notify();
655  }
656  }
657 }
658 
659 inline void Logger::LogThreadRun()
660 {
661  while (running_)
662  {
663  EmptyLogQueue();
664  signal_->Wait();
665  }
666  // Bail the queue one last time on exit
667  EmptyLogQueue();
668 }
669 
670 inline void Logger::EmptyLogQueue()
671 {
672  std::queue<LogMessage> to_log;
673  {
674  etcpal::MutexGuard lock(*mutex_);
675  to_log.swap(msg_q_);
676  }
677 
678  while (!to_log.empty())
679  {
680  etcpal_log(&log_params_, to_log.front().pri, "%s", to_log.front().buf);
681  to_log.pop();
682  }
683 }
684 
685 }; // namespace etcpal
686 
687 #endif // ETCPAL_CPP_LOG_H_
An interface which handles log messages.
Definition: log.h:197
virtual void HandleLogMessage(const EtcPalLogStrings &strings)=0
Define this function to handle log messages and determine what to do with them.
virtual LogTimestamp GetLogTimestamp()
Return a LogTimestamp representing the current local time.
Definition: log.h:216
An object representing the current local time with millisecond resolution for logging purposes.
Definition: log.h:121
constexpr const EtcPalLogTimestamp & get() const noexcept
Get a const reference to the underlying C type.
Definition: log.h:173
bool IsValid() const noexcept
Whether this timestamp represents a valid time.
Definition: log.h:167
LogTimestamp()=default
Construct an invalid timestamp by default.
static LogTimestamp Invalid()
Construct an invalid timestamp.
Definition: log.h:185
A class for dispatching log messages.
Definition: log.h:235
Logger & SetSyslogFacility(int facility) noexcept
Set the Syslog facility value; see RFC 5424 § 6.2.1.
Definition: log.h:578
void Critical(const char *format,...)
Log a message at critical priority.
Definition: log.h:468
void Info(const char *format,...)
Log a message at informational priority.
Definition: log.h:432
bool CanLog(int pri) const noexcept
Determine whether a priority level can be logged using the mask given via SetLogMask().
Definition: log.h:402
LogDispatchPolicy dispatch_policy() const noexcept
Get the current log dispatch policy.
Definition: log.h:495
Logger & SetLogAction(int log_action) noexcept
Set the types of log messages to create and dispatch to the LogMessageHandler.
Definition: log.h:571
void Error(const char *format,...)
Log a message at error priority.
Definition: log.h:459
int log_action() const noexcept
Get the current log action.
Definition: log.h:507
void Emergency(const char *format,...)
Log a message at emergency priority.
Definition: log.h:486
void Alert(const char *format,...)
Log a message at alert priority.
Definition: log.h:477
bool Startup(LogMessageHandler &message_handler)
Start logging.
Definition: log.h:344
int syslog_facility() const noexcept
Get the current Syslog facility value.
Definition: log.h:513
Logger & SetSyslogHostname(const char *hostname) noexcept
Set the Syslog HOSTNAME; see RFC 5424 § 6.2.4.
Definition: log.h:585
void Warning(const char *format,...)
Log a message at warning priority.
Definition: log.h:450
Logger & SetSyslogAppName(const char *app_name) noexcept
Set the Syslog APP-NAME; see RFC 5424 § 6.2.5.
Definition: log.h:600
const EtcPalLogParams & log_params() const noexcept
Get the log params used by this logger.
Definition: log.h:541
const char * syslog_hostname() const noexcept
Get the current Syslog HOSTNAME.
Definition: log.h:519
void Log(int pri, const char *format,...)
Log a message.
Definition: log.h:414
const char * syslog_procid() const noexcept
Get the current Syslog PROCID.
Definition: log.h:531
void Shutdown()
Stop logging.
Definition: log.h:384
const char * syslog_app_name() const noexcept
Get the current Syslog APP-NAME.
Definition: log.h:525
int log_mask() const noexcept
Get the current log mask.
Definition: log.h:501
Logger & SetLogMask(int log_mask) noexcept
Set a new log mask.
Definition: log.h:564
Logger & SetSyslogProcId(const char *proc_id) noexcept
Set the Syslog PROCID; see RFC 5424 § 6.2.6.
Definition: log.h:615
void Debug(const char *format,...)
Log a message at debug priority.
Definition: log.h:423
Logger & SetDispatchPolicy(LogDispatchPolicy new_policy) noexcept
Change the dispatch policy of this logger.
Definition: log.h:551
void Notice(const char *format,...)
Log a message at notice priority.
Definition: log.h:441
Lock guard around a mutex.
Definition: lock.h:590
A wrapper class for the EtcPal mutex type.
Definition: lock.h:89
A wrapper class for the EtcPal signal type.
Definition: lock.h:207
A thread class, modeled after std::thread.
Definition: thread.h:143
Error Start(Function &&func, Args &&... args)
Associate this thread object with a new thread of execution.
Definition: thread.h:384
Thread & SetName(const char *name) noexcept
Set the name of this thread.
Definition: thread.h:328
Error Join(int timeout_ms=ETCPAL_WAIT_FOREVER) noexcept
Wait for the thread to finish execution.
Definition: thread.h:412
Common definitions used by EtcPal C++ wrappers.
C++ wrapper and utilities for etcpal/lock.h.
C++ wrapper and utilities for etcpal/thread.h.
LogDispatchPolicy
Options for the method by which the Logger dispatches log messages.
Definition: log.h:224
@ Queued
Log messages are queued and dispatched from another thread (recommended)
@ Direct
Log messages propagate directly from Log() calls to output streams (normally only used for testing)
#define ETCPAL_CONSTEXPR_14
Stand-in for "constexpr" on entities that can only be defined "constexpr" in C++14 or later.
Definition: common.h:53
#define ETCPAL_CONSTEXPR_14_OR_INLINE
Defined to "constexpr" in C++14 or later, "inline" earlier.
Definition: common.h:54
@ kEtcPalErrOk
The call was successful, no error occurred.
Definition: error.h:51
#define ETCPAL_LOG_ERR
Error conditions.
Definition: log.h:178
#define ETCPAL_LOG_PROCID_MAX_LEN
Max length of the procid param.
Definition: log.h:198
#define ETCPAL_LOG_CRIT
Critical conditions.
Definition: log.h:177
#define ETCPAL_RAW_LOG_MSG_MAX_LEN
Max length of a log message string passed to etcpal_log() or etcpal_vlog().
Definition: log.h:201
#define ETCPAL_LOG_APP_NAME_MAX_LEN
Max length of the app_name param.
Definition: log.h:197
#define ETCPAL_LOG_NOTICE
Normal but significant condition.
Definition: log.h:180
void etcpal_vlog(const EtcPalLogParams *params, int pri, const char *format, va_list args)
Log a message with the list of format arguments already generated.
Definition: log.c:431
#define ETCPAL_LOG_CREATE_HUMAN_READABLE
Create a log string with a human-readable prefix including timestamp and severity.
Definition: log.h:340
#define ETCPAL_LOG_DEBUG
Debug-level messages.
Definition: log.h:182
bool etcpal_validate_log_timestamp(const EtcPalLogTimestamp *timestamp)
Determine whether the given EtcPalLogTimestamp is valid.
Definition: log.c:372
bool etcpal_validate_log_params(EtcPalLogParams *params)
Ensure that the given EtcPalLogParams are valid.
Definition: log.c:350
#define ETCPAL_LOG_INFO
Informational.
Definition: log.h:181
#define ETCPAL_LOG_EMERG
System is unusable.
Definition: log.h:175
void etcpal_log(const EtcPalLogParams *params, int pri, const char *format,...)
Log a message.
Definition: log.c:412
bool etcpal_can_log(const EtcPalLogParams *params, int pri)
Determine whether a priority level can be logged given the mask present in the log params.
Definition: log.c:395
#define ETCPAL_LOG_WARNING
Warning conditions.
Definition: log.h:179
#define ETCPAL_LOG_UPTO(pri)
Create a priority mask for all priorities through pri.
Definition: log.h:194
#define ETCPAL_LOG_ALERT
Action must be taken immediately.
Definition: log.h:176
#define ETCPAL_LOG_HOSTNAME_MAX_LEN
Max length of the hostname param.
Definition: log.h:196
void etcpal_deinit(etcpal_features_t features)
Deinitialize the EtcPal library.
Definition: common.c:136
etcpal_error_t etcpal_init(etcpal_features_t features)
Initialize the EtcPal library.
Definition: common.c:87
#define ETCPAL_FEATURE_LOGGING
Use the etcpal/log module.
Definition: common.h:130
A set of parameters used for the etcpal_*log() functions.
Definition: log.h:371
EtcPalSyslogParams syslog_params
The syslog header parameters.
Definition: log.h:377
EtcPalLogCallback log_fn
A callback function for the finished log string(s).
Definition: log.h:375
int action
What should be done when etcpal_log() or etcpal_vlog() is called.
Definition: log.h:373
int log_mask
A mask value that determines which priority messages can be logged.
Definition: log.h:379
EtcPalLogTimeFn time_fn
A callback function for the etcpal_log() and etcpal_vlog() functions to obtain the time from the appl...
Definition: log.h:384
void * context
Application context that will be passed back with the log callback function.
Definition: log.h:386
The set of log strings passed with a call to an etcpal_log_callback function.
Definition: log.h:288
A set of parameters which represent the current local time with millisecond resolution.
Definition: log.h:272
int facility
Syslog Facility; see RFC 5424 § 6.2.1.
Definition: log.h:349
char app_name[ETCPAL_LOG_APP_NAME_MAX_LEN]
Syslog APP-NAME; see RFC 5424 § 6.2.5.
Definition: log.h:351
char procid[ETCPAL_LOG_PROCID_MAX_LEN]
Syslog PROCID; see RFC 5424 § 6.2.6.
Definition: log.h:352
char hostname[ETCPAL_LOG_HOSTNAME_MAX_LEN]
Syslog HOSTNAME; see RFC 5424 § 6.2.4.
Definition: log.h:350