diff --git a/maldoca/base/BUILD b/maldoca/base/BUILD index ecd3353..1930fc4 100644 --- a/maldoca/base/BUILD +++ b/maldoca/base/BUILD @@ -29,8 +29,8 @@ cc_library( srcs = ["error_code_to_status.cc"], hdrs = ["error_code_to_status.h"], deps = [ - ":status", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:status_builder", ], ) @@ -64,6 +64,7 @@ cc_library( ":status", "@abseil-cpp//absl/log:check", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:status_builder", "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:string_view", @@ -84,68 +85,30 @@ cc_library( ], ) -cc_library( - name = "source_location", - hdrs = ["source_location.h"], - deps = [ - ], -) - cc_library( name = "ret_check", srcs = ["ret_check.cc"], hdrs = ["ret_check.h"], deps = [ - ":source_location", ":status", "@abseil-cpp//absl/base:core_headers", "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:status_builder", "@abseil-cpp//absl/status:statusor", - ], -) - -cc_library( - name = "symbolized_stacktrace", - srcs = ["symbolized_stacktrace.cc"], - hdrs = ["symbolized_stacktrace.h"], - deps = [ - "@abseil-cpp//absl/debugging:stacktrace", - "@abseil-cpp//absl/debugging:symbolize", - "@abseil-cpp//absl/strings:str_format", - ], -) - -cc_test( - name = "symbolized_stacktrace_test", - srcs = ["symbolized_stacktrace_test.cc"], - deps = [ - ":symbolized_stacktrace", - "@googletest//:gtest_main", + "@abseil-cpp//absl/types:source_location", ], ) cc_library( name = "status", - srcs = ["status_builder.cc"], hdrs = [ - "status_builder.h", "status_macros.h", ], deps = [ - ":source_location", - ":symbolized_stacktrace", "@abseil-cpp//absl/base:core_headers", - "@abseil-cpp//absl/base:log_severity", - "@abseil-cpp//absl/container:flat_hash_map", - "@abseil-cpp//absl/log", - "@abseil-cpp//absl/log:log_entry", - "@abseil-cpp//absl/log:log_sink", "@abseil-cpp//absl/status", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:cord", - "@abseil-cpp//absl/synchronization", - "@abseil-cpp//absl/time", - "@abseil-cpp//absl/types:span", + "@abseil-cpp//absl/status:status_builder", + "@abseil-cpp//absl/types:source_location", ], ) diff --git a/maldoca/base/error_code_to_status.cc b/maldoca/base/error_code_to_status.cc index c12c314..7fa8dfb 100644 --- a/maldoca/base/error_code_to_status.cc +++ b/maldoca/base/error_code_to_status.cc @@ -17,7 +17,7 @@ #include // NOLINT(build/c++11): open source #include "absl/status/status.h" -#include "maldoca/base/status_builder.h" +#include "absl/status/status_builder.h" namespace maldoca { @@ -197,12 +197,13 @@ absl::StatusCode ErrorCodeToStatusCode(const std::error_code& ec) { } } -StatusBuilder ErrorCodeToStatus(const std::error_code& ec) { - return StatusBuilder(absl::Status(ErrorCodeToStatusCode(ec), ec.message())); +absl::StatusBuilder ErrorCodeToStatus(const std::error_code& ec) { + return absl::StatusBuilder( + absl::Status(ErrorCodeToStatusCode(ec), ec.message())); } -StatusBuilder ErrnoToStatus(int errno_value) { - return StatusBuilder( +absl::StatusBuilder ErrnoToStatus(int errno_value) { + return absl::StatusBuilder( ErrorCodeToStatus(std::error_code(errno_value, std::generic_category()))); } diff --git a/maldoca/base/error_code_to_status.h b/maldoca/base/error_code_to_status.h index 0b77ff3..58c79fd 100644 --- a/maldoca/base/error_code_to_status.h +++ b/maldoca/base/error_code_to_status.h @@ -18,16 +18,16 @@ #include // NOLINT(build/c++11): open source #include "absl/status/status.h" -#include "maldoca/base/status_builder.h" +#include "absl/status/status_builder.h" namespace maldoca { absl::StatusCode ErrorCodeToStatusCode(const std::error_code& ec); -StatusBuilder ErrorCodeToStatus(const std::error_code& ec); +absl::StatusBuilder ErrorCodeToStatus(const std::error_code& ec); // Converts an `errno` value into an absl::Status. -StatusBuilder ErrnoToStatus(int errno_value); +absl::StatusBuilder ErrnoToStatus(int errno_value); } // namespace maldoca diff --git a/maldoca/base/filesystem.cc b/maldoca/base/filesystem.cc index d733a46..a53015a 100644 --- a/maldoca/base/filesystem.cc +++ b/maldoca/base/filesystem.cc @@ -23,11 +23,11 @@ #include "absl/log/check.h" #include "absl/status/status.h" +#include "absl/status/status_builder.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "maldoca/base/error_code_to_status.h" -#include "maldoca/base/status_builder.h" #include "maldoca/base/status_macros.h" #include "google/protobuf/io/tokenizer.h" #include "google/protobuf/message.h" @@ -40,7 +40,7 @@ namespace { // the filename. absl::Status ErrNoToStatusWithFilename(int errno_value, const std::filesystem::path& file_name) { - StatusBuilder builder = ErrnoToStatus(errno); + absl::StatusBuilder builder = ErrnoToStatus(errno); builder << file_name.string(); return std::move(builder); } diff --git a/maldoca/base/ret_check.cc b/maldoca/base/ret_check.cc index 4bc6102..cee0898 100644 --- a/maldoca/base/ret_check.cc +++ b/maldoca/base/ret_check.cc @@ -22,34 +22,34 @@ #include "absl/base/log_severity.h" #include "absl/status/status.h" -#include "maldoca/base/source_location.h" -#include "maldoca/base/status_builder.h" +#include "absl/status/status_builder.h" +#include "absl/types/source_location.h" namespace maldoca { namespace internal_status_macros_ret_check { -StatusBuilder RetCheckFailSlowPath(SourceLocation location) { - return InternalErrorBuilder(location) +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location) { + return absl::StatusBuilder(absl::StatusCode::kInternal, location) .Log(absl::LogSeverity::kError) .EmitStackTrace() << "MALDOCA_RET_CHECK failure (" << location.file_name() << ":" << location.line() << ") "; } -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - std::string* condition) { +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + std::string* condition) { std::unique_ptr cleanup(condition); return RetCheckFailSlowPath(location) << *condition << " "; } -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - const char* condition) { +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + const char* condition) { return RetCheckFailSlowPath(location) << condition << " "; } -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - const char* condition, - const absl::Status& status) { +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + const char* condition, + const absl::Status& status) { return RetCheckFailSlowPath(location) << condition << " returned " << status.ToString() << " "; } diff --git a/maldoca/base/ret_check.h b/maldoca/base/ret_check.h index cf2ef75..7c4edb8 100644 --- a/maldoca/base/ret_check.h +++ b/maldoca/base/ret_check.h @@ -46,33 +46,33 @@ #include "absl/base/attributes.h" #include "absl/base/optimization.h" #include "absl/status/status.h" +#include "absl/status/status_builder.h" #include "absl/status/statusor.h" -#include "maldoca/base/source_location.h" -#include "maldoca/base/status_builder.h" +#include "absl/types/source_location.h" #include "maldoca/base/status_macros.h" namespace maldoca { namespace internal_status_macros_ret_check { // Returns a StatusBuilder that corresponds to a `MALDOCA_RET_CHECK` failure. -StatusBuilder RetCheckFailSlowPath(SourceLocation location); -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - const char* condition); -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - const char* condition, - const absl::Status& s); +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location); +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + const char* condition); +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + const char* condition, + const absl::Status& s); // Takes ownership of `condition`. This API is a little quirky because it is // designed to make use of the `::Check_*Impl` methods that implement `CHECK_*` // and `DCHECK_*`. -StatusBuilder RetCheckFailSlowPath(SourceLocation location, - std::string* condition); +absl::StatusBuilder RetCheckFailSlowPath(absl::SourceLocation location, + std::string* condition); -inline StatusBuilder RetCheckImpl(const absl::Status& status, - const char* condition, - SourceLocation location) { +inline absl::StatusBuilder RetCheckImpl(const absl::Status& status, + const char* condition, + absl::SourceLocation location) { if (ABSL_PREDICT_TRUE(status.ok())) { - return StatusBuilder(absl::OkStatus(), location); + return absl::StatusBuilder(absl::OkStatus(), location); } return RetCheckFailSlowPath(location, condition, status); } @@ -214,11 +214,11 @@ inline unsigned long long GetReferenceableValue( // NOLINT: runtime/int #define MALDOCA_RET_CHECK(cond) \ while (ABSL_PREDICT_FALSE(!(cond))) \ return ::maldoca::internal_status_macros_ret_check::RetCheckFailSlowPath( \ - MALDOCA_LOC, #cond) + absl::SourceLocation::current(), #cond) #define MALDOCA_RET_CHECK_FAIL() \ return ::maldoca::internal_status_macros_ret_check::RetCheckFailSlowPath( \ - MALDOCA_LOC) + absl::SourceLocation::current()) // Takes an expression returning absl::Status and asserts that the status is // `ok()`. If not, it returns an internal error. @@ -235,7 +235,7 @@ inline unsigned long long GetReferenceableValue( // NOLINT: runtime/int MALDOCA_RETURN_IF_ERROR( \ ::maldoca::internal_status_macros_ret_check::RetCheckImpl( \ ::maldoca::internal_status_macros_ret_check::AsStatus(status), \ - #status, MALDOCA_LOC)) + #status, absl::SourceLocation::current())) #if defined(STATIC_ANALYSIS) || defined(PORTABLE_STATUS) #define MALDOCA_COMMON_MACROS_INTERNAL_RET_CHECK_OP(name, op, lhs, rhs) \ @@ -250,7 +250,7 @@ inline unsigned long long GetReferenceableValue( // NOLINT: runtime/int GetReferenceableValue(rhs), \ #lhs " " #op " " #rhs)) \ return ::maldoca::internal_status_macros_ret_check::RetCheckFailSlowPath( \ - MALDOCA_LOC, _result) + absl::SourceLocation::current(), _result) #endif #define MALDOCA_RET_CHECK_EQ(lhs, rhs) \ diff --git a/maldoca/base/source_location.h b/maldoca/base/source_location.h deleted file mode 100644 index d3105d7..0000000 --- a/maldoca/base/source_location.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#ifndef MALDOCA_BASE_SOURCE_LOCATION_H_ -#define MALDOCA_BASE_SOURCE_LOCATION_H_ - -#ifdef MALDOCA_USE_ABSL_SOURCE_LOCATION - -#include "absl/types/source_location.h" - -// Use absl::SourceLocation -namespace maldoca { - -using SourceLocation = absl::SourceLocation; -#define MALDOCA_LOC ABSL_LOC -#define MALDOCA_LOC_CURRENT_DEFAULT_ARG ABSL_LOC_CURRENT_DEFAULT_ARG - -} // namespace maldoca - -#else - -#include - -#define MALDOCA_HAVE_SOURCE_LOCATION_CURRENT 1 - -namespace maldoca { - -// Class representing a specific location in the source code of a program. -// `maldoca::SourceLocation` is copyable. -class SourceLocation { - struct PrivateTag { - private: - explicit PrivateTag() = default; - friend class SourceLocation; - }; - - public: - // Avoid this constructor; it populates the object with dummy values. - constexpr SourceLocation() : line_(0), file_name_(nullptr) {} - - // Wrapper to invoke the private constructor below. This should only be used - // by the `MALDOCA_LOC` macro, hence the name. - static constexpr SourceLocation DoNotInvokeDirectly(std::uint_least32_t line, - const char* file_name) { - return SourceLocation(line, file_name); - } - -#ifdef MALDOCA_HAVE_SOURCE_LOCATION_CURRENT - // SourceLocation::current - // - // Creates a `SourceLocation` based on the current line and file. APIs that - // accept a `SourceLocation` as a default parameter can use this to capture - // their caller's locations. - // - // Example: - // - // void TracedAdd(int i, SourceLocation loc = SourceLocation::current()) { - // std::cout << loc.file_name() << ":" << loc.line() << " added " << i; - // ... - // } - // - // void UserCode() { - // TracedAdd(1); - // TracedAdd(2); - // } - static constexpr SourceLocation current( - PrivateTag = PrivateTag{}, std::uint_least32_t line = __builtin_LINE(), - const char* file_name = __builtin_FILE()) { - return SourceLocation(line, file_name); - } -#else - // Creates a dummy `SourceLocation` of "" at line number 1, - // if no `SourceLocation::current()` implementation is available. - static constexpr SourceLocation current() { - return SourceLocation(1, ""); - } -#endif - // The line number of the captured source location. - constexpr std::uint_least32_t line() const { return line_; } - - // The file name of the captured source location. - constexpr const char* file_name() const { return file_name_; } - - // `column()` and `function_name()` are omitted because we don't have a way to - // support them. - - private: - // Do not invoke this constructor directly. Instead, use the `MALDOCA_LOC` - // macro below. - // - // `file_name` must outlive all copies of the `maldoca::SourceLocation` - // object, so in practice it should be a string literal. - constexpr SourceLocation(std::uint_least32_t line, const char* file_name) - : line_(line), file_name_(file_name) {} - - friend constexpr int UseUnused() { - static_assert(SourceLocation(0, nullptr).unused_column_ == 0, - "Use the otherwise-unused member."); - return 0; - } - - // "unused" members are present to minimize future changes in the size of this - // type. - std::uint_least32_t line_; - std::uint_least32_t unused_column_ = 0; - const char* file_name_; -}; - -} // namespace maldoca - -// If a function takes an `maldoca::SourceLocation` parameter, pass this as the -// argument. -#define MALDOCA_LOC \ - ::maldoca::SourceLocation::DoNotInvokeDirectly(__LINE__, __FILE__) - -// ABSL_LOC_CURRENT_DEFAULT_ARG -// -// Specifies that a function should use `maldoca::SourceLocation::current()` on -// platforms where it will return useful information, but require explicitly -// passing `MALDOCA_LOC` on platforms where it would return dummy information. -// -// Usage: -// -// void MyLog(std::string_view msg, -// maldoca::SourceLocation loc MALDOCA_LOC_CURRENT_DEFAULT_ARG) { -// std::cout << loc.file_name() << "@" << loc.line() << ": " << msg; -// } -// -#if MALDOCA_HAVE_SOURCE_LOCATION_CURRENT -#define MALDOCA_LOC_CURRENT_DEFAULT_ARG = ::maldoca::SourceLocation::current() -#else -#define MALDOCA_LOC_CURRENT_DEFAULT_ARG -#endif - -#endif // MALDOCA_USE_ABSL_SOURCE_LOCATION - -#endif // MALDOCA_BASE_SOURCE_LOCATION_H_ diff --git a/maldoca/base/status_builder.cc b/maldoca/base/status_builder.cc deleted file mode 100644 index 836ce96..0000000 --- a/maldoca/base/status_builder.cc +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#include "maldoca/base/status_builder.h" - -#include -#include -#include -#include -#include -#include - -#include "absl/base/log_severity.h" -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/log/log.h" -#include "absl/log/log_entry.h" -#include "absl/log/log_sink.h" -#include "absl/status/status.h" -#include "absl/strings/cord.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "absl/types/span.h" -#include "maldoca/base/source_location.h" -#include "maldoca/base/symbolized_stacktrace.h" - -namespace maldoca { - -StatusBuilder::Rep::Rep(const Rep& r) - : logging_mode(r.logging_mode), - log_severity(r.log_severity), - verbose_level(r.verbose_level), - n(r.n), - period(r.period), - stream(r.stream.str()), - should_log_stack_trace(r.should_log_stack_trace), - message_join_style(r.message_join_style), - sink(r.sink) {} - -absl::Status StatusBuilder::JoinMessageToStatus(absl::Status s, - absl::string_view msg, - MessageJoinStyle style) { - if (msg.empty()) { - return s; - } - if (style == MessageJoinStyle::kAnnotate) { - return AnnotateStatus(s, msg); - } - std::string new_msg = style == MessageJoinStyle::kPrepend - ? absl::StrCat(msg, s.message()) - : absl::StrCat(s.message(), msg); - absl::Status result = WithMessage(s, new_msg); - SetStatusCode(s.code(), &result); - return result; -} - -void StatusBuilder::ConditionallyLog(const absl::Status& status) const { - if (rep_->logging_mode == Rep::LoggingMode::kDisabled) { - return; - } - - absl::LogSeverity severity = rep_->log_severity; - switch (rep_->logging_mode) { - case Rep::LoggingMode::kDisabled: - case Rep::LoggingMode::kLog: - break; - case Rep::LoggingMode::kVLog: { - // Combine these into a single struct so that we only have one atomic - // access on each pass through the function (instead of one for the map - // and one for the mutex). - struct LogSites { - absl::Mutex mutex; - // NOLINTNEXTLINE(abseil-no-internal-dependencies) - std::unordered_map - sites_by_file ABSL_GUARDED_BY(mutex); - }; - static auto* vlog_sites = new LogSites(); - - vlog_sites->mutex.lock(); - // This assumes that loc_.file_name() is a compile time constant in order - // to satisfy the lifetime constraints imposed by VLogSite. The - // constructors of SourceLocation guarantee that for us. - auto [iter, unused] = vlog_sites->sites_by_file.try_emplace( - loc_.file_name(), loc_.file_name()); - auto& site = iter->second; - vlog_sites->mutex.unlock(); - - if (!site.IsEnabled(rep_->verbose_level)) { - return; - } - - severity = absl::LogSeverity::kInfo; - break; - } - case Rep::LoggingMode::kLogEveryN: { - struct LogSites { - absl::Mutex mutex; - absl::flat_hash_map, uint> - counts_by_file_and_line ABSL_GUARDED_BY(mutex); - }; - static auto* log_every_n_sites = new LogSites(); - - log_every_n_sites->mutex.lock(); - const uint count = - log_every_n_sites - ->counts_by_file_and_line[{loc_.file_name(), loc_.line()}]++; - log_every_n_sites->mutex.unlock(); - - if (count % rep_->n != 0) { - return; - } - break; - } - case Rep::LoggingMode::kLogEveryPeriod: { - struct LogSites { - absl::Mutex mutex; - absl::flat_hash_map, absl::Time> - next_log_by_file_and_line ABSL_GUARDED_BY(mutex); - }; - static auto* log_every_sites = new LogSites(); - - const auto now = absl::Now(); - absl::MutexLock lock(log_every_sites->mutex); - absl::Time& next_log = - log_every_sites - ->next_log_by_file_and_line[{loc_.file_name(), loc_.line()}]; - if (now < next_log) { - return; - } - next_log = now + rep_->period; - break; - } - } - - absl::LogSink* const sink = rep_->sink; - const std::string maybe_stack_trace = - rep_->should_log_stack_trace - ? absl::StrCat("\n", GetSymbolizedStackTraceAsString( - /*max_depth=*/50, /*skip_count=*/1)) - : ""; - const int verbose_level = rep_->logging_mode == Rep::LoggingMode::kVLog - ? rep_->verbose_level - : absl::LogEntry::kNoVerboseLevel; - if (sink) { - LOG(LEVEL(severity)) - .AtLocation(loc_.file_name(), loc_.line()) - .ToSinkAlso(sink) - .WithVerbosity(verbose_level) - << status << maybe_stack_trace; - } else { - // sink == nullptr indicates not to call ToSinkAlso(), which dies if sink is - // nullptr. Unfortunately, this means we reproduce the above macro call. - LOG(LEVEL(severity)) - .AtLocation(loc_.file_name(), loc_.line()) - .WithVerbosity(verbose_level) - << status << maybe_stack_trace; - } -} - -void StatusBuilder::SetStatusCode(absl::StatusCode canonical_code, - absl::Status* status) { - if (status->code() == canonical_code) { - return; - } - absl::Status new_status(canonical_code, status->message()); - CopyPayloads(*status, &new_status); - using std::swap; - swap(*status, new_status); -} - -void StatusBuilder::CopyPayloads(const absl::Status& src, absl::Status* dst) { - src.ForEachPayload([&](absl::string_view type_url, absl::Cord payload) { - dst->SetPayload(type_url, payload); - }); -} - -absl::Status StatusBuilder::WithMessage(const absl::Status& status, - absl::string_view msg) { - // Unfortunately since we can't easily strip the source-location off of this - // new status the backtrace can end up with a lot of copies of this line at - // the beginning. We manually try to trim them out but we can't actually - // remove the first one. - auto ret = absl::Status(status.code(), msg); - std::optional first = - StatusBuilder::GetSourceLocations(ret).empty() - ? std::nullopt - : std::make_optional( - StatusBuilder::GetSourceLocations(ret).front()); - bool first_non_duplicate = false; - for (const SourceLocation& sl : StatusBuilder::GetSourceLocations(status)) { - if (!first_non_duplicate && first && first->line() == sl.line() && - absl::string_view(first->file_name()) == - absl::string_view(sl.file_name())) { - continue; - } - first_non_duplicate = true; - StatusBuilder::AddSourceLocation(ret, sl); - } - CopyPayloads(status, &ret); - return ret; -} - -absl::Status StatusBuilder::AnnotateStatus(const absl::Status& s, - absl::string_view msg) { - if (s.ok() || msg.empty()) { - return s; - } - - absl::string_view new_msg = msg; - std::string annotated; - if (!s.message().empty()) { - absl::StrAppend(&annotated, s.message(), "; ", msg); - new_msg = annotated; - } - absl::Status result = WithMessage(s, new_msg); - SetStatusCode(s.code(), &result); - return result; -} - -absl::Status StatusBuilder::CreateStatusAndConditionallyLog() && { - absl::Status result = JoinMessageToStatus( - std::move(status_), rep_->stream.str(), rep_->message_join_style); - ConditionallyLog(result); - StatusBuilder::AddSourceLocation(result, loc_); - - // We consumed the status above, we set it to some error just to prevent - // people relying on it become OK or something. - status_ = absl::UnknownError(""); - rep_ = nullptr; - return result; -} - -/* static */ void StatusBuilder::AddSourceLocation(absl::Status& status, - SourceLocation loc) { -} - -/* static */ absl::Span StatusBuilder::GetSourceLocations( - const absl::Status& status) { - absl::Span result; - return result; -} - -std::ostream& operator<<(std::ostream& os, const StatusBuilder& builder) { - return os << static_cast(builder); -} - -std::ostream& operator<<(std::ostream& os, StatusBuilder&& builder) { - return os << static_cast(std::move(builder)); -} - -StatusBuilder AbortedErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kAborted, location); -} - -StatusBuilder AlreadyExistsErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kAlreadyExists, location); -} - -StatusBuilder CancelledErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kCancelled, location); -} - -StatusBuilder DataLossErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kDataLoss, location); -} - -StatusBuilder DeadlineExceededErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kDeadlineExceeded, location); -} - -StatusBuilder FailedPreconditionErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kFailedPrecondition, location); -} - -StatusBuilder InternalErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kInternal, location); -} - -StatusBuilder InvalidArgumentErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kInvalidArgument, location); -} - -StatusBuilder NotFoundErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kNotFound, location); -} - -StatusBuilder OutOfRangeErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kOutOfRange, location); -} - -StatusBuilder PermissionDeniedErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kPermissionDenied, location); -} - -StatusBuilder UnauthenticatedErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kUnauthenticated, location); -} - -StatusBuilder ResourceExhaustedErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kResourceExhausted, location); -} - -StatusBuilder UnavailableErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kUnavailable, location); -} - -StatusBuilder UnimplementedErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kUnimplemented, location); -} - -StatusBuilder UnknownErrorBuilder(SourceLocation location) { - return StatusBuilder(absl::StatusCode::kUnknown, location); -} - -} // namespace maldoca diff --git a/maldoca/base/status_builder.h b/maldoca/base/status_builder.h deleted file mode 100644 index 6358999..0000000 --- a/maldoca/base/status_builder.h +++ /dev/null @@ -1,684 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#ifndef MALDOCA_BASE_STATUS_BUILDER_H_ -#define MALDOCA_BASE_STATUS_BUILDER_H_ - -#include -#include -#include -#include -#include - -#include "absl/base/attributes.h" -#include "absl/base/log_severity.h" -#include "absl/log/log_sink.h" -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "absl/types/span.h" -#include "maldoca/base/source_location.h" - -namespace maldoca { - -// Creates a status based on an original_status, but enriched with additional -// information. The builder implicitly converts to Status and StatusOr -// allowing for it to be returned directly. -// -// StatusBuilder builder(original); -// builder << "info about error"; -// return builder; -// -// It provides method chaining to simplify typical usage: -// -// return StatusBuilder(original) -// .Log(absl::LogSeverity::kWarning) << "oh no!"; -// -// In more detail: -// - When the original status is OK, all methods become no-ops and nothing will -// be logged. -// - Messages streamed into the status builder are collected into a single -// additional message string. -// - The original Status's message and the additional message are joined -// together when the result status is built. -// - By default, the messages will be joined including a convenience separator -// between the original message and the additional one. This behavior can be -// changed with the `SetAppend()` and `SetPrepend()` methods of the builder. -// - By default, the result status is not logged. The `Log` and -// `EmitStackTrace` methods will cause the builder to log the result status -// when it is built. -// - All side effects (like logging or constructing a stack trace) happen when -// the builder is converted to a status. -class ABSL_MUST_USE_RESULT StatusBuilder { - public: - // Creates a `StatusBuilder` based on an original status. If logging is - // enabled, it will use `location` as the location from which the log message - // occurs. A typical user will not specify `location`, allowing it to default - // to the current location. - explicit StatusBuilder(const absl::Status& original_status, - SourceLocation location = SourceLocation::current()); - explicit StatusBuilder(absl::Status&& original_status, - SourceLocation location = SourceLocation::current()); - - // Creates a `StatusBuilder` from a status code. If logging is enabled, it - // will use `location` as the location from which the log message occurs. A - // typical user will not specify `location`, allowing it to default to the - // current location. - explicit StatusBuilder(absl::StatusCode code, - SourceLocation location = SourceLocation::current()); - - StatusBuilder(const StatusBuilder& sb); - StatusBuilder& operator=(const StatusBuilder& sb); - StatusBuilder(StatusBuilder&&) = default; - StatusBuilder& operator=(StatusBuilder&&) = default; - - // Mutates the builder so that the final additional message is prepended to - // the original error message in the status. A convenience separator is not - // placed between the messages. - // - // NOTE: Multiple calls to `SetPrepend` and `SetAppend` just adjust the - // behavior of the final join of the original status with the extra message. - // - // Returns `*this` to allow method chaining. - StatusBuilder& SetPrepend() &; - StatusBuilder&& SetPrepend() &&; - - // Mutates the builder so that the final additional message is appended to the - // original error message in the status. A convenience separator is not - // placed between the messages. - // - // NOTE: Multiple calls to `SetPrepend` and `SetAppend` just adjust the - // behavior of the final join of the original status with the extra message. - // - // Returns `*this` to allow method chaining. - StatusBuilder& SetAppend() &; - StatusBuilder&& SetAppend() &&; - - // Mutates the builder to disable any logging that was set using any of the - // logging functions below. Returns `*this` to allow method chaining. - StatusBuilder& SetNoLogging() &; - StatusBuilder&& SetNoLogging() &&; - - // Mutates the builder so that the result status will be logged (without a - // stack trace) when this builder is converted to a Status. This overrides - // the logging settings from earlier calls to any of the logging mutator - // functions. Returns `*this` to allow method chaining. - StatusBuilder& Log(absl::LogSeverity level) &; - StatusBuilder&& Log(absl::LogSeverity level) &&; - StatusBuilder& LogError() & { return Log(absl::LogSeverity::kError); } - StatusBuilder&& LogError() && { return std::move(LogError()); } - StatusBuilder& LogWarning() & { return Log(absl::LogSeverity::kWarning); } - StatusBuilder&& LogWarning() && { return std::move(LogWarning()); } - StatusBuilder& LogInfo() & { return Log(absl::LogSeverity::kInfo); } - StatusBuilder&& LogInfo() && { return std::move(LogInfo()); } - - // Mutates the builder so that the result status will be logged every N - // invocations (without a stack trace) when this builder is converted to a - // Status. This overrides the logging settings from earlier calls to any of - // the logging mutator functions. Returns `*this` to allow method chaining. - StatusBuilder& LogEveryN(absl::LogSeverity level, int n) &; - StatusBuilder&& LogEveryN(absl::LogSeverity level, int n) &&; - - // Mutates the builder so that the result status will be logged once per - // period (without a stack trace) when this builder is converted to a Status. - // This overrides the logging settings from earlier calls to any of the - // logging mutator functions. Returns `*this` to allow method chaining. - // If period is absl::ZeroDuration() or less, then this is equivalent to - // calling the Log() method. - StatusBuilder& LogEvery(absl::LogSeverity level, absl::Duration period) &; - StatusBuilder&& LogEvery(absl::LogSeverity level, absl::Duration period) &&; - - // Mutates the builder so that the result status will be VLOGged (without a - // stack trace) when this builder is converted to a Status. `verbose_level` - // indicates the verbosity level that would be passed to VLOG(). This - // overrides the logging settings from earlier calls to any of the logging - // mutator functions. Returns `*this` to allow method chaining. - StatusBuilder& VLog(int verbose_level) &; - StatusBuilder&& VLog(int verbose_level) &&; - - // Mutates the builder so that a stack trace will be logged if the status is - // logged. One of the logging setters above should be called as well. If - // logging is not yet enabled this behaves as if LogInfo().EmitStackTrace() - // was called. Returns `*this` to allow method chaining. - StatusBuilder& EmitStackTrace() &; - StatusBuilder&& EmitStackTrace() &&; - - // Mutates the builder so that the result status will also be logged to the - // provided `sink` when this builder is converted to a status. Overwrites any - // sink set prior. The provided `sink` must point to a valid object by the - // time this builder is converted to a status. Has no effect if this builder - // is not configured to log by calling any of the LogXXX methods. Returns - // `*this` to allow method chaining. - StatusBuilder& AlsoOutputToSink(absl::LogSink* sink) &; - StatusBuilder&& AlsoOutputToSink(absl::LogSink* sink) &&; - - // Appends to the extra message that will be added to the original status. By - // default, the extra message is added to the original message and includes a - // convenience separator between the original message and the enriched one. - template - StatusBuilder& operator<<(const T& value) &; - template - StatusBuilder&& operator<<(const T& value) &&; - - // Sets the status code for the status that will be returned by this - // StatusBuilder. Returns `*this` to allow method chaining. - StatusBuilder& SetCode(absl::StatusCode code) &; - StatusBuilder&& SetCode(absl::StatusCode code) &&; - - ///////////////////////////////// Adaptors ///////////////////////////////// - // - // A StatusBuilder `adaptor` is a functor which can be included in a builder - // method chain. There are two common variants: - // - // 1. `Pure policy` adaptors modify the StatusBuilder and return the modified - // object, which can then be chained with further adaptors or mutations. - // - // 2. `Terminal` adaptors consume the builder's Status and return some - // other type of object. Alternatively, the consumed Status may be used - // for side effects, e.g. by passing it to a side channel. A terminal - // adaptor cannot be chained. - // - // Careful: The conversion of StatusBuilder to Status has side effects! - // Adaptors must ensure that this conversion happens at most once in the - // builder chain. The easiest way to do this is to determine the adaptor type - // and follow the corresponding guidelines: - // - // Pure policy adaptors should: - // (a) Take a StatusBuilder as input parameter. - // (b) NEVER convert the StatusBuilder to Status: - // - Never assign the builder to a Status variable. - // - Never pass the builder to a function whose parameter type is Status, - // including by reference (e.g. const Status&). - // - Never pass the builder to any function which might convert the - // builder to Status (i.e. this restriction is viral). - // (c) Return a StatusBuilder (usually the input parameter). - // - // Terminal adaptors should: - // (a) Take a Status as input parameter (not a StatusBuilder!). - // (b) Return a type matching the enclosing function. (This can be `void`.) - // - // Adaptors do not necessarily fit into one of these categories. However, any - // which satisfies the conversion rule can always be decomposed into a pure - // adaptor chained into a terminal adaptor. (This is recommended.) - // - // Examples - // - // Pure adaptors allow teams to configure team-specific error handling - // policies. For example: - // - // StatusBuilder TeamPolicy(StatusBuilder builder) { - // return std::move(builder).Log(absl::LogSeverity::kWarning); - // } - // - // MALDOCA_RETURN_IF_ERROR(foo()).With(TeamPolicy); - // - // Because pure policy adaptors return the modified StatusBuilder, they - // can be chained with further adaptors, e.g.: - // - // MALDOCA_RETURN_IF_ERROR(foo()).With(TeamPolicy).With(OtherTeamPolicy); - // - // Terminal adaptors are often used for type conversion. This allows - // MALDOCA_RETURN_IF_ERROR to be used in functions which do not return Status. - // For example, a function might want to return some default value on error: - // - // int GetSysCounter() { - // int value; - // MALDOCA_RETURN_IF_ERROR(ReadCounterFile(filename, &value)) - // .LogInfo() - // .With([](const absl::Status& unused) { return 0; }); - // return value; - // } - // - // For the simple case of returning a constant (e.g. zero, false, nullptr) on - // error, consider `status_macros::Return` or `status_macros::ReturnVoid`: - // - // bool DoMyThing() { - // MALDOCA_RETURN_IF_ERROR(foo()) - // .LogWarning().With(status_macros::Return(false)); - // ... - // } - // - // A terminal adaptor may instead (or additionally) be used to create side - // effects that are not supported natively by `StatusBuilder`, such as - // returning the Status through a side channel. - - // Calls `adaptor` on this status builder to apply policies, type conversions, - // and/or side effects on the StatusBuilder. Returns the value returned by - // `adaptor`, which may be any type including `void`. See comments above. - // - // Style guide exception for Ref qualified methods and rvalue refs. This - // allows us to avoid a copy in the common case. - template - auto With( - Adaptor&& adaptor) & -> decltype(std::forward(adaptor)(*this)) { - return std::forward(adaptor)(*this); - } - template - auto With(Adaptor&& adaptor) && -> decltype(std::forward(adaptor)( - std::move(*this))) { - return std::forward(adaptor)(std::move(*this)); - } - - // Returns true if the Status created by this builder will be ok(). - bool ok() const; - - // Returns the (canonical) error code for the Status created by this builder. - absl::StatusCode code() const; - - // Implicit conversion to Status. - // - // Careful: this operator has side effects, so it should be called at - // most once. In particular, do NOT use this conversion operator to inspect - // the status from an adapter object passed into With(). - // - // Style guide exception for using Ref qualified methods and for implicit - // conversions. This override allows us to implement MALDOCA_RETURN_IF_ERROR - // with 2 move operations in the common case. - operator absl::Status() const&; // NOLINT: Builder converts implicitly. - operator absl::Status() &&; // NOLINT: Builder converts implicitly. - - // Returns the source location used to create this builder. - SourceLocation source_location() const; - - private: - // Specifies how to join the error message in the original status and any - // additional message that has been streamed into the builder. - enum class MessageJoinStyle { - kAnnotate, - kAppend, - kPrepend, - }; - - // Creates a new status based on an old one by joining the message from the - // original to an additional message. - static absl::Status JoinMessageToStatus(absl::Status s, absl::string_view msg, - MessageJoinStyle style); - - // Creates a Status from this builder and logs it if the builder has been - // configured to log itself. - absl::Status CreateStatusAndConditionallyLog() &&; - - // Conditionally logs if the builder has been configured to log. This method - // is split from the above to isolate the portability issues around logging - // into a single place. - void ConditionallyLog(const absl::Status& status) const; - - // Sets the code of the provided Status (there is no setter for it on - // absl::Status). - static void SetStatusCode(absl::StatusCode canonical_code, - absl::Status* status); - // Copies all payloads of a Status to another Status (there is no helper for - // this in absl::Status). - static void CopyPayloads(const absl::Status& src, absl::Status* dst); - // Returns a Status that is the same as the provided `status` but with the - // message set to `msg`. - static absl::Status WithMessage(const absl::Status& status, - absl::string_view msg); - // Returns a Status that is identical to `s` except that the error_message() - // has been augmented by adding `msg` to the end of the original error - // message. - // - // Annotate should be used to add higher-level information to a Status. E.g., - // - // absl::Status s = GetFileContents(...); - // if (!s.ok()) { - // return Annotate(s, "loading summary statistics data"); - // } - // - // Annotate() adds the appropriate separators, so callers should not include a - // separator in `msg`. The exact formatting is subject to change, so you - // should not depend on it in your tests. - // - // OK status values have no error message and therefore if `s` is OK, the - // result is unchanged. - static absl::Status AnnotateStatus(const absl::Status& s, - absl::string_view msg); - - // Infrequently set builder options, instantiated lazily. This reduces - // average construction/destruction time (e.g. the `stream` is fairly - // expensive). Stacks can also be blown if StatusBuilder grows too large. - // This is primarily an issue for debug builds, which do not necessarily - // re-use stack space within a function across the sub-scopes used by - // status macros. - struct Rep { - explicit Rep() = default; - Rep(const Rep& r); - - enum class LoggingMode { - kDisabled, - kLog, - kVLog, - kLogEveryN, - kLogEveryPeriod - }; - LoggingMode logging_mode = LoggingMode::kDisabled; - - // Corresponds to the levels in `absl::LogSeverity`. - // `logging_mode == LoggingMode::kVLog` always logs at severity INFO. - absl::LogSeverity log_severity; - - // The level at which the Status should be VLOGged. - // Only used when `logging_mode == LoggingMode::kVLog`. - int verbose_level; - - // Only log every N invocations. - // Only used when `logging_mode == LoggingMode::kLogEveryN`. - int n; - - // Only log once per period. - // Only used when `logging_mode == LoggingMode::kLogEveryPeriod`. - absl::Duration period; - - // Gathers additional messages added with `<<` for use in the final status. - std::ostringstream stream; - - // Whether to log stack trace. Only used when `logging_mode != - // LoggingMode::kDisabled`. - bool should_log_stack_trace = false; - - // Specifies how to join the message in `status_` and `stream`. - MessageJoinStyle message_join_style = MessageJoinStyle::kAnnotate; - - // If not nullptr, specifies the log sink where log output should be also - // sent to. Only used when `logging_mode != LoggingMode::kDisabled`. - absl::LogSink* sink = nullptr; - }; - - // The status that the result will be based on. - absl::Status status_; - - // The location to record if this status is logged. - SourceLocation loc_; - - // nullptr if the result status will be OK. Extra fields moved to the heap to - // minimize stack space. - std::unique_ptr rep_; - - private: - // Update this status to include the given source location (if supported by - // Status implementation). - // - // This is only for internal use by the StatusBuilder. - static void AddSourceLocation(absl::Status& status, SourceLocation loc); - // Get the current source-location set for the given status. - // - // This is only for internal use by the StatusBuilder. - static absl::Span GetSourceLocations( - const absl::Status& status); -}; - -// Implicitly converts `builder` to `Status` and write it to `os`. -std::ostream& operator<<(std::ostream& os, const StatusBuilder& builder); -std::ostream& operator<<(std::ostream& os, StatusBuilder&& builder); - -// Each of the functions below creates StatusBuilder with a canonical error. -// The error code of the StatusBuilder matches the name of the function. -StatusBuilder AbortedErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder AlreadyExistsErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder CancelledErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder DataLossErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder DeadlineExceededErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder FailedPreconditionErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder InternalErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder InvalidArgumentErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder NotFoundErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder OutOfRangeErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder PermissionDeniedErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder UnauthenticatedErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder ResourceExhaustedErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder UnavailableErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder UnimplementedErrorBuilder( - SourceLocation location = SourceLocation::current()); -StatusBuilder UnknownErrorBuilder( - SourceLocation location = SourceLocation::current()); - -// Implementation details follow; clients should ignore. - -inline StatusBuilder::StatusBuilder(const absl::Status& original_status, - SourceLocation location) - : status_(original_status), loc_(location) {} - -inline StatusBuilder::StatusBuilder(absl::Status&& original_status, - SourceLocation location) - : status_(std::move(original_status)), loc_(location) {} - -inline StatusBuilder::StatusBuilder(absl::StatusCode code, - SourceLocation location) - : status_(code, ""), loc_(location) {} - -inline StatusBuilder::StatusBuilder(const StatusBuilder& sb) - : status_(sb.status_), loc_(sb.loc_) { - if (sb.rep_ != nullptr) { - rep_ = std::make_unique(*sb.rep_); - } -} - -inline StatusBuilder& StatusBuilder::operator=(const StatusBuilder& sb) { - status_ = sb.status_; - loc_ = sb.loc_; - if (sb.rep_ != nullptr) { - rep_ = std::make_unique(*sb.rep_); - } else { - rep_ = nullptr; - } - return *this; -} - -inline StatusBuilder& StatusBuilder::SetPrepend() & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - - rep_->message_join_style = MessageJoinStyle::kPrepend; - return *this; -} -inline StatusBuilder&& StatusBuilder::SetPrepend() && { - return std::move(SetPrepend()); -} - -inline StatusBuilder& StatusBuilder::SetAppend() & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->message_join_style = MessageJoinStyle::kAppend; - return *this; -} -inline StatusBuilder&& StatusBuilder::SetAppend() && { - return std::move(SetAppend()); -} - -inline StatusBuilder& StatusBuilder::SetNoLogging() & { - if (rep_ != nullptr) { - rep_->logging_mode = Rep::LoggingMode::kDisabled; - rep_->should_log_stack_trace = false; - } - return *this; -} -inline StatusBuilder&& StatusBuilder::SetNoLogging() && { - return std::move(SetNoLogging()); -} - -inline StatusBuilder& StatusBuilder::Log(absl::LogSeverity level) & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->logging_mode = Rep::LoggingMode::kLog; - rep_->log_severity = level; - return *this; -} -inline StatusBuilder&& StatusBuilder::Log(absl::LogSeverity level) && { - return std::move(Log(level)); -} - -inline StatusBuilder& StatusBuilder::LogEveryN(absl::LogSeverity level, - int n) & { - if (status_.ok()) { - return *this; - } - if (n < 1) { - return Log(level); - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->logging_mode = Rep::LoggingMode::kLogEveryN; - rep_->log_severity = level; - rep_->n = n; - return *this; -} -inline StatusBuilder&& StatusBuilder::LogEveryN(absl::LogSeverity level, - int n) && { - return std::move(LogEveryN(level, n)); -} - -inline StatusBuilder& StatusBuilder::LogEvery(absl::LogSeverity level, - absl::Duration period) & { - if (status_.ok()) { - return *this; - } - if (period <= absl::ZeroDuration()) { - return Log(level); - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->logging_mode = Rep::LoggingMode::kLogEveryPeriod; - rep_->log_severity = level; - rep_->period = period; - return *this; -} -inline StatusBuilder&& StatusBuilder::LogEvery(absl::LogSeverity level, - absl::Duration period) && { - return std::move(LogEvery(level, period)); -} - -inline StatusBuilder& StatusBuilder::VLog(int verbose_level) & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->logging_mode = Rep::LoggingMode::kVLog; - rep_->verbose_level = verbose_level; - return *this; -} -inline StatusBuilder&& StatusBuilder::VLog(int verbose_level) && { - return std::move(VLog(verbose_level)); -} - -inline StatusBuilder& StatusBuilder::EmitStackTrace() & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - // Default to INFO logging, otherwise nothing would be emitted. - rep_->logging_mode = Rep::LoggingMode::kLog; - rep_->log_severity = absl::LogSeverity::kInfo; - } - rep_->should_log_stack_trace = true; - return *this; -} -inline StatusBuilder&& StatusBuilder::EmitStackTrace() && { - return std::move(EmitStackTrace()); -} - -inline StatusBuilder& StatusBuilder::AlsoOutputToSink(absl::LogSink* sink) & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->sink = sink; - return *this; -} -inline StatusBuilder&& StatusBuilder::AlsoOutputToSink(absl::LogSink* sink) && { - return std::move(AlsoOutputToSink(sink)); -} - -template -StatusBuilder& StatusBuilder::operator<<(const T& value) & { - if (status_.ok()) { - return *this; - } - if (rep_ == nullptr) { - rep_ = std::make_unique(); - } - rep_->stream << value; - return *this; -} -template -StatusBuilder&& StatusBuilder::operator<<(const T& value) && { - return std::move(operator<<(value)); -} - -inline StatusBuilder& StatusBuilder::SetCode(absl::StatusCode code) & { - SetStatusCode(code, &status_); - return *this; -} -inline StatusBuilder&& StatusBuilder::SetCode(absl::StatusCode code) && { - return std::move(SetCode(code)); -} - -inline bool StatusBuilder::ok() const { return status_.ok(); } - -inline absl::StatusCode StatusBuilder::code() const { return status_.code(); } - -inline StatusBuilder::operator absl::Status() const& { - if (rep_ == nullptr) { - absl::Status result = status_; - StatusBuilder::AddSourceLocation(result, loc_); - return result; - } - return StatusBuilder(*this).CreateStatusAndConditionallyLog(); -} -inline StatusBuilder::operator absl::Status() && { - if (rep_ == nullptr) { - absl::Status result = std::move(status_); - StatusBuilder::AddSourceLocation(result, loc_); - return result; - } - return std::move(*this).CreateStatusAndConditionallyLog(); -} - -inline SourceLocation StatusBuilder::source_location() const { return loc_; } - -} // namespace maldoca - -#endif // MALDOCA_BASE_STATUS_BUILDER_H_ diff --git a/maldoca/base/status_macros.h b/maldoca/base/status_macros.h index cfa91b7..6c0f4e2 100644 --- a/maldoca/base/status_macros.h +++ b/maldoca/base/status_macros.h @@ -19,8 +19,8 @@ #include "absl/base/optimization.h" #include "absl/status/status.h" -#include "maldoca/base/source_location.h" -#include "maldoca/base/status_builder.h" // IWYU pragma: export +#include "absl/status/status_builder.h" // IWYU pragma: export +#include "absl/types/source_location.h" // Evaluates an expression that produces a `absl::Status`. If the status is not // ok, returns it from the current function. @@ -53,11 +53,12 @@ // MALDOCA_RETURN_IF_ERROR(foo.Method(args...)); // return absl::OkStatus(); // } -#define MALDOCA_RETURN_IF_ERROR(expr) \ - MALDOCA_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ - if (::maldoca::status_macro_internal::StatusAdaptorForMacros \ - status_macro_internal_adaptor = {(expr), MALDOCA_LOC}) { \ - } else /* NOLINT */ \ +#define MALDOCA_RETURN_IF_ERROR(expr) \ + MALDOCA_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ + if (::maldoca::status_macro_internal::StatusAdaptorForMacros \ + status_macro_internal_adaptor = {(expr), \ + absl::SourceLocation::current()}) { \ + } else /* NOLINT */ \ return status_macro_internal_adaptor.Consume() // Executes an expression `rexpr` that returns a `StatusOr`. On OK, moves its @@ -149,7 +150,8 @@ error_expression) \ auto statusor = (rexpr); \ if (ABSL_PREDICT_FALSE(!statusor.ok())) { \ - ::maldoca::StatusBuilder _(std::move(statusor).status(), MALDOCA_LOC); \ + absl::StatusBuilder _(std::move(statusor).status(), \ + absl::SourceLocation::current()); \ (void)_; /* error_expression is allowed to not use this variable */ \ return (error_expression); \ } \ @@ -233,16 +235,18 @@ constexpr bool HasPotentialConditionalOperator(const char* lhs, int index) { // that declares a variable. class StatusAdaptorForMacros { public: - StatusAdaptorForMacros(const absl::Status& status, SourceLocation loc) + StatusAdaptorForMacros(const absl::Status& status, absl::SourceLocation loc) : builder_(status, loc) {} - StatusAdaptorForMacros(absl::Status&& status, SourceLocation loc) + StatusAdaptorForMacros(absl::Status&& status, absl::SourceLocation loc) : builder_(std::move(status), loc) {} - StatusAdaptorForMacros(const StatusBuilder& builder, SourceLocation loc) + StatusAdaptorForMacros(const absl::StatusBuilder& builder, + absl::SourceLocation loc) : builder_(builder) {} - StatusAdaptorForMacros(StatusBuilder&& builder, SourceLocation loc) + StatusAdaptorForMacros(absl::StatusBuilder&& builder, + absl::SourceLocation loc) : builder_(std::move(builder)) {} StatusAdaptorForMacros(const StatusAdaptorForMacros&) = delete; @@ -250,10 +254,10 @@ class StatusAdaptorForMacros { explicit operator bool() const { return ABSL_PREDICT_TRUE(builder_.ok()); } - StatusBuilder&& Consume() { return std::move(builder_); } + absl::StatusBuilder&& Consume() { return std::move(builder_); } private: - StatusBuilder builder_; + absl::StatusBuilder builder_; }; } // namespace status_macro_internal diff --git a/maldoca/base/symbolized_stacktrace.cc b/maldoca/base/symbolized_stacktrace.cc deleted file mode 100644 index d6090a7..0000000 --- a/maldoca/base/symbolized_stacktrace.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#include "maldoca/base/symbolized_stacktrace.h" - -#include -#include -#include - -#include "absl/debugging/stacktrace.h" -#include "absl/debugging/symbolize.h" -#include "absl/strings/str_format.h" - -namespace maldoca { - -std::string GetSymbolizedStackTraceAsString(int max_depth, int skip_count, - bool demangle) { - std::string result; - int skip_count_including_self = skip_count + 1; - std::vector stack_trace; - stack_trace.resize(max_depth); - stack_trace.resize(absl::GetStackTrace(stack_trace.data(), max_depth, - skip_count_including_self)); - std::array symbol_name_buffer; - for (void* pc : stack_trace) { - if (absl::Symbolize(pc, symbol_name_buffer.data(), - symbol_name_buffer.size())) { - result += absl::StrFormat("%08p: %s\n", pc, symbol_name_buffer.data()); - } else { - result += absl::StrFormat("%08p: [unknown]\n", pc); - } - } - return result; -} - -} // namespace maldoca diff --git a/maldoca/base/symbolized_stacktrace.h b/maldoca/base/symbolized_stacktrace.h deleted file mode 100644 index aeeaae9..0000000 --- a/maldoca/base/symbolized_stacktrace.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#ifndef MALDOCA_BASE_SYMBOLIZED_STACKTRACE_H_ -#define MALDOCA_BASE_SYMBOLIZED_STACKTRACE_H_ - -#include - -namespace maldoca { - -// Get the symbolized stack trace at most "max_depth" frames, skipping -// innermost "skip_count" frames, as a string. All symbol names will be -// simply connected with "\n". Useful for simple debug output. -// -// Example: -// LOG(INFO) << "@@stacktrace\n" << GetSymbolizedStackTraceAsString(10); -// -std::string GetSymbolizedStackTraceAsString(int max_depth = 50, - int skip_count = 0, - bool demangle = true); - -} // namespace maldoca - -#endif // MALDOCA_BASE_SYMBOLIZED_STACKTRACE_H_ diff --git a/maldoca/base/symbolized_stacktrace_test.cc b/maldoca/base/symbolized_stacktrace_test.cc deleted file mode 100644 index b93b400..0000000 --- a/maldoca/base/symbolized_stacktrace_test.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2025 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 -// -// 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. - -#include "maldoca/base/symbolized_stacktrace.h" - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace maldoca { -namespace { - -using ::testing::HasSubstr; - -#ifndef NDEBUG // Symbols are not available in optimized builds. -TEST(SymbolizedStacktraceTest, StacktraceContainsTestMethodName) { - std::string trace = GetSymbolizedStackTraceAsString(); - - EXPECT_THAT(trace, HasSubstr("StacktraceContainsTestMethodName")); -} - -TEST(SymbolizedStacktraceTest, StacktraceDoesNotContainHelperMethodName) { - std::string trace = GetSymbolizedStackTraceAsString(); - - EXPECT_THAT(trace, Not(HasSubstr("GetSymbolizedStackTraceAsString"))); -} -#endif - -} // namespace -} // namespace maldoca diff --git a/maldoca/base/testing/BUILD b/maldoca/base/testing/BUILD index e7ddaea..2e60fe4 100644 --- a/maldoca/base/testing/BUILD +++ b/maldoca/base/testing/BUILD @@ -49,6 +49,7 @@ cc_library( deps = [ "//maldoca/base:status", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:status_builder", "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@googletest//:gtest", diff --git a/maldoca/base/testing/status_matchers.cc b/maldoca/base/testing/status_matchers.cc index 3308f36..e22d778 100644 --- a/maldoca/base/testing/status_matchers.cc +++ b/maldoca/base/testing/status_matchers.cc @@ -21,8 +21,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/status/status.h" +#include "absl/status/status_builder.h" #include "absl/strings/str_cat.h" -#include "maldoca/base/status_builder.h" namespace maldoca { namespace testing { @@ -100,7 +100,7 @@ bool CanonicalStatusIsMatcherCommonImpl::MatchAndExplain( } void AddFatalFailure(std::string_view expression, - const maldoca::StatusBuilder& builder) { + const absl::StatusBuilder& builder) { GTEST_MESSAGE_AT_( builder.source_location().file_name(), builder.source_location().line(), ::absl::StrCat(expression, diff --git a/maldoca/base/testing/status_matchers.h b/maldoca/base/testing/status_matchers.h index 07f7aa9..ef743f6 100644 --- a/maldoca/base/testing/status_matchers.h +++ b/maldoca/base/testing/status_matchers.h @@ -145,8 +145,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/status/status.h" +#include "absl/status/status_builder.h" #include "absl/status/statusor.h" -#include "maldoca/base/status_builder.h" #include "maldoca/base/status_macros.h" namespace maldoca { @@ -459,7 +459,7 @@ class IsOkMatcher { }; void AddFatalFailure(std::string_view expression, - const maldoca::StatusBuilder& builder); + const absl::StatusBuilder& builder); } // namespace internal_status