| #include "http2/core/http2_trace_logging.h" | 
 |  | 
 | #include <cstdint> | 
 |  | 
 | #include "absl/strings/str_cat.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "common/platform/api/quiche_bug_tracker.h" | 
 | #include "common/platform/api/quiche_logging.h" | 
 | #include "spdy/core/spdy_protocol.h" | 
 |  | 
 | // Convenience macros for printing function arguments in log lines in the | 
 | // format arg_name=value. | 
 | #define FORMAT_ARG(arg) " " #arg "=" << arg | 
 | #define FORMAT_INT_ARG(arg) " " #arg "=" << static_cast<int>(arg) | 
 |  | 
 | // Convenience macros for printing Spdy*IR attributes in log lines in the | 
 | // format attrib_name=value. | 
 | #define FORMAT_ATTR(ir, attrib) " " #attrib "=" << ir.attrib() | 
 | #define FORMAT_INT_ATTR(ir, attrib) \ | 
 |   " " #attrib "=" << static_cast<int>(ir.attrib()) | 
 |  | 
 | namespace { | 
 |  | 
 | // Logs a container, using a user-provided object to log each individual item. | 
 | template <typename T, typename ItemLogger> | 
 | struct ContainerLogger { | 
 |   explicit ContainerLogger(const T& c, ItemLogger l) | 
 |       : container(c), item_logger(l) {} | 
 |  | 
 |   friend std::ostream& operator<<(std::ostream& out, | 
 |                                   const ContainerLogger& logger) { | 
 |     out << "["; | 
 |     auto begin = logger.container.begin(); | 
 |     for (auto it = begin; it != logger.container.end(); ++it) { | 
 |       if (it != begin) { | 
 |         out << ", "; | 
 |       } | 
 |       logger.item_logger.Log(out, *it); | 
 |     } | 
 |     out << "]"; | 
 |     return out; | 
 |   } | 
 |   const T& container; | 
 |   ItemLogger item_logger; | 
 | }; | 
 |  | 
 | // Returns a ContainerLogger that will log |container| using |item_logger|. | 
 | template <typename T, typename ItemLogger> | 
 | auto LogContainer(const T& container, ItemLogger item_logger) | 
 |     -> decltype(ContainerLogger<T, ItemLogger>(container, item_logger)) { | 
 |   return ContainerLogger<T, ItemLogger>(container, item_logger); | 
 | } | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | #define FORMAT_HEADER_BLOCK(ir) \ | 
 |   " header_block=" << LogContainer(ir.header_block(), LogHeaderBlockEntry()) | 
 |  | 
 | namespace http2 { | 
 |  | 
 | using spdy::SettingsMap; | 
 | using spdy::SpdyAltSvcIR; | 
 | using spdy::SpdyContinuationIR; | 
 | using spdy::SpdyDataIR; | 
 | using spdy::SpdyGoAwayIR; | 
 | using spdy::SpdyHeaderBlock; | 
 | using spdy::SpdyHeadersIR; | 
 | using spdy::SpdyPingIR; | 
 | using spdy::SpdyPriorityIR; | 
 | using spdy::SpdyPushPromiseIR; | 
 | using spdy::SpdyRstStreamIR; | 
 | using spdy::SpdySettingsIR; | 
 | using spdy::SpdyStreamId; | 
 | using spdy::SpdyUnknownIR; | 
 | using spdy::SpdyWindowUpdateIR; | 
 |  | 
 | namespace { | 
 |  | 
 | // Defines how elements of SpdyHeaderBlocks are logged. | 
 | struct LogHeaderBlockEntry { | 
 |   void Log(std::ostream& out, | 
 |            const SpdyHeaderBlock::value_type& entry) const {  // NOLINT | 
 |     out << "\"" << entry.first << "\": \"" << entry.second << "\""; | 
 |   } | 
 | }; | 
 |  | 
 | // Defines how elements of SettingsMap are logged. | 
 | struct LogSettingsEntry { | 
 |   void Log(std::ostream& out, | 
 |            const SettingsMap::value_type& entry) const {  // NOLINT | 
 |     out << spdy::SettingsIdToString(entry.first) << ": " << entry.second; | 
 |   } | 
 | }; | 
 |  | 
 | // Defines how elements of AlternativeServiceVector are logged. | 
 | struct LogAlternativeService { | 
 |   void Log(std::ostream& out, | 
 |            const spdy::SpdyAltSvcWireFormat::AlternativeService& altsvc) | 
 |       const {  // NOLINT | 
 |     out << "{" | 
 |         << "protocol_id=" << altsvc.protocol_id << " host=" << altsvc.host | 
 |         << " port=" << altsvc.port | 
 |         << " max_age_seconds=" << altsvc.max_age_seconds << " version="; | 
 |     for (auto v : altsvc.version) { | 
 |       out << v << ","; | 
 |     } | 
 |     out << "}"; | 
 |   } | 
 | }; | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | Http2TraceLogger::Http2TraceLogger(SpdyFramerVisitorInterface* parent, | 
 |                                    absl::string_view perspective, | 
 |                                    std::function<bool()> is_enabled, | 
 |                                    const void* connection_id) | 
 |     : wrapped_(parent), | 
 |       perspective_(perspective), | 
 |       is_enabled_(std::move(is_enabled)), | 
 |       connection_id_(connection_id) {} | 
 |  | 
 | Http2TraceLogger::~Http2TraceLogger() { | 
 |   if (recording_headers_handler_ != nullptr && | 
 |       !recording_headers_handler_->decoded_block().empty()) { | 
 |     HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |         << "connection_id=" << connection_id_ | 
 |         << " Received headers that were never logged! keys/values:" | 
 |         << recording_headers_handler_->decoded_block().DebugString(); | 
 |   } | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnError(Http2DecoderAdapter::SpdyFramerError error, | 
 |                                std::string detailed_error) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnError:" << FORMAT_ARG(connection_id_) | 
 |       << ", error=" << Http2DecoderAdapter::SpdyFramerErrorToString(error); | 
 |   wrapped_->OnError(error, detailed_error); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnCommonHeader(SpdyStreamId stream_id, size_t length, | 
 |                                       uint8_t type, uint8_t flags) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnCommonHeader:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(length) << FORMAT_INT_ARG(type) | 
 |       << FORMAT_INT_ARG(flags); | 
 |   wrapped_->OnCommonHeader(stream_id, length, type, flags); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnDataFrameHeader(SpdyStreamId stream_id, size_t length, | 
 |                                         bool fin) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnDataFrameHeader:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(length) << FORMAT_ARG(fin); | 
 |   wrapped_->OnDataFrameHeader(stream_id, length, fin); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnStreamFrameData(SpdyStreamId stream_id, | 
 |                                         const char* data, size_t len) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnStreamFrameData:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(len); | 
 |   wrapped_->OnStreamFrameData(stream_id, data, len); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnStreamEnd(SpdyStreamId stream_id) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnStreamEnd:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id); | 
 |   wrapped_->OnStreamEnd(stream_id); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnStreamPadLength(SpdyStreamId stream_id, size_t value) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnStreamPadLength:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(value); | 
 |   wrapped_->OnStreamPadLength(stream_id, value); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnStreamPadding(SpdyStreamId stream_id, size_t len) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnStreamPadding:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(len); | 
 |   wrapped_->OnStreamPadding(stream_id, len); | 
 | } | 
 |  | 
 | spdy::SpdyHeadersHandlerInterface* Http2TraceLogger::OnHeaderFrameStart( | 
 |     SpdyStreamId stream_id) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnHeaderFrameStart:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id); | 
 |   spdy::SpdyHeadersHandlerInterface* result = | 
 |       wrapped_->OnHeaderFrameStart(stream_id); | 
 |   recording_headers_handler_ = | 
 |       absl::make_unique<spdy::RecordingHeadersHandler>(result); | 
 |   result = recording_headers_handler_.get(); | 
 |   return result; | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnHeaderFrameEnd(SpdyStreamId stream_id) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnHeaderFrameEnd:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id); | 
 |   LogReceivedHeaders(); | 
 |   wrapped_->OnHeaderFrameEnd(stream_id); | 
 |   recording_headers_handler_ = nullptr; | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnRstStream(SpdyStreamId stream_id, | 
 |                                   SpdyErrorCode error_code) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnRstStream:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id) | 
 |       << " error_code=" << spdy::ErrorCodeToString(error_code); | 
 |   wrapped_->OnRstStream(stream_id, error_code); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnSettings() { wrapped_->OnSettings(); } | 
 |  | 
 | void Http2TraceLogger::OnSetting(SpdySettingsId id, uint32_t value) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnSetting:" << FORMAT_ARG(connection_id_) | 
 |       << " id=" << spdy::SettingsIdToString(id) << FORMAT_ARG(value); | 
 |   wrapped_->OnSetting(id, value); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnSettingsEnd() { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnSettingsEnd:" << FORMAT_ARG(connection_id_); | 
 |   wrapped_->OnSettingsEnd(); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnSettingsAck() { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnSettingsAck:" << FORMAT_ARG(connection_id_); | 
 |   wrapped_->OnSettingsAck(); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnPing(SpdyPingId unique_id, bool is_ack) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnPing:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(unique_id) | 
 |       << FORMAT_ARG(is_ack); | 
 |   wrapped_->OnPing(unique_id, is_ack); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnGoAway(SpdyStreamId last_accepted_stream_id, | 
 |                                SpdyErrorCode error_code) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnGoAway:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(last_accepted_stream_id) | 
 |       << " error_code=" << spdy::ErrorCodeToString(error_code); | 
 |   wrapped_->OnGoAway(last_accepted_stream_id, error_code); | 
 | } | 
 |  | 
 | bool Http2TraceLogger::OnGoAwayFrameData(const char* goaway_data, size_t len) { | 
 |   return wrapped_->OnGoAwayFrameData(goaway_data, len); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnHeaders(SpdyStreamId stream_id, bool has_priority, | 
 |                                 int weight, SpdyStreamId parent_stream_id, | 
 |                                 bool exclusive, bool fin, bool end) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnHeaders:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id) | 
 |       << FORMAT_ARG(has_priority) << FORMAT_INT_ARG(weight) | 
 |       << FORMAT_ARG(parent_stream_id) << FORMAT_ARG(exclusive) | 
 |       << FORMAT_ARG(fin) << FORMAT_ARG(end); | 
 |   wrapped_->OnHeaders(stream_id, has_priority, weight, parent_stream_id, | 
 |                       exclusive, fin, end); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnWindowUpdate(SpdyStreamId stream_id, | 
 |                                      int delta_window_size) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnWindowUpdate:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(delta_window_size); | 
 |   wrapped_->OnWindowUpdate(stream_id, delta_window_size); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnPushPromise(SpdyStreamId original_stream_id, | 
 |                                     SpdyStreamId promised_stream_id, bool end) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnPushPromise:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(original_stream_id) << FORMAT_ARG(promised_stream_id) | 
 |       << FORMAT_ARG(end); | 
 |   wrapped_->OnPushPromise(original_stream_id, promised_stream_id, end); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnContinuation(SpdyStreamId stream_id, bool end) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnContinuation:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_ARG(end); | 
 |   wrapped_->OnContinuation(stream_id, end); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnAltSvc( | 
 |     SpdyStreamId stream_id, absl::string_view origin, | 
 |     const SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnAltSvc:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id) | 
 |       << FORMAT_ARG(origin) << " altsvc_vector=" | 
 |       << LogContainer(altsvc_vector, LogAlternativeService()); | 
 |   wrapped_->OnAltSvc(stream_id, origin, altsvc_vector); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnPriority(SpdyStreamId stream_id, | 
 |                                  SpdyStreamId parent_stream_id, int weight, | 
 |                                  bool exclusive) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnPriority:" << FORMAT_ARG(connection_id_) << FORMAT_ARG(stream_id) | 
 |       << FORMAT_ARG(parent_stream_id) << FORMAT_INT_ARG(weight) | 
 |       << FORMAT_ARG(exclusive); | 
 |   wrapped_->OnPriority(stream_id, parent_stream_id, weight, exclusive); | 
 | } | 
 |  | 
 | void Http2TraceLogger::OnPriorityUpdate( | 
 |     SpdyStreamId prioritized_stream_id, | 
 |     absl::string_view priority_field_value) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnPriorityUpdate:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(prioritized_stream_id) << FORMAT_ARG(priority_field_value); | 
 |   wrapped_->OnPriorityUpdate(prioritized_stream_id, priority_field_value); | 
 | } | 
 |  | 
 | bool Http2TraceLogger::OnUnknownFrame(SpdyStreamId stream_id, | 
 |                                      uint8_t frame_type) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "OnUnknownFrame:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ARG(stream_id) << FORMAT_INT_ARG(frame_type); | 
 |   return wrapped_->OnUnknownFrame(stream_id, frame_type); | 
 | } | 
 |  | 
 | void Http2TraceLogger::LogReceivedHeaders() const { | 
 |   if (recording_headers_handler_ == nullptr) { | 
 |     QUICHE_BUG(bug_2794_1) << "Cannot log headers before creating handler."; | 
 |     return; | 
 |   } | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Received headers;" << FORMAT_ARG(connection_id_) << " keys/values:" | 
 |       << recording_headers_handler_->decoded_block().DebugString() | 
 |       << " compressed_bytes=" | 
 |       << recording_headers_handler_->compressed_header_bytes() | 
 |       << " uncompressed_bytes=" | 
 |       << recording_headers_handler_->uncompressed_header_bytes(); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitRstStream(const SpdyRstStreamIR& rst_stream) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyRstStreamIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(rst_stream, stream_id) | 
 |       << " error_code=" << spdy::ErrorCodeToString(rst_stream.error_code()); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitSettings(const SpdySettingsIR& settings) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdySettingsIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(settings, is_ack) | 
 |       << " values=" << LogContainer(settings.values(), LogSettingsEntry()); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitPing(const SpdyPingIR& ping) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyPingIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(ping, id) << FORMAT_ATTR(ping, is_ack); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitGoAway(const SpdyGoAwayIR& goaway) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyGoAwayIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(goaway, last_good_stream_id) | 
 |       << " error_code=" << spdy::ErrorCodeToString(goaway.error_code()) | 
 |       << FORMAT_ATTR(goaway, description); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitHeaders(const SpdyHeadersIR& headers) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyHeadersIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(headers, stream_id) << FORMAT_ATTR(headers, fin) | 
 |       << FORMAT_ATTR(headers, has_priority) << FORMAT_INT_ATTR(headers, weight) | 
 |       << FORMAT_ATTR(headers, parent_stream_id) | 
 |       << FORMAT_ATTR(headers, exclusive) << FORMAT_ATTR(headers, padded) | 
 |       << FORMAT_ATTR(headers, padding_payload_len) | 
 |       << FORMAT_HEADER_BLOCK(headers); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitWindowUpdate( | 
 |     const SpdyWindowUpdateIR& window_update) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyWindowUpdateIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(window_update, stream_id) | 
 |       << FORMAT_ATTR(window_update, delta); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitPushPromise(const SpdyPushPromiseIR& push_promise) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyPushPromiseIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(push_promise, stream_id) << FORMAT_ATTR(push_promise, fin) | 
 |       << FORMAT_ATTR(push_promise, promised_stream_id) | 
 |       << FORMAT_ATTR(push_promise, padded) | 
 |       << FORMAT_ATTR(push_promise, padding_payload_len) | 
 |       << FORMAT_HEADER_BLOCK(push_promise); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitContinuation( | 
 |     const SpdyContinuationIR& continuation) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyContinuationIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(continuation, stream_id) | 
 |       << FORMAT_ATTR(continuation, end_headers); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitAltSvc(const SpdyAltSvcIR& altsvc) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyAltSvcIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(altsvc, stream_id) << FORMAT_ATTR(altsvc, origin) | 
 |       << " altsvc_vector=" | 
 |       << LogContainer(altsvc.altsvc_vector(), LogAlternativeService()); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitPriority(const SpdyPriorityIR& priority) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyPriorityIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(priority, stream_id) | 
 |       << FORMAT_ATTR(priority, parent_stream_id) | 
 |       << FORMAT_INT_ATTR(priority, weight) << FORMAT_ATTR(priority, exclusive); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitData(const SpdyDataIR& data) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyDataIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(data, stream_id) << FORMAT_ATTR(data, fin) | 
 |       << " data_len=" << data.data_len() << FORMAT_ATTR(data, padded) | 
 |       << FORMAT_ATTR(data, padding_payload_len); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitPriorityUpdate( | 
 |     const spdy::SpdyPriorityUpdateIR& priority_update) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyPriorityUpdateIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(priority_update, stream_id) | 
 |       << FORMAT_ATTR(priority_update, prioritized_stream_id) | 
 |       << FORMAT_ATTR(priority_update, priority_field_value); | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitAcceptCh( | 
 |     const spdy::SpdyAcceptChIR& /*accept_ch*/) { | 
 |   QUICHE_BUG(bug_2794_2) | 
 |       << "Sending ACCEPT_CH frames is currently unimplemented."; | 
 | } | 
 |  | 
 | void Http2FrameLogger::VisitUnknown(const SpdyUnknownIR& ir) { | 
 |   HTTP2_TRACE_LOG(perspective_, is_enabled_) | 
 |       << "Wrote SpdyUnknownIR:" << FORMAT_ARG(connection_id_) | 
 |       << FORMAT_ATTR(ir, stream_id) << FORMAT_INT_ATTR(ir, type) | 
 |       << FORMAT_INT_ATTR(ir, flags) << FORMAT_ATTR(ir, length); | 
 | } | 
 |  | 
 | }  // namespace http2 |