| // Copyright 2023 Google Inc. 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 "logger.h" |
| |
| #include "util.h" |
| |
| namespace { |
| |
| struct StdioBackend : public Logger::Backend { |
| StdioBackend(FILE* stream) : stream_(stream) {} |
| |
| bool Log(StringPiece message) override { |
| fwrite(message.str_, message.len_, 1, stream_); |
| fputc('\n', stream_); |
| return true; |
| } |
| bool Log(const char* fmt, va_list args) override { |
| vfprintf(stream_, fmt, args); |
| fputc('\n', stream_); |
| return true; |
| } |
| FILE* stream_; |
| }; |
| |
| struct StdOstreamBackend : public Logger::Backend { |
| StdOstreamBackend(std::ostream& out) : out_(out) {} |
| bool Log(StringPiece str) override { |
| out_.write(str.str_, static_cast<std::streamsize>(str.len_)); |
| out_.put('\n'); |
| return true; |
| } |
| std::ostream& out_; |
| }; |
| |
| struct StringBackend : public Logger::Backend { |
| StringBackend(std::string& out) : out_(out) {} |
| bool Log(StringPiece str) override { |
| out_.append(str.str_, str.len_); |
| out_.push_back('\n'); |
| return true; |
| } |
| bool Log(const char* fmt, va_list args) override { |
| StringAppendFormat(out_, fmt, args); |
| out_.push_back('\n'); |
| return true; |
| } |
| std::string& out_; |
| }; |
| |
| struct ProxyBackend : public Logger::Backend { |
| ProxyBackend(const Logger& logger) : logger_(logger) {} |
| bool Log(StringPiece str) override { return logger_.Log(str); } |
| bool Log(const char* fmt, va_list args) override { |
| return logger_.Logv(fmt, args); |
| } |
| bool enabled() const override { return logger_.enabled(); } |
| const Logger& logger_; |
| }; |
| |
| struct TeeBackend : public Logger::Backend { |
| TeeBackend(const Logger& a, const Logger& b) : a_(a), b_(b) {} |
| |
| bool enabled() const override { return a_.enabled() || b_.enabled(); } |
| |
| bool Log(StringPiece str) override { |
| bool result_a = a_.Log(str); |
| bool result_b = b_.Log(str); |
| return result_a || result_b; |
| } |
| |
| const Logger& a_; |
| const Logger& b_; |
| }; |
| |
| } // namespace |
| |
| // Default Logger::Backend::Log implementation uses StringFormat() |
| // which creates a temporary string. Derived classes may want to |
| // override this for better performance. |
| bool Logger::Backend::Log(const char* fmt, va_list args) { |
| std::string message = StringFormat(fmt, args); |
| return this->Log(StringPiece(message)); |
| } |
| |
| bool Logger::enabled() const { |
| if (!backend_) |
| return false; |
| return backend_->enabled(); |
| } |
| |
| bool Logger::Log(const char* fmt, ...) const { |
| if (!backend_) |
| return false; |
| |
| va_list args; |
| va_start(args, fmt); |
| bool result = backend_->Log(fmt, args); |
| va_end(args); |
| return result; |
| } |
| |
| bool Logger::Log(StringPiece message) const { |
| if (!backend_) |
| return false; |
| |
| return backend_->Log(message); |
| } |
| |
| bool Logger::Logv(const char* fmt, va_list args) const { |
| if (!backend_) |
| return false; |
| return backend_->Log(fmt, args); |
| } |
| |
| // static |
| Logger Logger::CreateForStdio(FILE* stream) { |
| return Logger(new StdioBackend(stream)); |
| } |
| |
| // static |
| Logger Logger::CreateForStd(std::ostream& out) { |
| return Logger(new StdOstreamBackend(out)); |
| } |
| |
| // static |
| Logger Logger::CreateForString(std::string* messages) { |
| return Logger(new StringBackend(*messages)); |
| } |
| |
| // static |
| Logger Logger::CreateProxyFor(const Logger& logger) { |
| return Logger(new ProxyBackend(logger)); |
| } |
| |
| // static |
| Logger Logger::CreateTeeFor(const Logger& logger_a, const Logger& logger_b) { |
| return Logger(new TeeBackend(logger_a, logger_b)); |
| } |
| |
| // static |
| Logger Logger::CreateForBackend(std::unique_ptr<Backend> backend) { |
| return Logger(std::move(backend)); |
| } |