• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
12 #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
13 
14 #include <string>
15 #include <vector>
16 
17 #include "absl/strings/string_view.h"
18 #include "logging/rtc_event_log/events/rtc_event_field_encoding.h"
19 
20 // TODO(terelius): Compared to a generic 'Status' class, this
21 // class allows us additional information about the context
22 // in which the error occurred. This is currently limited to
23 // the source location (file and line), but we plan on adding
24 // information about the event and field name being parsed.
25 // If/when we start using absl::Status in WebRTC, consider
26 // whether payloads would be an appropriate alternative.
27 class RtcEventLogParseStatus {
28   template <typename T>
29   friend class RtcEventLogParseStatusOr;
30 
31  public:
Success()32   static RtcEventLogParseStatus Success() { return RtcEventLogParseStatus(); }
Error(absl::string_view error,absl::string_view file,int line)33   static RtcEventLogParseStatus Error(absl::string_view error,
34                                       absl::string_view file,
35                                       int line) {
36     return RtcEventLogParseStatus(error, file, line);
37   }
38 
ok()39   bool ok() const { return error_.empty(); }
40   ABSL_DEPRECATED("Use ok() instead") explicit operator bool() const {
41     return ok();
42   }
43 
message()44   std::string message() const { return error_; }
45 
46  private:
RtcEventLogParseStatus()47   RtcEventLogParseStatus() : error_() {}
RtcEventLogParseStatus(absl::string_view error,absl::string_view file,int line)48   RtcEventLogParseStatus(absl::string_view error,
49                          absl::string_view file,
50                          int line)
51       : error_(std::string(error) + " (" + std::string(file) + ": " +
52                std::to_string(line) + ")") {}
53 
54   std::string error_;
55 };
56 
57 template <typename T>
58 class RtcEventLogParseStatusOr {
59  public:
RtcEventLogParseStatusOr(RtcEventLogParseStatus status)60   RtcEventLogParseStatusOr(RtcEventLogParseStatus status)  // NOLINT
61       : status_(status), value_() {}
RtcEventLogParseStatusOr(const T & value)62   RtcEventLogParseStatusOr(const T& value)  // NOLINT
63       : status_(), value_(value) {}
64 
ok()65   bool ok() const { return status_.ok(); }
66 
message()67   std::string message() const { return status_.message(); }
68 
status()69   RtcEventLogParseStatus status() const { return status_; }
70 
value()71   const T& value() const {
72     RTC_DCHECK(ok());
73     return value_;
74   }
75 
value()76   T& value() {
77     RTC_DCHECK(ok());
78     return value_;
79   }
80 
Error(absl::string_view error,absl::string_view file,int line)81   static RtcEventLogParseStatusOr Error(absl::string_view error,
82                                         absl::string_view file,
83                                         int line) {
84     return RtcEventLogParseStatusOr(error, file, line);
85   }
86 
87  private:
RtcEventLogParseStatusOr()88   RtcEventLogParseStatusOr() : status_() {}
RtcEventLogParseStatusOr(absl::string_view error,absl::string_view file,int line)89   RtcEventLogParseStatusOr(absl::string_view error,
90                            absl::string_view file,
91                            int line)
92       : status_(error, file, line), value_() {}
93 
94   RtcEventLogParseStatus status_;
95   T value_;
96 };
97 
98 namespace webrtc {
99 
100 class EventParser {
101  public:
102   struct ValueAndPostionView {
103     rtc::ArrayView<uint64_t> values;
104     rtc::ArrayView<uint8_t> positions;
105   };
106 
107   EventParser() = default;
108 
109   // N.B: This method stores a abls::string_view into the string to be
110   // parsed. The caller is responsible for ensuring that the actual string
111   // remains unmodified and outlives the EventParser.
112   RtcEventLogParseStatus Initialize(absl::string_view s, bool batched);
113 
114   // Attempts to parse the field specified by `params`, skipping past
115   // other fields that may occur before it. If 'required_field == true',
116   // then failing to find the field is an error, otherwise the functions
117   // return success, but with an empty view of values.
118   RtcEventLogParseStatusOr<rtc::ArrayView<absl::string_view>> ParseStringField(
119       const FieldParameters& params,
120       bool required_field = true);
121   RtcEventLogParseStatusOr<rtc::ArrayView<uint64_t>> ParseNumericField(
122       const FieldParameters& params,
123       bool required_field = true);
124   RtcEventLogParseStatusOr<ValueAndPostionView> ParseOptionalNumericField(
125       const FieldParameters& params,
126       bool required_field = true);
127 
128   // Number of events in a batch.
NumEventsInBatch()129   uint64_t NumEventsInBatch() const { return num_events_; }
130 
131   // Bytes remaining in `pending_data_`. Assuming there are no unknown
132   // fields, BytesRemaining() should return 0 when all known fields
133   // in the event have been parsed.
RemainingBytes()134   size_t RemainingBytes() const { return pending_data_.size(); }
135 
136  private:
137   uint64_t ReadLittleEndian(uint8_t bytes);
138   uint64_t ReadVarInt();
139   uint64_t ReadSingleValue(FieldType field_type);
140   uint64_t ReadOptionalValuePositions();
141   void ReadDeltasAndPopulateValues(FixedLengthEncodingParametersV3 params,
142                                    uint64_t num_deltas,
143                                    uint64_t base);
144   RtcEventLogParseStatus ParseNumericFieldInternal(uint64_t value_bit_width,
145                                                    FieldType field_type);
146   RtcEventLogParseStatus ParseStringFieldInternal();
147 
148   // Attempts to parse the field specified by `params`, skipping past
149   // other fields that may occur before it. Returns
150   // RtcEventLogParseStatus::Success() and populates `values_` (and
151   // `positions_`) if the field is found. Returns
152   // RtcEventLogParseStatus::Success() and clears `values_` (and `positions_`)
153   // if the field doesn't exist. Returns a RtcEventLogParseStatus::Error() if
154   // the log is incomplete, malformed or otherwise can't be parsed.
155   RtcEventLogParseStatus ParseField(const FieldParameters& params);
156 
SetError()157   void SetError() { error_ = true; }
Ok()158   bool Ok() const { return !error_; }
159 
GetValues()160   rtc::ArrayView<uint64_t> GetValues() { return values_; }
GetPositions()161   rtc::ArrayView<uint8_t> GetPositions() { return positions_; }
GetStrings()162   rtc::ArrayView<absl::string_view> GetStrings() { return strings_; }
163 
ClearTemporaries()164   void ClearTemporaries() {
165     positions_.clear();
166     values_.clear();
167     strings_.clear();
168   }
169 
170   // Tracks whether an error has occurred in one of the helper
171   // functions above.
172   bool error_ = false;
173 
174   // Temporary storage for result.
175   std::vector<uint8_t> positions_;
176   std::vector<uint64_t> values_;
177   std::vector<absl::string_view> strings_;
178 
179   // String to be consumed.
180   absl::string_view pending_data_;
181   uint64_t num_events_ = 1;
182   uint64_t last_field_id_ = FieldParameters::kTimestampField;
183 };
184 
185 // Inverse of the ExtractRtcEventMember function used when parsing
186 // a log. Uses a vector of values to populate a specific field in a
187 // vector of structs.
188 template <typename T,
189           typename E,
190           std::enable_if_t<std::is_integral<T>::value, bool> = true>
191 ABSL_MUST_USE_RESULT RtcEventLogParseStatus
PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,T E::* member,rtc::ArrayView<E> output)192 PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
193                        T E::*member,
194                        rtc::ArrayView<E> output) {
195   size_t batch_size = values.size();
196   RTC_CHECK_EQ(output.size(), batch_size);
197   for (size_t i = 0; i < batch_size; ++i) {
198     output[i].*member = DecodeFromUnsignedToType<T>(values[i]);
199   }
200   return RtcEventLogParseStatus::Success();
201 }
202 
203 // Same as above, but for optional fields.
204 template <typename T,
205           typename E,
206           std::enable_if_t<std::is_integral<T>::value, bool> = true>
207 ABSL_MUST_USE_RESULT RtcEventLogParseStatus
PopulateRtcEventMember(const rtc::ArrayView<uint8_t> positions,const rtc::ArrayView<uint64_t> values,absl::optional<T> E::* member,rtc::ArrayView<E> output)208 PopulateRtcEventMember(const rtc::ArrayView<uint8_t> positions,
209                        const rtc::ArrayView<uint64_t> values,
210                        absl::optional<T> E::*member,
211                        rtc::ArrayView<E> output) {
212   size_t batch_size = positions.size();
213   RTC_CHECK_EQ(output.size(), batch_size);
214   RTC_CHECK_LE(values.size(), batch_size);
215   auto value_it = values.begin();
216   for (size_t i = 0; i < batch_size; ++i) {
217     if (positions[i]) {
218       RTC_CHECK(value_it != values.end());
219       output[i].*member = DecodeFromUnsignedToType<T>(value_it);
220       ++value_it;
221     } else {
222       output[i].*member = absl::nullopt;
223     }
224   }
225   RTC_CHECK(value_it == values.end());
226   return RtcEventLogParseStatus::Success();
227 }
228 
229 // Same as above, but for enum fields.
230 template <typename T,
231           typename E,
232           std::enable_if_t<std::is_enum<T>::value, bool> = true>
233 ABSL_MUST_USE_RESULT RtcEventLogParseStatus
PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,T E::* member,rtc::ArrayView<E> output)234 PopulateRtcEventMember(const rtc::ArrayView<uint64_t> values,
235                        T E::*member,
236                        rtc::ArrayView<E> output) {
237   size_t batch_size = values.size();
238   RTC_CHECK_EQ(output.size(), batch_size);
239   for (size_t i = 0; i < batch_size; ++i) {
240     auto result = RtcEventLogEnum<T>::Decode(values[i]);
241     if (!result.ok()) {
242       return result.status();
243     }
244     output[i].*member = result.value();
245   }
246   return RtcEventLogParseStatus::Success();
247 }
248 
249 // Same as above, but for string fields.
250 template <typename E>
251 ABSL_MUST_USE_RESULT RtcEventLogParseStatus
PopulateRtcEventMember(const rtc::ArrayView<absl::string_view> values,std::string E::* member,rtc::ArrayView<E> output)252 PopulateRtcEventMember(const rtc::ArrayView<absl::string_view> values,
253                        std::string E::*member,
254                        rtc::ArrayView<E> output) {
255   size_t batch_size = values.size();
256   RTC_CHECK_EQ(output.size(), batch_size);
257   for (size_t i = 0; i < batch_size; ++i) {
258     output[i].*member = values[i];
259   }
260   return RtcEventLogParseStatus::Success();
261 }
262 
263 // Same as above, but for Timestamp fields.
264 // N.B. Assumes that the encoded value uses millisecond precision.
265 template <typename E>
266 ABSL_MUST_USE_RESULT RtcEventLogParseStatus
PopulateRtcEventTimestamp(const rtc::ArrayView<uint64_t> & values,Timestamp E::* timestamp,rtc::ArrayView<E> output)267 PopulateRtcEventTimestamp(const rtc::ArrayView<uint64_t>& values,
268                           Timestamp E::*timestamp,
269                           rtc::ArrayView<E> output) {
270   size_t batch_size = values.size();
271   RTC_CHECK_EQ(batch_size, output.size());
272   for (size_t i = 0; i < batch_size; ++i) {
273     output[i].*timestamp =
274         Timestamp::Millis(DecodeFromUnsignedToType<int64_t>(values[i]));
275   }
276   return RtcEventLogParseStatus::Success();
277 }
278 
279 template <typename E>
ExtendLoggedBatch(std::vector<E> & output,size_t new_elements)280 rtc::ArrayView<E> ExtendLoggedBatch(std::vector<E>& output,
281                                     size_t new_elements) {
282   size_t old_size = output.size();
283   output.insert(output.end(), old_size + new_elements, E());
284   rtc::ArrayView<E> output_batch = output;
285   output_batch.subview(old_size);
286   RTC_DCHECK_EQ(output_batch.size(), new_elements);
287   return output_batch;
288 }
289 
290 }  // namespace webrtc
291 #endif  // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_PARSER_H_
292