blob: 77073bf1a3bd8b7cc356a61b8c163ed6400a4979 [file] [log] [blame]
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 "src/main/cpp/util/bazel_log_handler.h"
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include "src/main/cpp/util/file.h"
#include "src/main/cpp/util/logging.h"
namespace blaze_util {
BazelLogHandler::BazelLogHandler()
: output_dir_set_attempted_(false),
buffer_stream_(new std::stringstream()),
logfile_stream_(nullptr) {}
BazelLogHandler::~BazelLogHandler() {
// If we never wrote the logs to a file, dump the buffer to stderr,
// otherwise, flush the stream.
if (logfile_stream_ != nullptr) {
logfile_stream_->flush();
} else if (buffer_stream_ != nullptr) {
std::cerr << buffer_stream_->rdbuf();
} else {
std::cerr << "Illegal state - neither a logfile nor a logbuffer "
<< "existed at program end." << std::endl;
}
}
void BazelLogHandler::HandleMessage(LogLevel level, const std::string& filename,
int line, const std::string& message) {
// Select the appropriate stream to log to.
std::ostream* log_stream;
if (logfile_stream_ != nullptr) {
log_stream = logfile_stream_.get();
} else {
log_stream = buffer_stream_.get();
}
*log_stream << "[bazel " << LogLevelName(level) << " " << filename << ":"
<< line << "] " << message << "\n";
// If we have a fatal message, we should abort and leave a stack trace -
// normal exit behavior will be lost, so print this log message out to
// stderr and avoid loosing the information.
if (level == LOGLEVEL_FATAL) {
std::cerr << "[bazel " << LogLevelName(level) << " " << filename << ":"
<< line << "] " << message << "\n";
std::abort();
}
}
void BazelLogHandler::SetOutputDir(const std::string& new_output_dir) {
// Disallow second calls to this, we only intend this to support setting
// output_base once it is created, not changing the log location.
BAZEL_CHECK(!output_dir_set_attempted_)
<< "Tried to SetOutputDir a second time, to " << new_output_dir;
output_dir_set_attempted_ = true;
// Create a log file in the newly available directory, and flush the
// buffer to it.
const std::string logfile = JoinPath(new_output_dir, "bazel_client.log");
logfile_stream_ = std::unique_ptr<std::ofstream>(
new std::ofstream(logfile, std::fstream::out));
if (logfile_stream_->fail()) {
// If opening the stream failed, continue buffering and have the logs
// dump to stderr at shutdown.
logfile_stream_ = nullptr;
BAZEL_LOG(ERROR) << "Opening the log file failed, in directory "
<< new_output_dir;
} else {
// Transfer the contents of the buffer to the logfile's stream before
// replacing it.
*logfile_stream_ << buffer_stream_->rdbuf();
buffer_stream_ = nullptr;
logfile_stream_->flush();
}
}
} // namespace blaze_util