blob: c3776cecdd238d0c2898a6d290ea0c75603e6c82 [file] [log] [blame]
// Copyright 2022 The Abseil Authors.
//
// 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
//
// https://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.
//
// -----------------------------------------------------------------------------
// File: log/log_streamer.h
// -----------------------------------------------------------------------------
//
// This header declares the class `LogStreamer` and convenience functions to
// construct LogStreamer objects with different associated log severity levels.
#ifndef ABSL_LOG_LOG_STREAMER_H_
#define ABSL_LOG_LOG_STREAMER_H_
#include <ios>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include "absl/base/config.h"
#include "absl/base/log_severity.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/strings/internal/ostringstream.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
// LogStreamer
//
// Although you can stream into `LOG(INFO)`, you can't pass it into a function
// that takes a `std::ostream` parameter. `LogStreamer::stream()` provides a
// `std::ostream` that buffers everything that's streamed in. The buffer's
// contents are logged as if by `LOG` when the `LogStreamer` is destroyed.
// If nothing is streamed in, an empty message is logged. If the specified
// severity is `absl::LogSeverity::kFatal`, the program will be terminated when
// the `LogStreamer` is destroyed regardless of whether any data were streamed
// in.
//
// Factory functions corresponding to the `absl::LogSeverity` enumerators
// are provided for convenience; if the desired severity is variable, invoke the
// constructor directly.
//
// LogStreamer is movable, but not copyable.
//
// Examples:
//
// ShaveYakAndWriteToStream(
// yak, absl::LogInfoStreamer(__FILE__, __LINE__).stream());
//
// {
// // This logs a single line containing data streamed by all three function
// // calls.
// absl::LogStreamer streamer(absl::LogSeverity::kInfo, __FILE__, __LINE__);
// ShaveYakAndWriteToStream(yak1, streamer.stream());
// streamer.stream() << " ";
// ShaveYakAndWriteToStream(yak2, streamer.stream());
// streamer.stream() << " ";
// ShaveYakAndWriteToStreamPointer(yak3, &streamer.stream());
// }
class LogStreamer final {
public:
// LogStreamer::LogStreamer()
//
// Creates a LogStreamer with a given `severity` that will log a message
// attributed to the given `file` and `line`.
explicit LogStreamer(absl::LogSeverity severity, absl::string_view file,
int line)
: severity_(severity),
line_(line),
file_(file),
stream_(
absl::make_unique<absl::strings_internal::OStringStream>(&buf_)) {
// To match `LOG`'s defaults:
stream_->setf(std::ios_base::showbase | std::ios_base::boolalpha);
}
// A moved-from `absl::LogStreamer` does not `LOG` when destroyed,
// and a program that streams into one has undefined behavior.
LogStreamer(LogStreamer&& that) noexcept
: severity_(that.severity_),
line_(that.line_),
file_(std::move(that.file_)),
buf_(std::move(that.buf_)),
stream_(that.stream_
? absl::make_unique<absl::strings_internal::OStringStream>(
&buf_)
: nullptr) {
that.stream_.reset();
}
LogStreamer& operator=(LogStreamer&& that) {
LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_;
severity_ = that.severity_;
file_ = std::move(that.file_);
line_ = that.line_;
buf_ = std::move(that.buf_);
stream_ =
that.stream_
? absl::make_unique<absl::strings_internal::OStringStream>(&buf_)
: nullptr;
that.stream_.reset();
return *this;
}
// LogStreamer::~LogStreamer()
//
// Logs this LogStreamer's buffered content as if by LOG.
~LogStreamer() {
LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_;
}
// LogStreamer::stream()
//
// Returns the `std::ostream` to use to write into this LogStreamer' internal
// buffer.
std::ostream& stream() { return *stream_; }
private:
absl::LogSeverity severity_;
int line_;
std::string file_;
std::string buf_;
// TODO(durandal): de-pointerize this once we are off of our old mostly-C++11
// libstdc++ (which lacks move constructors for std streams).
// `stream_` is null in a moved-from `LogStreamer`; this is in fact how we
// recognize one to avoid logging when it is destroyed or reassigned.
std::unique_ptr<absl::strings_internal::OStringStream> stream_;
};
// LogInfoStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kInfo.
inline LogStreamer LogInfoStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kInfo, file, line);
}
// LogWarningStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kWarning.
inline LogStreamer LogWarningStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kWarning, file, line);
}
// LogErrorStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kError.
inline LogStreamer LogErrorStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kError, file, line);
}
// LogFatalStreamer()
//
// Returns a LogStreamer that writes at level LogSeverity::kFatal.
//
// The program will be terminated when this `LogStreamer` is destroyed,
// regardless of whether any data were streamed in.
inline LogStreamer LogFatalStreamer(absl::string_view file, int line) {
return absl::LogStreamer(absl::LogSeverity::kFatal, file, line);
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOG_LOG_STREAMER_H_