mirror of
https://github.com/nestriness/cdc-file-transfer.git
synced 2026-01-30 16:35:35 +02:00
On Windows, fclose() seems to be very expensive for large files, where closing a 1 GB file takes up to 5 seconds. This CL calls fclose() in background threads. This tremendously improves local syncs, e.g. copying a 4.5 GB, 300 files data set takes only 7 seconds instead of 30 seconds. Also increases the buffer size for copying from 16K to 128K (better throughput for local copies), and adds a timestamp to debug and verbose console logs (useful when comparing client and server logs).
172 lines
4.2 KiB
C++
172 lines
4.2 KiB
C++
// Copyright 2022 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "log.h"
|
|
|
|
#include <cassert>
|
|
|
|
#include "common/platform.h"
|
|
|
|
#if PLATFORM_WINDOWS
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
namespace cdc_ft {
|
|
namespace {
|
|
|
|
const char* GetLogLevelString(LogLevel level) {
|
|
switch (level) {
|
|
case LogLevel::kVerbose:
|
|
return "VERBOSE";
|
|
case LogLevel::kDebug:
|
|
return "DEBUG";
|
|
case LogLevel::kInfo:
|
|
return "INFO";
|
|
case LogLevel::kWarning:
|
|
return "WARNING";
|
|
case LogLevel::kError:
|
|
return "ERROR";
|
|
}
|
|
return "UnknownLogLevel";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
void Log::Initialize(std::unique_ptr<Log> log) {
|
|
assert(!instance_);
|
|
instance_ = log.release();
|
|
}
|
|
|
|
// static
|
|
void Log::Shutdown() {
|
|
assert(instance_);
|
|
delete instance_;
|
|
instance_ = nullptr;
|
|
}
|
|
|
|
// static
|
|
Log* Log::Instance() {
|
|
assert(instance_);
|
|
return instance_;
|
|
}
|
|
|
|
// static
|
|
Log* Log::MaybeNullInstance() { return instance_; }
|
|
|
|
Log* Log::instance_ = nullptr;
|
|
|
|
Log::~Log() = default;
|
|
|
|
// static
|
|
LogLevel Log::VerbosityToLogLevel(int verbosity) {
|
|
if (verbosity >= 4) {
|
|
return LogLevel::kVerbose;
|
|
}
|
|
if (verbosity >= 3) {
|
|
return LogLevel::kDebug;
|
|
}
|
|
if (verbosity >= 2) {
|
|
return LogLevel::kInfo;
|
|
}
|
|
return LogLevel::kWarning;
|
|
}
|
|
|
|
// static
|
|
void Log::DefaultWriteLogMessage(LogLevel level, const char* file, int line,
|
|
const char* message) {
|
|
// Only print warnings and above.
|
|
if (level < LogLevel::kWarning) return;
|
|
fprintf(stderr, "%-7s %s(%i): %s\n", GetLogLevelString(level), file, line,
|
|
message);
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS
|
|
enum Colors {
|
|
kLightGray = 7,
|
|
kGray = 8,
|
|
kBlue = 9,
|
|
kCyan = 11,
|
|
kRed = 12,
|
|
kYellow = 14,
|
|
kWhite = 15
|
|
};
|
|
|
|
WORD GetConsoleColor(LogLevel level) {
|
|
switch (level) {
|
|
case LogLevel::kVerbose:
|
|
return kGray;
|
|
case LogLevel::kDebug:
|
|
return kCyan;
|
|
case LogLevel::kInfo:
|
|
return kWhite;
|
|
case LogLevel::kWarning:
|
|
return kYellow;
|
|
case LogLevel::kError:
|
|
return kRed;
|
|
}
|
|
return 15;
|
|
}
|
|
#endif
|
|
|
|
void ConsoleLog::WriteLogMessage(LogLevel level, const char* file, int line,
|
|
const char* func, const char* message) {
|
|
absl::MutexLock lock(&mutex_);
|
|
|
|
// Show leaner log messages in non-verbose mode.
|
|
bool show_time_file_func = GetLogLevel() <= LogLevel::kDebug;
|
|
FILE* stdfile = level >= LogLevel::kError ? stderr : stdout;
|
|
#if PLATFORM_WINDOWS
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
SetConsoleTextAttribute(hConsole, GetConsoleColor(level));
|
|
if (show_time_file_func) {
|
|
fprintf(stdfile, "%0.3f %s(%i): %s(): %s\n", stopwatch_.ElapsedSeconds(),
|
|
file, line, func, message);
|
|
} else {
|
|
fprintf(stdfile, "%s\n", message);
|
|
}
|
|
SetConsoleTextAttribute(hConsole, kLightGray);
|
|
#else
|
|
if (show_time_file_func) {
|
|
fprintf(stdfile, "%-7s %0.3f %s(%i): %s(): %s\n", GetLogLevelString(level),
|
|
stopwatch_.ElapsedSeconds(), file, line, func, message);
|
|
} else {
|
|
fprintf(stdfile, "%-7s %s\n", GetLogLevelString(level), message);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
FileLog::FileLog(LogLevel log_level, const char* path) : Log(log_level) {
|
|
file_ = fopen(path, "wt");
|
|
if (!file_) fprintf(stderr, "Failed to open log file '%s'", path);
|
|
}
|
|
|
|
FileLog::~FileLog() {
|
|
if (file_) fclose(file_);
|
|
}
|
|
|
|
void FileLog::WriteLogMessage(LogLevel level, const char* file, int line,
|
|
const char* func, const char* message) {
|
|
if (!file_) return;
|
|
std::string timestamp = clock_.FormatNow("%Y-%m-%d %H:%M:%S.", true);
|
|
|
|
absl::MutexLock lock(&mutex_);
|
|
fprintf(file_, "%s %-7s %s(%i): %s(): %s\n", timestamp.c_str(),
|
|
GetLogLevelString(level), file, line, func, message);
|
|
fflush(file_);
|
|
}
|
|
|
|
} // namespace cdc_ft
|