28 #include <boost/algorithm/string.hpp>
41 #define ERR_LS LOG_STREAM(err, log_setup)
42 #define WRN_LS LOG_STREAM(warn, log_setup)
43 #define LOG_LS LOG_STREAM(info, log_setup)
44 #define DBG_LS LOG_STREAM(debug, log_setup)
48 class null_streambuf :
public std::streambuf
50 virtual int overflow(
int c) {
return std::char_traits< char >::not_eof(
c); }
107 std::vector<std::string> files;
120 std::sort(files.begin(), files.end());
122 for(std::size_t j = 0; j < files.size() -
lg::max_logs; ++j) {
123 const std::string
path = log_dir +
'/' + files[j];
126 ERR_LS <<
"rotate_logs(): failed to delete " <<
path <<
"!";
133 std::ostringstream o;
134 const std::time_t cur = std::time(
nullptr);
138 << std::put_time(std::localtime(&cur),
"%Y%m%d-%H%M%S-")
192 if(!std::freopen(
"NUL",
"a", stderr)) {
193 std::cerr <<
"Failed to close stderr log file: '" << old_path <<
"'";
200 if(!std::freopen(
"NUL",
"a", stdout)) {
201 std::cerr <<
"Failed to close stdout log file: '" << old_path <<
"'";
226 std::cerr <<
"Failed to rename log file from '" << old_path <<
"' to '" <<
output_file_path_ <<
"'";
250 std::cerr <<
"Failed to redirect stderr to a file!";
260 std::cerr <<
"Failed to redirect stdout to a file!";
263 if(dup2(STDERR_FILENO, STDOUT_FILENO) == -1) {
264 std::cerr <<
"Failed to redirect stdout to a file!";
270 if(setvbuf(stdout, NULL, _IONBF, 2) == -1) {
271 std::cerr <<
"Failed to set stdout to be unbuffered";
347 std::string::size_type
s = name.size();
352 }
else if (
s > 2 && name.compare(
s - 2, 2,
"/*") == 0) {
354 if (l.first.compare(0,
s - 1, name, 0,
s - 1) == 0)
380 std::ostringstream res;
382 if(l.first.find(filter) != std::string::npos)
383 res << l.first <<
"\n";
403 std::ostringstream ss;
405 ss << std::put_time(std::localtime(&
t),
format.c_str());
410 std::ostringstream sout;
412 const std::time_t minutes =
t / 60;
413 const std::time_t days = minutes / 60 / 24;
416 }
else if(minutes == 0) {
417 sout <<
t <<
" seconds";
418 }
else if(days == 0) {
419 sout << minutes / 60 <<
" hours, " << minutes % 60 <<
" minutes";
421 sout << days <<
" days, " << (minutes / 60) % 24 <<
" hours, " << minutes % 60 <<
" minutes";
429 auto now = std::chrono::system_clock::now();
430 auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
431 auto fractional = std::chrono::duration_cast<std::chrono::microseconds>(now - seconds);
432 std::time_t tm = std::chrono::system_clock::to_time_t(seconds);
433 char c = out.fill(
'0');
434 out << std::put_time(std::localtime(&tm),
"%Y%m%d %H:%M:%S") <<
"." << std::setw(6) << fractional.count() <<
' ';
449 std::string str = logstr;
452 const char* user_name = getenv(
"USERNAME");
454 const char* user_name = getenv(
"USER");
457 if(user_name !=
nullptr) {
458 boost::replace_all(str, std::string(
"/") + user_name +
"/",
"/USER/");
459 boost::replace_all(str, std::string(
"\\") + user_name +
"\\",
"\\USER\\");
469 bool show_timestamps,
471 bool auto_newline)
const
487 stream |
formatter() <<
"Error (strict mode, strict_level = " <<
strict_level_ <<
"): wesnoth reported on channel " <<
name_ <<
" " << domain.
domain_->first << std::endl;
536 start_ = std::chrono::steady_clock::now();
537 debug()(domain_,
false,
true) |
formatter() <<
"{ BEGIN: " << str_;
547 auto now = std::chrono::steady_clock::now();
548 auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now -
start_);
554 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).
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)
std::string get_timespan(const std::time_t &t)
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 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_
std::string get_timestamp(const std::time_t &t, const std::string &format)
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()
static void print_precise_timestamp(std::ostream &out) noexcept
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::const_iterator iterator
An exception object used when an IO error occurs.
static map_location::direction s