| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "blimp/common/logging.h" | |
| 6 | |
| 7 #include <iostream> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/format_macros.h" | |
| 13 #include "base/json/string_escape.h" | |
| 14 #include "base/lazy_instance.h" | |
| 15 #include "base/memory/ptr_util.h" | |
| 16 #include "base/strings/string_number_conversions.h" | |
| 17 #include "base/strings/string_util.h" | |
| 18 #include "base/strings/stringprintf.h" | |
| 19 #include "blimp/common/create_blimp_message.h" | |
| 20 #include "blimp/common/proto/blimp_message.pb.h" | |
| 21 | |
| 22 namespace blimp { | |
| 23 namespace { | |
| 24 | |
| 25 using LogFields = std::vector<std::pair<std::string, std::string>>; | |
| 26 | |
| 27 // The AddField() suite of functions are used to convert KV pairs with | |
| 28 // arbitrarily typed values into string/string KV pairs for logging. | |
| 29 | |
| 30 // Specialization for string values, surrounding them with quotes and escaping | |
| 31 // characters as necessary. | |
| 32 void AddField(const std::string& key, | |
| 33 const std::string& value, | |
| 34 LogFields* output) { | |
| 35 std::string escaped_value; | |
| 36 base::EscapeJSONString(value, true, &escaped_value); | |
| 37 output->push_back(std::make_pair(key, escaped_value)); | |
| 38 } | |
| 39 | |
| 40 // Specialization for string literal values. | |
| 41 void AddField(const std::string& key, const char* value, LogFields* output) { | |
| 42 output->push_back(std::make_pair(key, std::string(value))); | |
| 43 } | |
| 44 | |
| 45 // Specialization for boolean values (serialized as "true" or "false"). | |
| 46 void AddField(const std::string& key, bool value, LogFields* output) { | |
| 47 output->push_back(std::make_pair(key, (value ? "true" : "false"))); | |
| 48 } | |
| 49 | |
| 50 // Specialization for SizeMessage values, serializing them as | |
| 51 // WIDTHxHEIGHT:RATIO. RATIO is rounded to two digits of precision | |
| 52 // (e.g. 2.123 => 2.12). | |
| 53 void AddField(const std::string& key, | |
| 54 const SizeMessage& value, | |
| 55 LogFields* output) { | |
| 56 output->push_back(std::make_pair( | |
| 57 key, base::StringPrintf("%" PRIu64 "x%" PRIu64 ":%.2lf", value.width(), | |
| 58 value.height(), value.device_pixel_ratio()))); | |
| 59 } | |
| 60 | |
| 61 // Conversion function for all other types. | |
| 62 // Uses std::to_string() to serialize |value|. | |
| 63 template <typename T> | |
| 64 void AddField(const std::string& key, const T& value, LogFields* output) { | |
| 65 output->push_back(std::make_pair(key, std::to_string(value))); | |
| 66 } | |
| 67 | |
| 68 // The following LogExtractor subclasses contain logic for extracting loggable | |
| 69 // fields from BlimpMessages. | |
| 70 | |
| 71 // Logs fields from COMPOSITOR messages. | |
| 72 void ExtractCompositorMessageFields(const BlimpMessage& message, | |
| 73 LogFields* output) { | |
| 74 AddField("render_widget_id", message.compositor().render_widget_id(), output); | |
| 75 } | |
| 76 | |
| 77 // Logs fields from IME messages. | |
| 78 void ExtractImeMessageFields(const BlimpMessage& message, LogFields* output) { | |
| 79 AddField("render_widget_id", message.ime().render_widget_id(), output); | |
| 80 switch (message.ime().type()) { | |
| 81 case ImeMessage::SHOW_IME: | |
| 82 AddField("subtype", "SHOW_IME", output); | |
| 83 AddField("text_input_type", message.ime().text_input_type(), output); | |
| 84 break; | |
| 85 case ImeMessage::HIDE_IME: | |
| 86 AddField("subtype", "HIDE_IME", output); | |
| 87 break; | |
| 88 case ImeMessage::SET_TEXT: | |
| 89 AddField("subtype", "SET_TEXT", output); | |
| 90 AddField("ime_text(length)", message.ime().ime_text().size(), output); | |
| 91 break; | |
| 92 case ImeMessage::UNKNOWN: | |
| 93 AddField("subtype", "UNKNOWN", output); | |
| 94 break; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 // Logs fields from INPUT messages. | |
| 99 void ExtractInputMessageFields(const BlimpMessage& message, LogFields* output) { | |
| 100 AddField("render_widget_id", message.input().render_widget_id(), output); | |
| 101 AddField("timestamp_seconds", message.input().timestamp_seconds(), output); | |
| 102 switch (message.input().type()) { | |
| 103 case InputMessage::Type_GestureScrollBegin: | |
| 104 AddField("subtype", "GestureScrollBegin", output); | |
| 105 break; | |
| 106 case InputMessage::Type_GestureScrollEnd: | |
| 107 AddField("subtype", "GestureScrollEnd", output); | |
| 108 break; | |
| 109 case InputMessage::Type_GestureScrollUpdate: | |
| 110 AddField("subtype", "GestureScrollUpdate", output); | |
| 111 break; | |
| 112 case InputMessage::Type_GestureFlingStart: | |
| 113 AddField("subtype", "GestureFlingStart", output); | |
| 114 break; | |
| 115 case InputMessage::Type_GestureFlingCancel: | |
| 116 AddField("subtype", "GestureFlingCancel", output); | |
| 117 AddField("prevent_boosting", | |
| 118 message.input().gesture_fling_cancel().prevent_boosting(), | |
| 119 output); | |
| 120 break; | |
| 121 case InputMessage::Type_GestureTap: | |
| 122 AddField("subtype", "GestureTap", output); | |
| 123 break; | |
| 124 case InputMessage::Type_GesturePinchBegin: | |
| 125 AddField("subtype", "GesturePinchBegin", output); | |
| 126 break; | |
| 127 case InputMessage::Type_GesturePinchEnd: | |
| 128 AddField("subtype", "GesturePinchEnd", output); | |
| 129 break; | |
| 130 case InputMessage::Type_GesturePinchUpdate: | |
| 131 AddField("subtype", "GesturePinchUpdate", output); | |
| 132 break; | |
| 133 case InputMessage::Type_GestureTapDown: | |
| 134 AddField("subtype", "GestureTapDown", output); | |
| 135 break; | |
| 136 case InputMessage::Type_GestureTapCancel: | |
| 137 AddField("subtype", "GestureTapCancel", output); | |
| 138 break; | |
| 139 case InputMessage::Type_GestureTapUnconfirmed: | |
| 140 AddField("subtype", "GestureTapUnconfirmed", output); | |
| 141 break; | |
| 142 case InputMessage::Type_GestureShowPress: | |
| 143 AddField("subtype", "GestureShowPress", output); | |
| 144 break; | |
| 145 case InputMessage::UNKNOWN: | |
| 146 break; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 // Logs fields from NAVIGATION messages. | |
| 151 void ExtractNavigationMessageFields(const BlimpMessage& message, | |
| 152 LogFields* output) { | |
| 153 switch (message.navigation().type()) { | |
| 154 case NavigationMessage::NAVIGATION_STATE_CHANGED: | |
| 155 AddField("subtype", "NAVIGATION_STATE_CHANGED", output); | |
| 156 if (message.navigation().navigation_state_changed().has_url()) { | |
| 157 AddField("url", message.navigation().navigation_state_changed().url(), | |
| 158 output); | |
| 159 } | |
| 160 if (message.navigation().navigation_state_changed().has_favicon()) { | |
| 161 AddField( | |
| 162 "favicon_size", | |
| 163 message.navigation().navigation_state_changed().favicon().size(), | |
| 164 output); | |
| 165 } | |
| 166 if (message.navigation().navigation_state_changed().has_title()) { | |
| 167 AddField("title", | |
| 168 message.navigation().navigation_state_changed().title(), | |
| 169 output); | |
| 170 } | |
| 171 if (message.navigation().navigation_state_changed().has_loading()) { | |
| 172 AddField("loading", | |
| 173 message.navigation().navigation_state_changed().loading(), | |
| 174 output); | |
| 175 } | |
| 176 break; | |
| 177 case NavigationMessage::LOAD_URL: | |
| 178 AddField("subtype", "LOAD_URL", output); | |
| 179 AddField("url", message.navigation().load_url().url(), output); | |
| 180 break; | |
| 181 case NavigationMessage::GO_BACK: | |
| 182 AddField("subtype", "GO_BACK", output); | |
| 183 break; | |
| 184 case NavigationMessage::GO_FORWARD: | |
| 185 AddField("subtype", "GO_FORWARD", output); | |
| 186 break; | |
| 187 case NavigationMessage::RELOAD: | |
| 188 AddField("subtype", "RELOAD", output); | |
| 189 break; | |
| 190 case NavigationMessage::UNKNOWN: | |
| 191 break; | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 // Logs fields from PROTOCOL_CONTROL messages. | |
| 196 void ExtractProtocolControlMessageFields(const BlimpMessage& message, | |
| 197 LogFields* output) { | |
| 198 switch (message.protocol_control().connection_message_case()) { | |
| 199 case ProtocolControlMessage::kStartConnection: | |
| 200 AddField("subtype", "START_CONNECTION", output); | |
| 201 AddField( | |
| 202 "client_token", | |
| 203 message.protocol_control().start_connection().client_auth_token(), | |
| 204 output); | |
| 205 AddField("protocol_version", | |
| 206 message.protocol_control().start_connection().protocol_version(), | |
| 207 output); | |
| 208 break; | |
| 209 case ProtocolControlMessage::kCheckpointAck: | |
| 210 AddField("subtype", "CHECKPOINT_ACK", output); | |
| 211 AddField("checkpoint_id", | |
| 212 message.protocol_control().checkpoint_ack().checkpoint_id(), | |
| 213 output); | |
| 214 break; | |
| 215 case ProtocolControlMessage::kEndConnection: | |
| 216 AddField("subtype", "END_CONNECTION", output); | |
| 217 switch (message.protocol_control().end_connection().reason()) { | |
| 218 case EndConnectionMessage::AUTHENTICATION_FAILED: | |
| 219 AddField("reason", "AUTHENTICATION_FAILED", output); | |
| 220 break; | |
| 221 case EndConnectionMessage::PROTOCOL_MISMATCH: | |
| 222 AddField("reason", "PROTOCOL_MISMATCH", output); | |
| 223 break; | |
| 224 case EndConnectionMessage::UNKNOWN: | |
| 225 break; | |
| 226 } | |
| 227 break; | |
| 228 case ProtocolControlMessage::CONNECTION_MESSAGE_NOT_SET: | |
| 229 break; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 // Logs fields from RENDER_WIDGET messages. | |
| 234 void ExtractRenderWidgetMessageFields(const BlimpMessage& message, | |
| 235 LogFields* output) { | |
| 236 switch (message.render_widget().type()) { | |
| 237 case RenderWidgetMessage::INITIALIZE: | |
| 238 AddField("subtype", "INITIALIZE", output); | |
| 239 break; | |
| 240 case RenderWidgetMessage::CREATED: | |
| 241 AddField("subtype", "CREATED", output); | |
| 242 break; | |
| 243 case RenderWidgetMessage::DELETED: | |
| 244 AddField("subtype", "DELETED", output); | |
| 245 break; | |
| 246 case RenderWidgetMessage::UNKNOWN: | |
| 247 break; | |
| 248 } | |
| 249 AddField("render_widget_id", message.render_widget().render_widget_id(), | |
| 250 output); | |
| 251 } | |
| 252 | |
| 253 // Logs fields from SETTINGS messages. | |
| 254 void ExtractSettingsMessageFields(const BlimpMessage& message, | |
| 255 LogFields* output) { | |
| 256 if (message.settings().has_engine_settings()) { | |
| 257 const EngineSettingsMessage& engine_settings = | |
| 258 message.settings().engine_settings(); | |
| 259 AddField("subtype", "ENGINE_SETTINGS", output); | |
| 260 AddField("record_whole_document", engine_settings.record_whole_document(), | |
| 261 output); | |
| 262 AddField("client_os_info", engine_settings.client_os_info(), output); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 // Logs fields from TAB_CONTROL messages. | |
| 267 void ExtractTabControlMessageFields(const BlimpMessage& message, | |
| 268 LogFields* output) { | |
| 269 switch (message.tab_control().tab_control_case()) { | |
| 270 case TabControlMessage::kCreateTab: | |
| 271 AddField("subtype", "CREATE_TAB", output); | |
| 272 break; | |
| 273 case TabControlMessage::kCloseTab: | |
| 274 AddField("subtype", "CLOSE_TAB", output); | |
| 275 break; | |
| 276 case TabControlMessage::kSize: | |
| 277 AddField("subtype", "SIZE", output); | |
| 278 AddField("size", message.tab_control().size(), output); | |
| 279 break; | |
| 280 case TabControlMessage::TAB_CONTROL_NOT_SET: | |
| 281 break; | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 // Logs fields from BLOB_CHANNEL messages. | |
| 286 void ExtractBlobChannelMessageFields(const BlimpMessage& message, | |
| 287 LogFields* output) { | |
| 288 switch (message.blob_channel().type_case()) { | |
| 289 case BlobChannelMessage::TypeCase::kTransferBlob: | |
| 290 AddField("subtype", "TRANSFER_BLOB", output); | |
| 291 AddField("id", | |
| 292 base::HexEncode( | |
| 293 message.blob_channel().transfer_blob().blob_id().data(), | |
| 294 message.blob_channel().transfer_blob().blob_id().size()), | |
| 295 output); | |
| 296 AddField("payload_size", | |
| 297 message.blob_channel().transfer_blob().payload().size(), output); | |
| 298 break; | |
| 299 case BlobChannelMessage::TypeCase::TYPE_NOT_SET: // unknown | |
| 300 break; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 // Logs fields from GEOLOCATION messages. | |
| 305 void ExtractGeolocationMessageFields(const BlimpMessage& message, | |
| 306 LogFields* output) { | |
| 307 switch (message.geolocation().type_case()) { | |
| 308 case GeolocationMessage::TypeCase::kSetInterestLevel: | |
| 309 AddField("subtype", "SET_INTEREST_LEVEL", output); | |
| 310 AddField("level", message.geolocation().set_interest_level().level(), | |
| 311 output); | |
| 312 break; | |
| 313 case GeolocationMessage::TypeCase::kRequestRefresh: | |
| 314 AddField("subtype", "REQUEST_REFRESH", output); | |
| 315 break; | |
| 316 case GeolocationMessage::TypeCase::kCoordinates: { | |
| 317 const GeolocationCoordinatesMessage& coordinates = | |
| 318 message.geolocation().coordinates(); | |
| 319 AddField("subtype", "COORDINATES", output); | |
| 320 AddField("latitude", coordinates.latitude(), output); | |
| 321 AddField("longitude", coordinates.longitude(), output); | |
| 322 AddField("altitude", coordinates.altitude(), output); | |
| 323 AddField("accuracy", coordinates.accuracy(), output); | |
| 324 AddField("altitude_accuracy", coordinates.altitude_accuracy(), output); | |
| 325 AddField("heading", coordinates.heading(), output); | |
| 326 AddField("speed", coordinates.speed(), output); | |
| 327 break; | |
| 328 } | |
| 329 case GeolocationMessage::TypeCase::kError: | |
| 330 AddField("subtype", "ERROR", output); | |
| 331 AddField("error_code", message.geolocation().error().error_code(), | |
| 332 output); | |
| 333 AddField("error_message", message.geolocation().error().error_message(), | |
| 334 output); | |
| 335 break; | |
| 336 case GeolocationMessage::TypeCase::TYPE_NOT_SET: | |
| 337 break; | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 } // namespace | |
| 342 | |
| 343 std::ostream& operator<<(std::ostream& out, const BlimpMessage& message) { | |
| 344 LogFields fields; | |
| 345 | |
| 346 switch (message.feature_case()) { | |
| 347 case BlimpMessage::kCompositor: | |
| 348 AddField("type", "COMPOSITOR", &fields); | |
| 349 ExtractCompositorMessageFields(message, &fields); | |
| 350 break; | |
| 351 case BlimpMessage::kInput: | |
| 352 AddField("type", "INPUT", &fields); | |
| 353 ExtractInputMessageFields(message, &fields); | |
| 354 break; | |
| 355 case BlimpMessage::kNavigation: | |
| 356 AddField("type", "NAVIGATION", &fields); | |
| 357 ExtractNavigationMessageFields(message, &fields); | |
| 358 break; | |
| 359 case BlimpMessage::kProtocolControl: | |
| 360 AddField("type", "PROTOCOL_CONTROL", &fields); | |
| 361 ExtractProtocolControlMessageFields(message, &fields); | |
| 362 break; | |
| 363 case BlimpMessage::kRenderWidget: | |
| 364 AddField("type", "RENDER_WIDGET", &fields); | |
| 365 ExtractRenderWidgetMessageFields(message, &fields); | |
| 366 break; | |
| 367 case BlimpMessage::kSettings: | |
| 368 AddField("type", "SETTINGS", &fields); | |
| 369 ExtractSettingsMessageFields(message, &fields); | |
| 370 break; | |
| 371 case BlimpMessage::kTabControl: | |
| 372 AddField("type", "TAB_CONTROL", &fields); | |
| 373 ExtractTabControlMessageFields(message, &fields); | |
| 374 break; | |
| 375 case BlimpMessage::kBlobChannel: | |
| 376 AddField("type", "BLOB_CHANNEL", &fields); | |
| 377 ExtractBlobChannelMessageFields(message, &fields); | |
| 378 break; | |
| 379 case BlimpMessage::kIme: | |
| 380 AddField("type", "IME", &fields); | |
| 381 ExtractImeMessageFields(message, &fields); | |
| 382 break; | |
| 383 case BlimpMessage::kGeolocation: | |
| 384 AddField("type", "GEOLOCATION", &fields); | |
| 385 ExtractGeolocationMessageFields(message, &fields); | |
| 386 break; | |
| 387 case BlimpMessage::FEATURE_NOT_SET: | |
| 388 AddField("type", "<UNKNOWN>", &fields); | |
| 389 break; | |
| 390 } | |
| 391 | |
| 392 // Append "target_tab_id" (if present) and "byte_size" to the field set. | |
| 393 if (message.has_target_tab_id()) { | |
| 394 AddField("target_tab_id", message.target_tab_id(), &fields); | |
| 395 } | |
| 396 AddField("byte_size", message.ByteSize(), &fields); | |
| 397 | |
| 398 // Format message using the syntax: | |
| 399 // <BlimpMessage field1=value1 field2="value 2"> | |
| 400 out << "<BlimpMessage "; | |
| 401 for (size_t i = 0; i < fields.size(); ++i) { | |
| 402 out << fields[i].first << "=" << fields[i].second | |
| 403 << (i != fields.size() - 1 ? " " : ""); | |
| 404 } | |
| 405 out << ">"; | |
| 406 | |
| 407 return out; | |
| 408 } | |
| 409 | |
| 410 } // namespace blimp | |
| OLD | NEW |