JayBeams  0.1
Another project to have fun coding.
log.cpp
Go to the documentation of this file.
1 #include "jb/log.hpp"
2 
3 #include <jb/as_hhmmss.hpp>
4 #include <jb/assert_throw.hpp>
5 
6 #include <boost/date_time/posix_time/posix_time.hpp>
7 #include <boost/log/attributes.hpp>
8 #include <boost/log/expressions.hpp>
9 #include <boost/log/sinks/text_ostream_backend.hpp>
10 #include <boost/log/utility/formatting_ostream.hpp>
11 #include <boost/log/utility/setup/console.hpp>
12 #include <boost/log/utility/setup/file.hpp>
13 #include <boost/shared_ptr.hpp>
14 #include <iomanip>
15 
16 namespace jb {
17 namespace log {
18 /// Define the default values for logging configuration
19 namespace defaults {
20 
21 #ifndef JB_LOG_DEFAULTS_minimum_severity
22 #define JB_LOG_DEFAULTS_minimum_severity jb::severity_level::info
23 #endif // JB_LOG_DEFAULTS_minimum_severity
24 
25 #ifndef JB_LOG_DEFAULTS_minimum_console_severity
26 #define JB_LOG_DEFAULTS_minimum_console_severity jb::severity_level::trace
27 #endif // JB_LOG_DEFAULTS_minimum_console_severity
28 
29 #ifndef JB_LOG_DEFAULTS_enable_file_logging
30 #define JB_LOG_DEFAULTS_enable_file_logging false
31 #endif // JB_LOG_DEFAULTS_enable_file_logging
32 
33 #ifndef JB_LOG_DEFAULTS_enable_console_logging
34 #define JB_LOG_DEFAULTS_enable_console_logging true
35 #endif // JB_LOG_DEFAULTS_enable_console_logging
36 
37 #ifndef JB_LOG_DEFAULTS_logfile_suffix
38 #define JB_LOG_DEFAULTS_logfile_suffix "_%Y%m%d.%N.log"
39 #endif // JB_LOG_DEFAULTS_logfile_suffix
40 
41 #ifndef JB_LOG_DEFAULTS_logfile_archive_directory
42 #define JB_LOG_DEFAULTS_logfile_archive_directory ""
43 #endif // JB_LOG_DEFAULTS_logfile_archive_directory
44 
45 #ifndef JB_LOG_DEFAULTS_maximum_size_archived
46 #define JB_LOG_DEFAULTS_maximum_size_archived 128L * 1024 * 1024 * 1024
47 #endif // JB_LOG_DEFAULTS_maximum_size_archived
48 
49 #ifndef JB_LOG_DEFAULTS_minimum_free_space
50 #define JB_LOG_DEFAULTS_minimum_free_space 8L * 1024 * 1024 * 1024
51 #endif // JB_LOG_DEFAULTS_minimum_free_space
52 
63 } // namespace defaults
64 
67  desc("minimum-severity")
68  .help("Log messages below this severity are filtered out"),
71  desc("minimum-console-severity")
72  .help("Log messages below this severity are "
73  "filtered out in the console"),
76  desc("enable-console-logging")
77  .help("If set, log messages are sent to the "
78  "console. Enabled by default"),
81  desc("enable-file-logging")
82  .help("If set, log messages are set to a "
83  "log file. Disabled by default"),
85  , logfile_basename(
86  desc("logfile-basename")
87  .help("Define the name of the logfile,"
88  " used only if enable-file-logging is true"),
89  this)
91  desc("logfile-suffix")
92  .help("Define suffix for the filename,"
93  " typically _%Y%m%d.%N.log."
94  " The format characters are defined"
95  " by Boost.Log"),
96  this, defaults::logfile_suffix)
98  desc("logfile-archive-directory")
99  .help("Define where are old, "
100  "and full logfiles archived."),
103  desc("maximum-size-archived")
104  .help("Define how much space, at most, "
105  "is used for saved logfiles."),
108  desc("minimum-free-space")
109  .help("Define the minimum amount of free"
110  " disk space kept after cleaning up"
111  " logfiles"),
112  this, defaults::minimum_free_space) {
113 }
114 
115 void config::validate() const {
116  if (enable_file_logging() and logfile_basename() == "") {
117  throw jb::usage(
118  "enable-file-logging is set,"
119  " you must also set logfile-basename",
120  1);
121  }
122 }
123 
124 BOOST_LOG_ATTRIBUTE_KEYWORD(filename, "Filename", std::string)
125 BOOST_LOG_ATTRIBUTE_KEYWORD(lineno, "Lineno", int)
126 BOOST_LOG_ATTRIBUTE_KEYWORD(transaction, "Transaction", std::int64_t)
127 BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", jb::severity_level)
128 BOOST_LOG_ATTRIBUTE_KEYWORD(min_severity, "MinSeverity", jb::severity_level)
130  current_thread_id, "ThreadID",
131  boost::log::attributes::current_thread_id::value_type)
133  local_time, "TimeStamp", boost::log::attributes::local_clock::value_type)
134 
135 bool filter_predicate(::boost::log::attribute_value_set const& attr) {
136  // ... if we got to this point the severity is high enough, but we
137  // need to silence some warnings (and also avoid lines without
138  // coverage) ...
139  JB_ASSERT_THROW(*attr[jb::log::severity] >= *attr[jb::log::min_severity]);
140  // ... debug messages are funny, only print a few ...
141  if (*attr[jb::log::severity] == jb::severity_level::debug) {
142  return (*attr[jb::log::transaction] % 10000) == 0;
143  }
144  return true;
145 }
146 
148  boost::log::record_view const& rec, boost::log::formatting_ostream& strm) {
149  strm << " [" << rec[jb::log::current_thread_id] << "]"
150  << " [" << std::setfill(' ') << std::setw(jb::severity_level_width())
151  << rec[jb::log::severity] << "]";
152 
153  if (rec[jb::log::severity] == jb::severity_level::debug) {
154  strm << " tid=<" << rec[jb::log::transaction] << ">";
155  }
156  strm << " " << rec[boost::log::expressions::smessage] << " ("
157  << rec[jb::log::filename] << ":" << rec[jb::log::lineno] << ")";
158 }
159 
161  boost::log::record_view const& rec, boost::log::formatting_ostream& strm) {
162  auto usecs = rec[jb::log::local_time]->time_of_day().total_microseconds();
163 
164  strm << jb::as_hhmmssu(std::chrono::microseconds(usecs));
165  format_common(rec, strm);
166 }
167 
169  boost::log::record_view const& rec, boost::log::formatting_ostream& strm) {
170  auto date = rec[jb::log::local_time]->date();
171  auto usecs = rec[jb::log::local_time]->time_of_day().total_microseconds();
172 
173  strm << std::setfill('0') << std::setw(4) << date.year() << '-'
174  << std::setfill('0') << std::setw(2) << date.month().as_number() << '-'
175  << std::setfill('0') << std::setw(2) << date.day() << ' '
176  << jb::as_hhmmssu(std::chrono::microseconds(usecs));
177  format_common(rec, strm);
178 }
179 
180 std::int64_t tid_;
181 
182 std::int64_t tid() {
183  return tid_;
184 }
185 
186 void next_tid() {
187  ++tid_;
188 }
189 
190 void init(config const& cfg) {
191  namespace expr = boost::log::expressions;
192  namespace keywords = boost::log::keywords;
193  auto core = boost::log::core::get();
194 
195  core->add_global_attribute("Scopes", boost::log::attributes::named_scope());
196  core->add_global_attribute(
197  "ThreadID", boost::log::attributes::current_thread_id());
198  core->add_global_attribute(
199  "TimeStamp", boost::log::attributes::local_clock());
200  core->add_global_attribute(
201  "Transaction", boost::log::attributes::make_function(&jb::log::tid));
202  core->add_global_attribute(
203  "MinSeverity", boost::log::attributes::constant<jb::severity_level>(
204  cfg.minimum_severity()));
205 
206  core->set_filter(&jb::log::filter_predicate);
207 
208  if (cfg.enable_console_logging()) {
209  auto sink = boost::log::add_console_log(std::clog);
210  sink->set_formatter(&jb::log::format_console);
211  sink->set_filter([cfg](::boost::log::attribute_value_set const& attr) {
212  return *attr[jb::log::severity] >= cfg.minimum_console_severity();
213  });
214  }
215 
216  if (cfg.enable_file_logging()) {
217  std::string filename_format = cfg.logfile_basename() + cfg.logfile_suffix();
218  auto sink = boost::log::add_file_log(
219  keywords::file_name = filename_format,
220  keywords::time_based_rotation =
221  boost::log::sinks::file::rotation_at_time_point(0, 0, 0));
222  sink->set_formatter(&jb::log::format_logfile);
223  sink->locked_backend()->set_file_collector(
224  boost::log::sinks::file::make_collector(
225  keywords::target = cfg.logfile_archive_directory(),
227  keywords::min_free_space = cfg.minimum_free_space()));
228  sink->locked_backend()->scan_for_files();
229  }
230 }
231 
232 } // namespace log
233 } // namespace jb
void format_logfile(boost::log::record_view const &rec, boost::log::formatting_ostream &strm)
Definition: log.cpp:168
Define defaults for program parameters.
jb::config_attribute< config, bool > enable_file_logging
Definition: log.hpp:37
#define JB_LOG_DEFAULTS_logfile_archive_directory
Definition: log.cpp:42
severity_level
Severity levels for JayBeams, based on syslog.
jb::severity_level minimum_console_severity
Definition: log.cpp:54
jb::config_attribute< config, std::string > logfile_basename
Definition: log.hpp:38
void validate() const override
Validate the settings.
Definition: log.cpp:115
Configuration object for the logging functions.
Definition: log.hpp:29
jb::config_attribute< config, std::string > logfile_archive_directory
Definition: log.hpp:40
long minimum_free_space
Definition: log.cpp:62
#define JB_LOG_DEFAULTS_minimum_free_space
Definition: log.cpp:50
#define JB_LOG_DEFAULTS_minimum_console_severity
Definition: log.cpp:26
Helper class to print time durations in a HHMMSS.UUUUUU format.
Definition: as_hhmmss.hpp:12
std::string logfile_archive_directory
Definition: log.cpp:59
jb::config_attribute< config, long > maximum_size_archived
Definition: log.hpp:41
bool enable_console_logging
Definition: log.cpp:57
#define JB_LOG_DEFAULTS_logfile_suffix
Definition: log.cpp:38
void init(config const &cfg)
Initialize the logging functions using the configuration provided.
Definition: log.cpp:190
#define JB_LOG_DEFAULTS_enable_console_logging
Definition: log.cpp:34
jb::config_attribute< config, std::string > logfile_suffix
Definition: log.hpp:39
long maximum_size_archived
Definition: log.cpp:61
jb::config_attribute< config, jb::severity_level > minimum_console_severity
Definition: log.hpp:35
#define JB_ASSERT_THROW(PRED)
#define JB_LOG_DEFAULTS_maximum_size_archived
Definition: log.cpp:46
void next_tid()
Definition: log.cpp:186
A simple class to communicate the result of parsing the options.
Definition: usage.hpp:11
std::int64_t tid_
Definition: log.cpp:180
jb::config_attribute< config, jb::severity_level > minimum_severity
Definition: log.hpp:34
std::string logfile_suffix
Definition: log.cpp:58
boost::log::attributes::local_clock::value_type bool filter_predicate(::boost::log::attribute_value_set const &attr)
Definition: log.cpp:135
void format_common(boost::log::record_view const &rec, boost::log::formatting_ostream &strm)
Definition: log.cpp:147
void format_console(boost::log::record_view const &rec, boost::log::formatting_ostream &strm)
Definition: log.cpp:160
std::int64_t tid()
Definition: log.cpp:182
int severity_level_width()
Return the recommended with for printing security levels.
jb::severity_level minimum_severity
Definition: log.cpp:53
jb::config_attribute< config, bool > enable_console_logging
Definition: log.hpp:36
#define JB_LOG_DEFAULTS_minimum_severity
Definition: log.cpp:22
BOOST_LOG_ATTRIBUTE_KEYWORD(current_thread_id, "ThreadID", boost::log::attributes::current_thread_id::value_type) BOOST_LOG_ATTRIBUTE_KEYWORD(local_time
#define JB_LOG_DEFAULTS_enable_file_logging
Definition: log.cpp:30
bool enable_file_logging
Definition: log.cpp:56
jb::config_attribute< config, long > minimum_free_space
Definition: log.hpp:42
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7