2018-01-28 15:33:14 +01:00
|
|
|
//
|
2022-01-01 01:35:39 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
2018-01-28 15:33:14 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#include "td/utils/FileLog.h"
|
|
|
|
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/port/FileFd.h"
|
|
|
|
#include "td/utils/port/path.h"
|
2018-09-07 02:41:21 +02:00
|
|
|
#include "td/utils/port/StdStreams.h"
|
2022-10-05 22:55:50 +02:00
|
|
|
#include "td/utils/port/thread_local.h"
|
2018-01-28 15:33:14 +01:00
|
|
|
#include "td/utils/Slice.h"
|
2021-05-17 14:21:11 +02:00
|
|
|
#include "td/utils/SliceBuilder.h"
|
2022-10-05 22:55:50 +02:00
|
|
|
#include "td/utils/Time.h"
|
2018-01-28 15:33:14 +01:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
2019-08-12 13:45:57 +02:00
|
|
|
Status FileLog::init(string path, int64 rotate_threshold, bool redirect_stderr) {
|
2019-10-08 20:17:42 +02:00
|
|
|
if (path.empty()) {
|
2022-09-10 21:48:34 +02:00
|
|
|
return Status::Error("Log file path must be non-empty");
|
2019-10-08 20:17:42 +02:00
|
|
|
}
|
2018-01-28 15:48:11 +01:00
|
|
|
if (path == path_) {
|
|
|
|
set_rotate_threshold(rotate_threshold);
|
2018-10-24 17:42:40 +02:00
|
|
|
return Status::OK();
|
2018-01-28 15:48:11 +01:00
|
|
|
}
|
|
|
|
|
2018-10-24 17:42:40 +02:00
|
|
|
TRY_RESULT(fd, FileFd::open(path, FileFd::Create | FileFd::Write | FileFd::Append));
|
2018-01-28 15:33:14 +01:00
|
|
|
|
2018-01-28 15:48:11 +01:00
|
|
|
fd_.close();
|
2018-10-24 17:42:40 +02:00
|
|
|
fd_ = std::move(fd);
|
2019-08-12 13:45:57 +02:00
|
|
|
if (!Stderr().empty() && redirect_stderr) {
|
2018-09-13 13:26:22 +02:00
|
|
|
fd_.get_native_fd().duplicate(Stderr().get_native_fd()).ignore();
|
|
|
|
}
|
2018-01-28 15:48:11 +01:00
|
|
|
|
2019-01-17 23:17:20 +01:00
|
|
|
auto r_path = realpath(path, true);
|
|
|
|
if (r_path.is_error()) {
|
|
|
|
path_ = std::move(path);
|
|
|
|
} else {
|
|
|
|
path_ = r_path.move_as_ok();
|
|
|
|
}
|
2019-12-08 07:57:33 +01:00
|
|
|
TRY_RESULT_ASSIGN(size_, fd_.get_size());
|
2018-01-28 15:33:14 +01:00
|
|
|
rotate_threshold_ = rotate_threshold;
|
2019-08-12 13:45:57 +02:00
|
|
|
redirect_stderr_ = redirect_stderr;
|
2018-10-24 17:42:40 +02:00
|
|
|
return Status::OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
Slice FileLog::get_path() const {
|
|
|
|
return path_;
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
|
2019-01-17 23:17:20 +01:00
|
|
|
vector<string> FileLog::get_file_paths() {
|
|
|
|
vector<string> result;
|
|
|
|
if (!path_.empty()) {
|
|
|
|
result.push_back(path_);
|
|
|
|
result.push_back(PSTRING() << path_ << ".old");
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-01-28 15:33:14 +01:00
|
|
|
void FileLog::set_rotate_threshold(int64 rotate_threshold) {
|
|
|
|
rotate_threshold_ = rotate_threshold;
|
|
|
|
}
|
|
|
|
|
2018-10-24 17:42:40 +02:00
|
|
|
int64 FileLog::get_rotate_threshold() const {
|
|
|
|
return rotate_threshold_;
|
|
|
|
}
|
|
|
|
|
2020-09-27 13:37:35 +02:00
|
|
|
bool FileLog::get_redirect_stderr() const {
|
|
|
|
return redirect_stderr_;
|
|
|
|
}
|
|
|
|
|
2021-05-17 15:18:19 +02:00
|
|
|
void FileLog::do_append(int log_level, CSlice slice) {
|
2022-10-05 22:55:50 +02:00
|
|
|
auto start_time = Time::now();
|
2021-05-17 16:33:26 +02:00
|
|
|
if (size_ > rotate_threshold_ || want_rotate_.load(std::memory_order_relaxed)) {
|
|
|
|
auto status = rename(path_, PSLICE() << path_ << ".old");
|
|
|
|
if (status.is_error()) {
|
2022-10-09 13:15:54 +02:00
|
|
|
process_fatal_error(PSLICE() << status << " in " << __FILE__ << " at " << __LINE__ << '\n');
|
2021-05-17 16:33:26 +02:00
|
|
|
}
|
2021-05-17 16:58:33 +02:00
|
|
|
do_after_rotation();
|
2021-05-17 16:33:26 +02:00
|
|
|
}
|
2018-01-28 15:33:14 +01:00
|
|
|
while (!slice.empty()) {
|
2022-11-14 12:34:31 +01:00
|
|
|
if (redirect_stderr_) {
|
2022-11-18 12:33:23 +01:00
|
|
|
while (has_log_guard()) {
|
2022-11-14 12:34:31 +01:00
|
|
|
// spin
|
|
|
|
}
|
|
|
|
}
|
2018-01-28 15:33:14 +01:00
|
|
|
auto r_size = fd_.write(slice);
|
|
|
|
if (r_size.is_error()) {
|
2021-05-18 03:35:36 +02:00
|
|
|
process_fatal_error(PSLICE() << r_size.error() << " in " << __FILE__ << " at " << __LINE__ << '\n');
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
auto written = r_size.ok();
|
|
|
|
size_ += static_cast<int64>(written);
|
|
|
|
slice.remove_prefix(written);
|
|
|
|
}
|
2022-10-05 22:55:50 +02:00
|
|
|
auto total_time = Time::now() - start_time;
|
|
|
|
if (total_time >= 0.1 && log_level >= 1) {
|
|
|
|
auto thread_id = get_thread_id();
|
2022-10-08 19:54:58 +02:00
|
|
|
auto r_size = fd_.write(PSLICE() << "[ 1][t" << (0 <= thread_id && thread_id < 10 ? " " : "") << thread_id
|
|
|
|
<< "] !!! Previous logging took " << total_time << " seconds !!!\n");
|
|
|
|
r_size.ignore();
|
2022-10-05 22:55:50 +02:00
|
|
|
}
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
|
2021-05-17 16:58:33 +02:00
|
|
|
void FileLog::after_rotation() {
|
2018-01-28 15:33:14 +01:00
|
|
|
if (path_.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-05-17 16:58:33 +02:00
|
|
|
do_after_rotation();
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
|
2020-06-24 13:47:36 +02:00
|
|
|
void FileLog::lazy_rotate() {
|
|
|
|
want_rotate_ = true;
|
|
|
|
}
|
|
|
|
|
2021-05-17 16:58:33 +02:00
|
|
|
void FileLog::do_after_rotation() {
|
2020-06-24 13:47:36 +02:00
|
|
|
want_rotate_ = false;
|
2020-06-26 01:24:13 +02:00
|
|
|
ScopedDisableLog disable_log; // to ensure that nothing will be printed to the closed log
|
2018-01-28 15:33:14 +01:00
|
|
|
CHECK(!path_.empty());
|
|
|
|
fd_.close();
|
2022-11-01 12:13:14 +01:00
|
|
|
auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Write | FileFd::Append);
|
2018-01-28 15:33:14 +01:00
|
|
|
if (r_fd.is_error()) {
|
2021-05-18 03:35:36 +02:00
|
|
|
process_fatal_error(PSLICE() << r_fd.error() << " in " << __FILE__ << " at " << __LINE__ << '\n');
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
fd_ = r_fd.move_as_ok();
|
2019-08-12 13:45:57 +02:00
|
|
|
if (!Stderr().empty() && redirect_stderr_) {
|
2018-09-13 13:26:22 +02:00
|
|
|
fd_.get_native_fd().duplicate(Stderr().get_native_fd()).ignore();
|
|
|
|
}
|
2022-11-29 15:39:46 +01:00
|
|
|
auto r_size = fd_.get_size();
|
|
|
|
if (r_fd.is_error()) {
|
|
|
|
process_fatal_error(PSLICE() << "Failed to get log size: " << r_fd.error() << " in " << __FILE__ << " at "
|
|
|
|
<< __LINE__ << '\n');
|
|
|
|
}
|
|
|
|
size_ = r_size.move_as_ok();
|
2020-06-24 13:47:36 +02:00
|
|
|
}
|
|
|
|
|
2020-06-26 01:24:13 +02:00
|
|
|
Result<unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {
|
2020-06-24 13:47:36 +02:00
|
|
|
auto l = make_unique<FileLog>();
|
|
|
|
TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr));
|
|
|
|
return std::move(l);
|
2018-01-28 15:33:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace td
|