Line data Source code
1 : #pragma once 2 : 3 : #include <fstream> 4 : 5 : #include "envoy/buffer/buffer.h" 6 : #include "envoy/config/tap/v3/common.pb.h" 7 : #include "envoy/data/tap/v3/common.pb.h" 8 : #include "envoy/data/tap/v3/wrapper.pb.h" 9 : 10 : #include "source/extensions/common/matcher/matcher.h" 11 : #include "source/extensions/common/tap/tap.h" 12 : 13 : namespace Envoy { 14 : namespace Extensions { 15 : namespace Common { 16 : namespace Tap { 17 : 18 : using Matcher = Envoy::Extensions::Common::Matcher::Matcher; 19 : using MatcherPtr = Envoy::Extensions::Common::Matcher::MatcherPtr; 20 : 21 : /** 22 : * Common utilities for tapping. 23 : */ 24 : class Utility { 25 : public: 26 : /** 27 : * Add body data to a tapped body message, taking into account the maximum bytes to buffer. 28 : * @param output_body supplies the body message to buffer to. 29 : * @param max_buffered_bytes supplies the maximum bytes to store, if truncation occurs the 30 : * truncation flag will be set. 31 : * @param data supplies the data to buffer. 32 : * @param buffer_start_offset supplies the offset within data to start buffering. 33 : * @param buffer_length_to_copy supplies the length of the data to buffer. 34 : * @return whether the buffered data was truncated or not. 35 : */ 36 : static bool addBufferToProtoBytes(envoy::data::tap::v3::Body& output_body, 37 : uint32_t max_buffered_bytes, const Buffer::Instance& data, 38 : uint32_t buffer_start_offset, uint32_t buffer_length_to_copy); 39 : 40 : /** 41 : * Swap body as bytes to body as string if necessary in a trace wrapper. 42 : */ 43 : static void bodyBytesToString(envoy::data::tap::v3::TraceWrapper& trace, 44 : envoy::config::tap::v3::OutputSink::Format sink_format); 45 : 46 : /** 47 : * Trim a container that contains buffer raw slices so that the slices start at an offset and 48 : * only contain a specific length. No slices are removed from the container, but their length 49 : * may be reduced to 0. 50 : * TODO(mattklein123): This is split out to ease testing and also because we should ultimately 51 : * move this directly into the buffer API. I would rather wait until the new buffer code merges 52 : * before we do that. 53 : */ 54 0 : template <typename T> static void trimSlices(T& slices, uint32_t start_offset, uint32_t length) { 55 0 : for (auto& slice : slices) { 56 0 : const uint32_t start_offset_trim = std::min<uint32_t>(start_offset, slice.len_); 57 0 : slice.len_ -= start_offset_trim; 58 0 : start_offset -= start_offset_trim; 59 0 : if (slice.mem_ != nullptr) { 60 0 : slice.mem_ = static_cast<char*>(slice.mem_) + start_offset_trim; 61 0 : } 62 : 63 0 : const uint32_t final_length = std::min<uint32_t>(length, slice.len_); 64 0 : slice.len_ = final_length; 65 0 : length -= final_length; 66 0 : } 67 0 : } 68 : }; 69 : 70 : /** 71 : * Base class for all tap configurations. 72 : * TODO(mattklein123): This class will handle common functionality such as rate limiting, etc. 73 : */ 74 : class TapConfigBaseImpl : public virtual TapConfig { 75 : public: 76 : // A wrapper for a per tap sink handle and trace submission. If in the future we support 77 : // multiple sinks we can easily do it here. 78 : class PerTapSinkHandleManagerImpl : public PerTapSinkHandleManager { 79 : public: 80 : PerTapSinkHandleManagerImpl(TapConfigBaseImpl& parent, uint64_t trace_id) 81 : : parent_(parent), 82 0 : handle_(parent.sink_to_use_->createPerTapSinkHandle(trace_id, parent.sink_type_)) {} 83 : 84 : // PerTapSinkHandleManager 85 : void submitTrace(TraceWrapperPtr&& trace) override; 86 : 87 : private: 88 : TapConfigBaseImpl& parent_; 89 : PerTapSinkHandlePtr handle_; 90 : }; 91 : 92 : // TapConfig 93 0 : PerTapSinkHandleManagerPtr createPerTapSinkHandleManager(uint64_t trace_id) override { 94 0 : return std::make_unique<PerTapSinkHandleManagerImpl>(*this, trace_id); 95 0 : } 96 0 : uint32_t maxBufferedRxBytes() const override { return max_buffered_rx_bytes_; } 97 0 : uint32_t maxBufferedTxBytes() const override { return max_buffered_tx_bytes_; } 98 0 : Matcher::MatchStatusVector createMatchStatusVector() const override { 99 0 : return Matcher::MatchStatusVector(matchers_.size()); 100 0 : } 101 : const Matcher& rootMatcher() const override; 102 0 : bool streaming() const override { return streaming_; } 103 : 104 : protected: 105 : TapConfigBaseImpl(const envoy::config::tap::v3::TapConfig& proto_config, 106 : Common::Tap::Sink* admin_streamer, SinkContext context); 107 : 108 : private: 109 : // This is the default setting for both RX/TX max buffered bytes. (This means that per tap, the 110 : // maximum amount that can be buffered is 2x this value). 111 : static constexpr uint32_t DefaultMaxBufferedBytes = 1024; 112 : 113 : const uint32_t max_buffered_rx_bytes_; 114 : const uint32_t max_buffered_tx_bytes_; 115 : const bool streaming_; 116 : Sink* sink_to_use_; 117 : SinkPtr sink_; 118 : envoy::config::tap::v3::OutputSink::Format sink_format_; 119 : envoy::config::tap::v3::OutputSink::OutputSinkTypeCase sink_type_; 120 : std::vector<MatcherPtr> matchers_; 121 : }; 122 : 123 : /** 124 : * A tap sink that writes each tap trace to a discrete output file. 125 : */ 126 : class FilePerTapSink : public Sink { 127 : public: 128 0 : FilePerTapSink(const envoy::config::tap::v3::FilePerTapSink& config) : config_(config) {} 129 : 130 : // Sink 131 : PerTapSinkHandlePtr 132 : createPerTapSinkHandle(uint64_t trace_id, 133 0 : envoy::config::tap::v3::OutputSink::OutputSinkTypeCase) override { 134 0 : return std::make_unique<FilePerTapSinkHandle>(*this, trace_id); 135 0 : } 136 : 137 : private: 138 : struct FilePerTapSinkHandle : public PerTapSinkHandle { 139 : FilePerTapSinkHandle(FilePerTapSink& parent, uint64_t trace_id) 140 0 : : parent_(parent), trace_id_(trace_id) {} 141 : 142 : // PerTapSinkHandle 143 : void submitTrace(TraceWrapperPtr&& trace, 144 : envoy::config::tap::v3::OutputSink::Format format) override; 145 : 146 : FilePerTapSink& parent_; 147 : const uint64_t trace_id_; 148 : std::ofstream output_file_; 149 : }; 150 : 151 : const envoy::config::tap::v3::FilePerTapSink config_; 152 : }; 153 : 154 : } // namespace Tap 155 : } // namespace Common 156 : } // namespace Extensions 157 : } // namespace Envoy