chromium/components/autofill/core/common/logging/log_buffer.h

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_

#include <concepts>
#include <string>
#include <string_view>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/types/strong_alias.h"
#include "base/values.h"
#include "components/autofill/core/common/logging/log_macros.h"
#include "url/gurl.h"

// The desired pattern to generate log messages is to pass a scope, a log
// message and then parameters.
//
// LogBuffer() << LoggingScope::kSomeScope << LogMessage::kSomeLogMessage
//     << Br{} << more << Br{} << parameters;
//
// Extra parameters can be:
//
// - numeric:
//   LogBuffer() << ... << 42;
//
// - inline strings:
//   LogBuffer() << ... << "foobar";
//
// - tags:
//   LogBuffer() << Tag{"div"} << ... << CTag{};
//   Note that tags need to be closed (even for <br> - use Br{} as it takes care
//   of generating an opening and closing tag). You may optionally specify what
//   tag is closed: CTag{"div"}.
//   Tags can get attributes via Attrib:
//   LogBuffer() << Tag{"div"} << Attrib{"class", "foobar"}... << CTag{};
//
// - objects that can have an overloaded operator:
//   LogBuffer& operator<<(LogBuffer& buf,
//                                       const SampleObject& value) {...}
//   LogBuffer() << ... << my_sample_object;
//
// - complex messages that require for loops:
//   LogBuffer buffer;
//   for (...) { buffer << something; }
//   LogBuffer() << std::move(buffer);
//
// In practice the LogBuffer requires a boolean parameter indicating whether
// logging should happen. You should rely on
// components/autofill/core/common/logging/log_macros.h and follow one of the
// following patterns:
//
// (1) void MyFunction(LogManager* log_manager) {
//       LOG_AF(log_mannager) << "foobar";
//     }
// (2) void MyFunction(LogManager* log_manager) {
//       LogBuffer buffer(
//          /*active=*/ log_manager && log_manager->IsLoggingActive());
//       LOG_AF(buffer) << "foobar";
//       LOG_AF(log_manager) << std::move(buffer);
//     }

namespace autofill {

// Tag of HTML Element (e.g. <div> would be represented by Tag{"div"}). Note
// that every element needs to be closed with a CTag{}.
struct Tag {};

// The closing tag of an HTML Element.
struct CTag {};

// Attribute of an HTML Tag (e.g. class="foo" would be represented by
// Attrib{"class", "foo"}.
struct Attrib {};

// Sets a html data attribute specificifying that the parent tab contains PII.
// Used so that it can be potentially stripped.
struct SetParentTagContainsPII {};

// An <br> HTML tag, note that this does not need to be closed.
struct Br {};

// A table row tag. This is syntactic sugar for logging data into a table.
// See LogTableRowBuffer below.
struct Tr {};

class LogManager;

// A buffer into which you can stream values. See the top of this header file
// for samples.
class LogBuffer {};

// Enable streaming numbers of all types.
template <typename T>
  requires(std::integral<T> || std::floating_point<T>)
LogBuffer& operator<<(LogBuffer& buf, T number) {}

LogBuffer& operator<<(LogBuffer& buf, Tag&& tag);

LogBuffer& operator<<(LogBuffer& buf, CTag&& tag);

LogBuffer& operator<<(LogBuffer& buf, Attrib&& attrib);

LogBuffer& operator<<(LogBuffer& buf, Br&& tag);

LogBuffer& operator<<(LogBuffer& buf, std::string_view text);

LogBuffer& operator<<(LogBuffer& buf, std::u16string_view text);

// Sometimes you may want to fill a buffer that you then stream as a whole
// to LOG_AF_INTERNALS, which commits the data to chrome://autofill-internals:
//
//   LogBuffer buffer;
//   for (FormStructure* form : forms)
//     buffer << *form;
//   LogBuffer() << LoggingScope::kParsing << std::move(buffer);
//
// It would not be possible to report all |forms| into a single log entry
// without this.
LogBuffer& operator<<(LogBuffer& buf, LogBuffer&& buffer);

// Streams only the security origin of the URL. This is done for privacy
// reasons.
LogBuffer& operator<<(LogBuffer& buf, const GURL& url);

template <typename T>
LogBuffer& operator<<(LogBuffer& buf, const std::vector<T>& values) {}

// This is syntactic sugar for creating table rows in a LogBuffer. Each
// value streamed into this LogTableRowBuffer is wrapped by a <td> element.
// The entire row is wrapped by a <tr>.
//
// Here is an example:
//   LogBuffer buf;
//   buf << Tr{} << Attrib{"style", "color: red"} << "Foo" << "Bar";
// This creates:
//   <tr style="color: red"><td>Foo</td><td>Bar</td></tr>.
class LogTableRowBuffer {};

LogTableRowBuffer operator<<(LogBuffer& buf, Tr&& tr);

template <typename T>
LogTableRowBuffer&& operator<<(LogTableRowBuffer&& buf, T&& value) {}

LogTableRowBuffer&& operator<<(LogTableRowBuffer&& buf, Attrib&& attrib);

// Highlights the first |needle| in |haystack| by wrapping it in <b> tags.
LogBuffer HighlightValue(std::string_view haystack, std::string_view needle);
LogBuffer HighlightValue(std::u16string_view haystack,
                         std::u16string_view needle);

namespace internal {

// Traits for LOG_AF() macro for `LogBuffer*`.
LoggerTraits<T>;

// Traits for LOG_AF() macro for `LogBuffer&`.
LoggerTraits<T>;

}  // namespace internal

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_COMMON_LOGGING_LOG_BUFFER_H_