30 #include <boost/algorithm/string.hpp>
43 #define ERR_LS LOG_STREAM(err, log_setup)
44 #define WRN_LS LOG_STREAM(warn, log_setup)
45 #define LOG_LS LOG_STREAM(info, log_setup)
46 #define DBG_LS LOG_STREAM(debug, log_setup)
50 class null_streambuf :
public std::streambuf
52 virtual int overflow(
int c) {
return std::char_traits< char >::not_eof(
c); }
109 std::vector<std::string> files;
122 std::sort(files.begin(), files.end());
124 for(std::size_t j = 0; j < files.size() -
lg::max_logs; ++j) {
125 const std::string
path = log_dir +
'/' + files[j];
128 ERR_LS <<
"rotate_logs(): failed to delete " <<
path <<
"!";
135 std::ostringstream o;
136 const std::time_t cur = std::time(
nullptr);
140 << std::put_time(std::localtime(&cur),
"%Y%m%d-%H%M%S-")
194 if(!std::freopen(
"NUL",
"a", stderr)) {
195 std::cerr <<
"Failed to close stderr log file: '" << old_path <<
"'";
202 if(!std::freopen(
"NUL",
"a", stdout)) {
203 std::cerr <<
"Failed to close stdout log file: '" << old_path <<
"'";
228 std::cerr <<
"Failed to rename log file from '" << old_path <<
"' to '" <<
output_file_path_ <<
"'";
252 std::cerr <<
"Failed to redirect stderr to a file!";
262 std::cerr <<
"Failed to redirect stdout to a file!";
265 if(dup2(STDERR_FILENO, STDOUT_FILENO) == -1) {
266 std::cerr <<
"Failed to redirect stdout to a file!";
272 if(setvbuf(stdout, NULL, _IONBF, 2) == -1) {
273 std::cerr <<
"Failed to set stdout to be unbuffered";
349 std::string::size_type
s = name.size();
354 }
else if (
s > 2 && name.compare(
s - 2, 2,
"/*") == 0) {
356 if (l.first.compare(0,
s - 1, name, 0,
s - 1) == 0)
382 std::ostringstream res;
384 if(l.first.find(filter) != std::string::npos)
385 res << l.first <<
"\n";
406 if(span <= std::chrono::seconds{0}) {
411 std::vector<std::string> formatted_values;
414 const auto format_time = [&formatted_values](
const auto& val,
const std::string& suffix) {
415 if(val > std::decay_t<decltype(val)>{0}) {
416 formatted_values.push_back(
formatter{} << val.count() <<
" " << suffix);
420 format_time(
days,
"days");
421 format_time(hours,
"hours");
422 format_time(minutes,
"minutes");
423 format_time(seconds,
"seconds");
438 std::string str = logstr;
441 const char* user_name = getenv(
"USERNAME");
443 const char* user_name = getenv(
"USER");
446 if(user_name !=
nullptr) {
447 boost::replace_all(str, std::string(
"/") + user_name +
"/",
"/USER/");
448 boost::replace_all(str, std::string(
"\\") + user_name +
"\\",
"\\USER\\");
458 bool show_timestamps,
460 bool auto_newline)
const
476 stream |
formatter() <<
"Error (strict mode, strict_level = " <<
strict_level_ <<
"): wesnoth reported on channel " <<
name_ <<
" " << domain.
domain_->first << std::endl;
494 auto now = std::chrono::system_clock::now();
497 auto as_seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
498 auto fractional = std::chrono::duration_cast<std::chrono::microseconds>(now - as_seconds);
499 stream_ <<
"." << std::setw(6) << fractional.count();
527 start_ = std::chrono::steady_clock::now();
528 debug()(domain_,
false,
true) |
formatter() <<
"{ BEGIN: " << str_;
538 auto now = std::chrono::steady_clock::now();
539 auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now -
start_);
545 static std::stringstream
lg;
log_domain(char const *name, severity severity=severity::LG_WARN)
void operator|(formatter &&message)
void set_auto_newline(bool enabled)
void set_prefix(const std::string &prefix)
void set_indent(int level)
log_in_progress(std::ostream &stream)
log_in_progress operator()(const log_domain &domain, bool show_names=true, bool do_indent=false, bool show_timestamps=true, bool break_strict=true, bool auto_newline=true) const
~redirect_output_setter()
std::ostream * old_stream_
The previously set redirection.
redirect_output_setter(std::ostream &stream)
Constructor.
const log_domain & domain_
void do_log_entry(const std::string &str) noexcept
std::chrono::steady_clock::time_point start_
void do_log_exit() noexcept
uint32_t get_next_random()
Get a new random number.
Declarations for File-IO.
static bool precise_timestamp
static std::string logs_dir_
path to the current logs directory; may change after being initially set if a custom userdata directo...
static utils::optional< bool > is_log_dir_writable_
whether the current logs directory is writable
static std::string output_file_path_
path to the current log file; does not include the extension
static std::ostream null_ostream(new null_streambuf)
static std::mutex log_mutex
static std::ostream & output()
static bool log_sanitization
static std::ostream * output_stream_
alternative stream to write data to
static lg::log_domain log_setup("logsetup")
Standard logging facilities (interface).
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
std::chrono::duration< int, std::ratio< 86400 > > days
constexpr auto deconstruct_duration(const std::chrono::duration< Rep, Period > &span)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
bool delete_file(const std::string &filename)
static bool file_exists(const bfs::path &fpath)
int file_size(const std::string &fname)
Returns the size of a file, or -1 if the file doesn't exist.
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode)
Throws io_exception if an error occurs.
std::string get_logs_dir()
bool make_directory(const std::string &dirname)
bool get_log_domain_severity(const std::string &name, severity &severity)
std::string list_log_domains(const std::string &filter)
const std::string out_log_file_suffix
void rotate_logs(const std::string &log_dir)
Check how many log files exist and delete the oldest when there's too many.
std::string unique_log_filename()
Generate a unique file name using the current timestamp and a randomly generated number.
void set_log_to_file()
Do the initial redirection to a log file if the logs directory is writable.
static log_domain dom("general")
void set_log_sanitize(bool sanitize)
toggle log sanitization
utils::optional< bool > log_dir_writable()
Returns the result set by check_log_dir_writable().
void move_log_file()
Move the log file to another directory.
std::string format_timespan(const std::chrono::seconds &span)
TODO: we also have utils::format_timespan, which does something very similar...
std::string sanitize_log(const std::string &logstr)
static severity strict_level_
void check_log_dir_writable()
Checks that a dummy file can be written to and deleted from the logs directory.
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
const std::string log_file_prefix
std::map< std::string, severity > domain_map
static domain_map * domains
std::pair< const std::string, severity > logd
static bool strict_threw_
bool is_not_log_file(const std::string &fn)
Use the defined prefix and suffix to determine if a filename is a log file.
void precise_timestamps(bool pt)
bool set_log_domain_severity(const std::string &name, severity severity)
void set_strict_severity(severity severity)
std::string get_log_file_path()
const std::string log_file_suffix
std::ostringstream & operator<<(std::ostringstream &oss, const lg::severity severity)
void erase_if(Container &container, const Predicate &predicate)
Convenience wrapper for using std::remove_if on a container.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string::const_iterator iterator
An exception object used when an IO error occurs.
static map_location::direction s