21#include "flow/error/error.hpp" 
   22#include <boost/move/make_unique.hpp> 
   33                                     Config* config, 
const fs::path& log_path,
 
   34                                     bool capture_rotate_signals_internally) :
 
   46  m_throttling_now(
false), 
 
   47  m_throttling_active(
false),
 
   50  m_serial_logger(boost::movelib::make_unique<Serial_file_logger>(get_logger(), m_config, log_path)),
 
   66  m_signal_set(*(m_async_worker.task_engine()))
 
   72                "Log-writing worker thread(s) have started around now; ready to work.");
 
   75  log_flush_and_reopen(
false); 
 
   77  if (capture_rotate_signals_internally)
 
   79    FLOW_LOG_INFO(
"Setting up internal log-rotate-reopening signal handler.  " 
   80                  "CAUTION!  User program MUST avoid using non-boost::asio::signal_set signal handling!  " 
   81                  "If it does use non-boost.asio, behavior is undefined.");
 
   84    m_signal_set.add(SIGHUP);
 
   96    m_signal_set.async_wait([
this](
const Error_code& sys_err_code, 
int sig_number)
 
   98      on_rotate_signal(sys_err_code, sig_number);
 
  128  assert((cfg.
m_hi_limit > 0) && 
"Per contract, hi_limit must be positive.");
 
  137  if (prev_active != active)
 
  140                  "Config set: throttling feature active? [" << prev_active << 
"] => [" << active << 
"].");
 
  158      const auto prev_throttling_now
 
  160                                    std::memory_order_relaxed);
 
  163      FLOW_LOG_INFO(
"Async_file_logger [" << 
this << 
"]: Config set: " 
  166                    "throttling? = [" << prev_throttling_now << 
"] => [" << 
m_throttling_now << 
"]; " 
  167                    "throttling feature active? = [" << active << 
"].  " 
  168                    "Reminder: `throttling?` shall only be used if `throttling feature active?` is 1.");
 
  184    FLOW_LOG_INFO(
"Async_file_logger [" << 
this << 
"]: Deleting.  Worker thread will flush " 
  185                  "output if possible; then we will proceed to shut down.  Current mem-use of queued " 
  186                  "log-requests is [" << 
m_pending_logs_sz << 
"]; if it is large, this might take some time.");
 
  204                      Synchronicity::S_ASYNC_AND_AWAIT_CONCURRENT_COMPLETION);
 
  213  if (sys_err_code == boost::asio::error::operation_aborted)
 
  220                "Internal log-rotate handler executed with signal number [" << sig_number << 
"].");
 
  227                     "Internal signal handler executed with an error indicator.  Strange!  " 
  228                     "Ignoring and continuing other operation.");
 
  265  const auto msg_sz = msg.size();
 
  266  Log_request log_request{ 
new char[msg_sz], msg_sz, metadata,
 
  268  memcpy(log_request.m_msg_copy, msg.data(), msg_sz);
 
  278  const auto logs_sz = 
mem_cost(log_request);
 
  279  auto& throttling_begins = log_request.m_throttling_begins;
 
  281  logs_sz_t pending_logs_sz; 
 
  282  logs_sz_t prev_pending_logs_sz;
 
  294        && (pending_logs_sz >= limit) && (prev_pending_logs_sz < limit))
 
  297      throttling_begins = 
true;
 
  300  if (throttling_begins)
 
  312       "Async_file_logger [" << 
this << 
"]: " 
  313         "do_log() throttling algorithm: a message reached hi_limit; next message-to-be => likely dropped, " 
  314         "if feature active.  Config: hi_limit [" << limit << 
"].  " 
  315         "Mem-use = [" << prev_pending_logs_sz << 
"] => [" << pending_logs_sz << 
"]; " 
  316         "throttling? = 1 (see above); throttling feature active? = [" << active << 
"].  " 
  317         "Reminder: `throttling?` shall only be used if `throttling feature active?` is 1.  " 
  318         "Limit-triggering message's contents follow: [" << msg << 
"].");
 
  324                  "do_log() throttling algorithm: a message was processed; situation (reminder: beware concurrency): " 
  325                  "Config: hi_limit [" << limit << 
"].  " 
  326                  "Mem-use = [" << prev_pending_logs_sz << 
"] => [" << pending_logs_sz << 
"]; " 
  327                  "throttling feature active? = [" << 
m_throttling_active.load(std::memory_order_relaxed) << 
"].  " 
  328                  "Message's contents follow: [" << msg << 
"].");
 
  336  auto really_log = [
this, log_request = std::move(log_request)]() 
mutable 
  338    const auto metadata = log_request.m_metadata;
 
  339    const String_view msg{log_request.m_msg_copy, log_request.m_msg_size};
 
  344    const auto logs_sz = 
mem_cost(log_request);
 
  346    bool throttling_ends = 
false;
 
  348    logs_sz_t pending_logs_sz; 
 
  349    logs_sz_t prev_pending_logs_sz;
 
  354      assert((prev_pending_logs_sz >= logs_sz) && 
"Bug?  really_log() has no matching do_log()?");
 
  359      if (pending_logs_sz == 0)
 
  362        throttling_ends = (
m_throttling_now.exchange(
false, std::memory_order_relaxed) == 
true);
 
  369      FLOW_LOG_INFO(
"Async_file_logger [" << 
this << 
"]: last pending message was logged; " 
  370                    "next message-to-be => likely first one to *not* be dropped, if throttling feature active.  " 
  371                    "Config: hi_limit [" << limit << 
"].  " 
  372                    "Mem-use = [" << prev_pending_logs_sz << 
"] => [" << pending_logs_sz << 
"]; " 
  373                    "throttling? = 0 (see above); " 
  374                    "throttling feature active? = [" << 
m_throttling_active.load(std::memory_order_relaxed) << 
"].  " 
  375                    "Reminder: `throttling?` shall only be used if `throttling feature active?` is 1.  " 
  376                    "Queue-clearing message's contents follow: [" << msg << 
"].");
 
  382                    "really_log() throttling algorithm: last pending message was logged; " 
  383                    "next message-to-be => likely first one to *not* be dropped, if throttling feature active.  " 
  384                    "Config: hi_limit [" << limit << 
"].  " 
  385                    "Mem-use = [" << prev_pending_logs_sz << 
"] => 0; " 
  386                    "throttling feature active? = [" << 
m_throttling_active.load(std::memory_order_relaxed) << 
"].  " 
  387                    "Queue-clearing message is the one immediately following me in file.  " 
  388                    "Compare its time stamp to mine to see time lag due to queueing.");
 
  394                    "really_log() throttling algorithm: a message is about to be written to file; " 
  395                    "situation (reminder: beware concurrency): Config: hi_limit [" << limit << 
"].  " 
  396                    "Mem-use = [" << prev_pending_logs_sz << 
"] => [" << pending_logs_sz << 
"]; " 
  397                    "throttling feature active? = [" << 
m_throttling_active.load(std::memory_order_relaxed) << 
"].  ");
 
  398                    "Message's contents follow: [" << msg << 
"].");
 
  406    if (log_request.m_throttling_begins)
 
  415         "Async_file_logger [" << 
this << 
"]: " 
  416           "really_log() throttling algorithm: The preceding message, when its log-request was " 
  417           "earlier enqueued, caused pending-logs RAM usage to exceed then-configured hi_limit.  " 
  418           "If throttling feature was active, subsequent messages-to-be (log-requests) were dropped.  " 
  419           "We only just got around to being able to log it (satisfy log-request) after all the " 
  420           "preceding ones in FIFO order.  Nowadays: Config: hi_limit [" << limit << 
"].  " 
  421           "Mem-use = [" << prev_pending_logs_sz << 
"] => [" << pending_logs_sz << 
"]; " 
  422           "throttling feature active? = [" << active << 
"].  " 
  423           "Limit-crossing (in the past) message is the one immediately preceding the current one " 
  424           "you're reading in file.  " 
  425           "Compare its time stamp to mine to see time lag due to queueing.");
 
  431    delete[] log_request.m_msg_copy;
 
  503  FLOW_LOG_INFO(
"Async_file_logger [" << 
this << 
"]: Non-worker (user) thread " 
  504                "requested [" << (async ? 
"asynchronous" : 
"synchronous") << 
"] file flush/close (if needed) and " 
  505                "re-open, such as for rotation or at initialization.");
 
  508                      async ? Synchronicity::S_ASYNC : Synchronicity::S_ASYNC_AND_AWAIT_CONCURRENT_COMPLETION);
 
  513  if (!m_serial_logger->should_log(sev, component)) 
 
  524  if (!m_throttling_active.load(std::memory_order_relaxed))
 
  530  const auto throttled = m_throttling_now.load(std::memory_order_relaxed);
 
  534                "should_log(sev=[" << sev << 
"]; component=[" << component.payload_enum_raw_value() << 
"]) " 
  535                "throttling algorithm situation (reminder: beware concurrency): " 
  536                "Throttling feature active? = 1; throttling? = [" << throttled << 
"].");
 
virtual void post(Task &&task, Synchronicity synchronicity=Synchronicity::S_ASYNC)
Cause the given Task (function) to execute within the worker thread as soon as the thread is free of ...
An implementation of Logger that logs messages to a given file-system path but never blocks any loggi...
flow::util::Lock_guard< Mutex > Lock_guard
Short-hand for Mutex lock.
async::Single_thread_task_loop m_async_worker
The thread (1-thread pool, technically) in charge of all m_serial_logger I/O operations including wri...
void on_rotate_signal(const Error_code &sys_err_code, int sig_number)
SIGHUP/equivalent handler for the optional feature capture_rotate_signals_internally in constructor.
std::atomic< bool > m_throttling_active
Whether the throttling-based-on-pending-logs-memory-used feature is currently active or not.
boost::movelib::unique_ptr< Serial_file_logger > m_serial_logger
This is the Logger doing all the real log-writing work (the one stored in Log_context is the logger-a...
static size_t mem_cost(const Log_request &log_request)
How much do_log() issuing the supplied Log_request shall contribute to m_pending_logs_sz.
Signal_set m_signal_set
Signal set which we may or may not be using to trap SIGHUP in order to auto-fire m_serial_logger->log...
size_t m_pending_logs_sz
Estimate of how much RAM is being used by storing do_log() requests' data (message itself,...
bool throttling_active() const
Whether the throttling feature is currently in effect.
Mutex m_throttling_mutex
Protects throttling algorithm data that require coherence among themselves: m_throttling_cfg,...
static size_t deep_size(const Log_request &val)
Estimate of memory footprint of the given value, including memory allocated on its behalf – but exclu...
std::atomic< bool > m_throttling_now
Contains the output of the always-on throttling algorithm; namely true if currently should_log() shal...
Throttling_cfg m_throttling_cfg
See Throttling_cfg. Protected by m_throttling_mutex.
void do_log(Msg_metadata *metadata, util::String_view msg) override
Implements interface method by asynchronously logging the message and some subset of the metadata in ...
void log_flush_and_reopen(bool async=true)
Causes the log at the file-system path to be flushed/closed (if needed) and re-opened; this will happ...
Throttling_cfg throttling_cfg() const
Accessor returning a copy of the current set of throttling knobs.
bool should_log(Sev sev, const Component &component) const override
Implements interface method by returning true if the severity and component (which is allowed to be n...
~Async_file_logger() override
Flushes out anything buffered, returns resources/closes output file(s); then returns.
Async_file_logger(Logger *backup_logger_ptr, Config *config, const fs::path &log_path, bool capture_rotate_signals_internally)
Constructs logger to subsequently log to the given file-system path.
bool logs_asynchronously() const override
Implements interface method by returning true, indicating that this Logger may need the contents of *...
A light-weight class, each object storing a component payload encoding an enum value from enum type o...
Class used to configure the filtering and logging behavior of Loggers; its use in your custom Loggers...
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
#define FLOW_ERROR_SYS_ERROR_LOG_WARNING()
Logs a warning about the (often errno-based or from a library) error code in sys_err_code.
#define FLOW_LOG_INFO(ARG_stream_fragment)
Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
#define FLOW_LOG_WITH_CHECKING(ARG_sev, ARG_stream_fragment)
Logs a message of the specified severity into flow::log::Logger *get_logger() with flow::log::Compone...
#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_....
Synchronicity
Enumeration indicating the manner in which asio_exec_ctx_post(), and various boost....
void reset_this_thread_pinning()
Resets processor-affinity of the calling thread; does not log; and throws on extremely unlikely syste...
Function< void()> Task
Short-hand for a task that can be posted for execution by a Concurrent_task_loop or flow::util::Task_...
Flow module providing logging functionality.
size_t deep_size(const Msg_metadata &val)
Estimate of memory footprint of the given value, including memory allocated on its behalf – but exclu...
Sev
Enumeration containing one of several message severity levels, ordered from highest to lowest.
@ S_WARNING
Message indicates a "bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
@ S_INFO
Message indicates a not-"bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
std::string ostream_op_string(T const &... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
boost::system::error_code Error_code
Short-hand for a boost.system error code (which basically encapsulates an integer/enum error code and...
Flow_log_component
The flow::log::Component payload enumeration comprising various log components used by Flow's own int...
In addition to the task object (function) itself, these are the data placed onto the queue of m_async...
size_t m_msg_size
Number of characters in m_msg_copy pointee string.
Msg_metadata * m_metadata
Pointer to array of characters comprising a copy of msg passed to do_log(). We must delete it.
Controls behavior of the throttling algorithm as described in Async_file_logger doc header Throttling...
static constexpr uint64_t S_HI_LIMIT_DEFAULT
Value of Async_file_logger(...).throttling_cfg().m_hi_limit: default/initial value of m_hi_limit.
uint64_t m_hi_limit
The throttling algorithm will go from Not-Throttling to Throttling state if and only if the current m...