blob: 4ed2435d61d1dc1a66ed434d60840453e1612b96 [file] [log] [blame]
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -07001// Copyright 2022 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// -----------------------------------------------------------------------------
16// File: log/log_streamer.h
17// -----------------------------------------------------------------------------
18//
19// This header declares the class `LogStreamer` and convenience functions to
20// construct LogStreamer objects with different associated log severity levels.
21
22#ifndef ABSL_LOG_LOG_STREAMER_H_
23#define ABSL_LOG_LOG_STREAMER_H_
24
25#include <ios>
26#include <memory>
27#include <ostream>
28#include <string>
29#include <utility>
30
31#include "absl/base/config.h"
32#include "absl/base/log_severity.h"
Andy Getzendanner2468b182022-12-17 12:00:38 -080033#include "absl/log/absl_log.h"
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -070034#include "absl/strings/internal/ostringstream.h"
35#include "absl/strings/string_view.h"
Andy Getzendannerd54fd912022-09-20 13:49:46 -070036#include "absl/types/optional.h"
37#include "absl/utility/utility.h"
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -070038
39namespace absl {
40ABSL_NAMESPACE_BEGIN
41
42// LogStreamer
43//
44// Although you can stream into `LOG(INFO)`, you can't pass it into a function
45// that takes a `std::ostream` parameter. `LogStreamer::stream()` provides a
46// `std::ostream` that buffers everything that's streamed in. The buffer's
47// contents are logged as if by `LOG` when the `LogStreamer` is destroyed.
48// If nothing is streamed in, an empty message is logged. If the specified
49// severity is `absl::LogSeverity::kFatal`, the program will be terminated when
50// the `LogStreamer` is destroyed regardless of whether any data were streamed
51// in.
52//
53// Factory functions corresponding to the `absl::LogSeverity` enumerators
54// are provided for convenience; if the desired severity is variable, invoke the
55// constructor directly.
56//
57// LogStreamer is movable, but not copyable.
58//
59// Examples:
60//
61// ShaveYakAndWriteToStream(
62// yak, absl::LogInfoStreamer(__FILE__, __LINE__).stream());
63//
64// {
65// // This logs a single line containing data streamed by all three function
66// // calls.
67// absl::LogStreamer streamer(absl::LogSeverity::kInfo, __FILE__, __LINE__);
68// ShaveYakAndWriteToStream(yak1, streamer.stream());
69// streamer.stream() << " ";
70// ShaveYakAndWriteToStream(yak2, streamer.stream());
71// streamer.stream() << " ";
72// ShaveYakAndWriteToStreamPointer(yak3, &streamer.stream());
73// }
74class LogStreamer final {
75 public:
76 // LogStreamer::LogStreamer()
77 //
78 // Creates a LogStreamer with a given `severity` that will log a message
79 // attributed to the given `file` and `line`.
80 explicit LogStreamer(absl::LogSeverity severity, absl::string_view file,
81 int line)
82 : severity_(severity),
83 line_(line),
84 file_(file),
Andy Getzendannerd54fd912022-09-20 13:49:46 -070085 stream_(absl::in_place, &buf_) {
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -070086 // To match `LOG`'s defaults:
87 stream_->setf(std::ios_base::showbase | std::ios_base::boolalpha);
88 }
89
90 // A moved-from `absl::LogStreamer` does not `LOG` when destroyed,
91 // and a program that streams into one has undefined behavior.
92 LogStreamer(LogStreamer&& that) noexcept
93 : severity_(that.severity_),
94 line_(that.line_),
95 file_(std::move(that.file_)),
96 buf_(std::move(that.buf_)),
Andy Getzendannerd54fd912022-09-20 13:49:46 -070097 stream_(std::move(that.stream_)) {
98 if (stream_.has_value()) stream_->str(&buf_);
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -070099 that.stream_.reset();
100 }
101 LogStreamer& operator=(LogStreamer&& that) {
Andy Getzendanner2468b182022-12-17 12:00:38 -0800102 ABSL_LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_;
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -0700103 severity_ = that.severity_;
104 file_ = std::move(that.file_);
105 line_ = that.line_;
106 buf_ = std::move(that.buf_);
Andy Getzendannerd54fd912022-09-20 13:49:46 -0700107 stream_ = std::move(that.stream_);
108 if (stream_.has_value()) stream_->str(&buf_);
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -0700109 that.stream_.reset();
110 return *this;
111 }
112
113 // LogStreamer::~LogStreamer()
114 //
115 // Logs this LogStreamer's buffered content as if by LOG.
116 ~LogStreamer() {
Andy Getzendanner2468b182022-12-17 12:00:38 -0800117 ABSL_LOG_IF(LEVEL(severity_), stream_.has_value()).AtLocation(file_, line_)
Andy Getzendannerd54fd912022-09-20 13:49:46 -0700118 << buf_;
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -0700119 }
120
121 // LogStreamer::stream()
122 //
123 // Returns the `std::ostream` to use to write into this LogStreamer' internal
124 // buffer.
125 std::ostream& stream() { return *stream_; }
126
127 private:
128 absl::LogSeverity severity_;
129 int line_;
130 std::string file_;
131 std::string buf_;
Andy Getzendannerd54fd912022-09-20 13:49:46 -0700132 // A disengaged `stream_` indicates a moved-from `LogStreamer` that should not
133 // `LOG` upon destruction.
134 absl::optional<absl::strings_internal::OStringStream> stream_;
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -0700135};
136
137// LogInfoStreamer()
138//
139// Returns a LogStreamer that writes at level LogSeverity::kInfo.
140inline LogStreamer LogInfoStreamer(absl::string_view file, int line) {
141 return absl::LogStreamer(absl::LogSeverity::kInfo, file, line);
142}
143
144// LogWarningStreamer()
145//
146// Returns a LogStreamer that writes at level LogSeverity::kWarning.
147inline LogStreamer LogWarningStreamer(absl::string_view file, int line) {
148 return absl::LogStreamer(absl::LogSeverity::kWarning, file, line);
149}
150
151// LogErrorStreamer()
152//
153// Returns a LogStreamer that writes at level LogSeverity::kError.
154inline LogStreamer LogErrorStreamer(absl::string_view file, int line) {
155 return absl::LogStreamer(absl::LogSeverity::kError, file, line);
156}
157
158// LogFatalStreamer()
159//
160// Returns a LogStreamer that writes at level LogSeverity::kFatal.
161//
162// The program will be terminated when this `LogStreamer` is destroyed,
163// regardless of whether any data were streamed in.
164inline LogStreamer LogFatalStreamer(absl::string_view file, int line) {
165 return absl::LogStreamer(absl::LogSeverity::kFatal, file, line);
166}
167
Derek Mauro70172ad2023-08-04 13:54:47 -0700168// LogDebugFatalStreamer()
169//
170// Returns a LogStreamer that writes at level LogSeverity::kLogDebugFatal.
171//
172// In debug mode, the program will be terminated when this `LogStreamer` is
173// destroyed, regardless of whether any data were streamed in.
174inline LogStreamer LogDebugFatalStreamer(absl::string_view file, int line) {
175 return absl::LogStreamer(absl::kLogDebugFatal, file, line);
176}
177
Gennadiy Rozental92fdbfb2022-08-25 14:15:03 -0700178ABSL_NAMESPACE_END
179} // namespace absl
180
181#endif // ABSL_LOG_LOG_STREAMER_H_