Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "blimp/common/logging.h" | 5 #include "blimp/common/logging.h" |
| 6 | 6 |
| 7 #include <iostream> | 7 #include <iostream> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 12 #include "base/json/string_escape.h" | 12 #include "base/json/string_escape.h" |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 18 #include "blimp/common/create_blimp_message.h" | 18 #include "blimp/common/create_blimp_message.h" |
| 19 #include "blimp/common/proto/blimp_message.pb.h" | 19 #include "blimp/common/proto/blimp_message.pb.h" |
| 20 | 20 |
| 21 namespace blimp { | 21 namespace blimp { |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 static base::LazyInstance<BlimpMessageLogger> g_logger = | 24 typedef std::vector<std::pair<std::string, std::string>> LogFields; |
| 25 LAZY_INSTANCE_INITIALIZER; | |
| 26 | 25 |
| 27 // The AddField() suite of functions are used to convert KV pairs with | 26 // The AddField() suite of functions are used to convert KV pairs with |
| 28 // arbitrarily typed values into string/string KV pairs for logging. | 27 // arbitrarily typed values into string/string KV pairs for logging. |
| 29 | 28 |
| 30 // Specialization for string values, surrounding them with quotes and escaping | 29 // Specialization for string values, surrounding them with quotes and escaping |
| 31 // characters as necessary. | 30 // characters as necessary. |
| 32 void AddField(const std::string& key, | 31 void AddField(const std::string& key, |
| 33 const std::string& value, | 32 const std::string& value, |
| 34 LogFields* output) { | 33 LogFields* output) { |
| 35 std::string escaped_value; | 34 std::string escaped_value; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 62 // Uses std::to_string() to serialize |value|. | 61 // Uses std::to_string() to serialize |value|. |
| 63 template <typename T> | 62 template <typename T> |
| 64 void AddField(const std::string& key, const T& value, LogFields* output) { | 63 void AddField(const std::string& key, const T& value, LogFields* output) { |
| 65 output->push_back(std::make_pair(key, std::to_string(value))); | 64 output->push_back(std::make_pair(key, std::to_string(value))); |
| 66 } | 65 } |
| 67 | 66 |
| 68 // The following LogExtractor subclasses contain logic for extracting loggable | 67 // The following LogExtractor subclasses contain logic for extracting loggable |
| 69 // fields from BlimpMessages. | 68 // fields from BlimpMessages. |
| 70 | 69 |
| 71 // Logs fields from COMPOSITOR messages. | 70 // Logs fields from COMPOSITOR messages. |
| 72 class CompositorLogExtractor : public LogExtractor { | 71 class CompositorLogExtractor { |
| 73 void ExtractFields(const BlimpMessage& message, | 72 public: |
| 74 LogFields* output) const override { | 73 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
|
Wez
2016/06/01 21:35:15
Looks like this, and the other static member metho
Kevin M
2016/06/02 18:05:00
Done.
| |
| 75 AddField("render_widget_id", message.compositor().render_widget_id(), | 74 AddField("render_widget_id", message.compositor().render_widget_id(), |
| 76 output); | 75 output); |
| 77 } | 76 } |
| 78 }; | 77 }; |
| 79 | 78 |
| 80 // Logs fields from INPUT messages. | 79 // Logs fields from INPUT messages. |
| 81 class InputLogExtractor : public LogExtractor { | 80 class InputLogExtractor { |
| 82 void ExtractFields(const BlimpMessage& message, | 81 public: |
| 83 LogFields* output) const override { | 82 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 84 AddField("render_widget_id", message.input().render_widget_id(), output); | 83 AddField("render_widget_id", message.input().render_widget_id(), output); |
| 85 AddField("timestamp_seconds", message.input().timestamp_seconds(), output); | 84 AddField("timestamp_seconds", message.input().timestamp_seconds(), output); |
| 86 switch (message.input().type()) { | 85 switch (message.input().type()) { |
| 87 case InputMessage::Type_GestureScrollBegin: | 86 case InputMessage::Type_GestureScrollBegin: |
| 88 AddField("subtype", "GestureScrollBegin", output); | 87 AddField("subtype", "GestureScrollBegin", output); |
| 89 break; | 88 break; |
| 90 case InputMessage::Type_GestureScrollEnd: | 89 case InputMessage::Type_GestureScrollEnd: |
| 91 AddField("subtype", "GestureScrollEnd", output); | 90 AddField("subtype", "GestureScrollEnd", output); |
| 92 break; | 91 break; |
| 93 case InputMessage::Type_GestureScrollUpdate: | 92 case InputMessage::Type_GestureScrollUpdate: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 114 case InputMessage::Type_GesturePinchUpdate: | 113 case InputMessage::Type_GesturePinchUpdate: |
| 115 AddField("subtype", "GesturePinchUpdate", output); | 114 AddField("subtype", "GesturePinchUpdate", output); |
| 116 break; | 115 break; |
| 117 default: // unknown | 116 default: // unknown |
| 118 break; | 117 break; |
| 119 } | 118 } |
| 120 } | 119 } |
| 121 }; | 120 }; |
| 122 | 121 |
| 123 // Logs fields from NAVIGATION messages. | 122 // Logs fields from NAVIGATION messages. |
| 124 class NavigationLogExtractor : public LogExtractor { | 123 class NavigationLogExtractor { |
| 125 void ExtractFields(const BlimpMessage& message, | 124 public: |
| 126 LogFields* output) const override { | 125 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 127 switch (message.navigation().type()) { | 126 switch (message.navigation().type()) { |
| 128 case NavigationMessage::NAVIGATION_STATE_CHANGED: | 127 case NavigationMessage::NAVIGATION_STATE_CHANGED: |
| 129 AddField("subtype", "NAVIGATION_STATE_CHANGED", output); | 128 AddField("subtype", "NAVIGATION_STATE_CHANGED", output); |
| 130 if (message.navigation().navigation_state_changed().has_url()) { | 129 if (message.navigation().navigation_state_changed().has_url()) { |
| 131 AddField("url", message.navigation().navigation_state_changed().url(), | 130 AddField("url", message.navigation().navigation_state_changed().url(), |
| 132 output); | 131 output); |
| 133 } | 132 } |
| 134 if (message.navigation().navigation_state_changed().has_favicon()) { | 133 if (message.navigation().navigation_state_changed().has_favicon()) { |
| 135 AddField( | 134 AddField( |
| 136 "favicon_size", | 135 "favicon_size", |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 161 case NavigationMessage::RELOAD: | 160 case NavigationMessage::RELOAD: |
| 162 AddField("subtype", "RELOAD", output); | 161 AddField("subtype", "RELOAD", output); |
| 163 break; | 162 break; |
| 164 default: | 163 default: |
| 165 break; | 164 break; |
| 166 } | 165 } |
| 167 } | 166 } |
| 168 }; | 167 }; |
| 169 | 168 |
| 170 // Logs fields from PROTOCOL_CONTROL messages. | 169 // Logs fields from PROTOCOL_CONTROL messages. |
| 171 class ProtocolControlLogExtractor : public LogExtractor { | 170 class ProtocolControlLogExtractor { |
| 172 void ExtractFields(const BlimpMessage& message, | 171 public: |
| 173 LogFields* output) const override { | 172 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 174 switch (message.protocol_control().connection_message_case()) { | 173 switch (message.protocol_control().connection_message_case()) { |
| 175 case ProtocolControlMessage::kStartConnection: | 174 case ProtocolControlMessage::kStartConnection: |
| 176 AddField("subtype", "START_CONNECTION", output); | 175 AddField("subtype", "START_CONNECTION", output); |
| 177 AddField("client_token", | 176 AddField("client_token", |
| 178 message.protocol_control().start_connection().client_token(), | 177 message.protocol_control().start_connection().client_token(), |
| 179 output); | 178 output); |
| 180 AddField( | 179 AddField( |
| 181 "protocol_version", | 180 "protocol_version", |
| 182 message.protocol_control().start_connection().protocol_version(), | 181 message.protocol_control().start_connection().protocol_version(), |
| 183 output); | 182 output); |
| 184 break; | 183 break; |
| 185 case ProtocolControlMessage::kCheckpointAck: | 184 case ProtocolControlMessage::kCheckpointAck: |
| 186 AddField("subtype", "CHECKPOINT_ACK", output); | 185 AddField("subtype", "CHECKPOINT_ACK", output); |
| 187 AddField("checkpoint_id", | 186 AddField("checkpoint_id", |
| 188 message.protocol_control().checkpoint_ack().checkpoint_id(), | 187 message.protocol_control().checkpoint_ack().checkpoint_id(), |
| 189 output); | 188 output); |
| 190 break; | 189 break; |
| 191 default: | 190 default: |
| 192 break; | 191 break; |
| 193 } | 192 } |
| 194 } | 193 } |
| 195 }; | 194 }; |
| 196 | 195 |
| 197 // Logs fields from RENDER_WIDGET messages. | 196 // Logs fields from RENDER_WIDGET messages. |
| 198 class RenderWidgetLogExtractor : public LogExtractor { | 197 class RenderWidgetLogExtractor { |
| 199 void ExtractFields(const BlimpMessage& message, | 198 public: |
| 200 LogFields* output) const override { | 199 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 201 switch (message.render_widget().type()) { | 200 switch (message.render_widget().type()) { |
| 202 case RenderWidgetMessage::INITIALIZE: | 201 case RenderWidgetMessage::INITIALIZE: |
| 203 AddField("subtype", "INITIALIZE", output); | 202 AddField("subtype", "INITIALIZE", output); |
| 204 break; | 203 break; |
| 205 case RenderWidgetMessage::CREATED: | 204 case RenderWidgetMessage::CREATED: |
| 206 AddField("subtype", "CREATED", output); | 205 AddField("subtype", "CREATED", output); |
| 207 break; | 206 break; |
| 208 case RenderWidgetMessage::DELETED: | 207 case RenderWidgetMessage::DELETED: |
| 209 AddField("subtype", "DELETED", output); | 208 AddField("subtype", "DELETED", output); |
| 210 break; | 209 break; |
| 211 } | 210 } |
| 212 AddField("render_widget_id", message.render_widget().render_widget_id(), | 211 AddField("render_widget_id", message.render_widget().render_widget_id(), |
| 213 output); | 212 output); |
| 214 } | 213 } |
| 215 }; | 214 }; |
| 216 | 215 |
| 217 // Logs fields from SETTINGS messages. | 216 // Logs fields from SETTINGS messages. |
| 218 class SettingsLogExtractor : public LogExtractor { | 217 class SettingsLogExtractor { |
| 219 void ExtractFields(const BlimpMessage& message, | 218 public: |
| 220 LogFields* output) const override { | 219 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 221 if (message.settings().has_engine_settings()) { | 220 if (message.settings().has_engine_settings()) { |
| 222 const EngineSettingsMessage& engine_settings = | 221 const EngineSettingsMessage& engine_settings = |
| 223 message.settings().engine_settings(); | 222 message.settings().engine_settings(); |
| 224 AddField("subtype", "ENGINE_SETTINGS", output); | 223 AddField("subtype", "ENGINE_SETTINGS", output); |
| 225 AddField("record_whole_document", engine_settings.record_whole_document(), | 224 AddField("record_whole_document", engine_settings.record_whole_document(), |
| 226 output); | 225 output); |
| 227 AddField("client_os_info", engine_settings.client_os_info(), output); | 226 AddField("client_os_info", engine_settings.client_os_info(), output); |
| 228 } | 227 } |
| 229 } | 228 } |
| 230 }; | 229 }; |
| 231 | 230 |
| 232 // Logs fields from TAB_CONTROL messages. | 231 // Logs fields from TAB_CONTROL messages. |
| 233 class TabControlLogExtractor : public LogExtractor { | 232 class TabControlLogExtractor { |
| 234 void ExtractFields(const BlimpMessage& message, | 233 public: |
| 235 LogFields* output) const override { | 234 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 236 switch (message.tab_control().tab_control_case()) { | 235 switch (message.tab_control().tab_control_case()) { |
| 237 case TabControlMessage::kCreateTab: | 236 case TabControlMessage::kCreateTab: |
| 238 AddField("subtype", "CREATE_TAB", output); | 237 AddField("subtype", "CREATE_TAB", output); |
| 239 break; | 238 break; |
| 240 case TabControlMessage::kCloseTab: | 239 case TabControlMessage::kCloseTab: |
| 241 AddField("subtype", "CLOSE_TAB", output); | 240 AddField("subtype", "CLOSE_TAB", output); |
| 242 break; | 241 break; |
| 243 case TabControlMessage::kSize: | 242 case TabControlMessage::kSize: |
| 244 AddField("subtype", "SIZE", output); | 243 AddField("subtype", "SIZE", output); |
| 245 AddField("size", message.tab_control().size(), output); | 244 AddField("size", message.tab_control().size(), output); |
| 246 break; | 245 break; |
| 247 default: // unknown | 246 default: // unknown |
| 248 break; | 247 break; |
| 249 } | 248 } |
| 250 } | 249 } |
| 251 }; | 250 }; |
| 252 | 251 |
| 253 // Logs fields from BLOB_CHANNEL messages. | 252 // Logs fields from BLOB_CHANNEL messages. |
| 254 class BlobChannelLogExtractor : public LogExtractor { | 253 class BlobChannelLogExtractor { |
| 255 void ExtractFields(const BlimpMessage& message, | 254 public: |
| 256 LogFields* output) const override { | 255 static void ExtractFields(const BlimpMessage& message, LogFields* output) { |
| 257 switch (message.blob_channel().type_case()) { | 256 switch (message.blob_channel().type_case()) { |
| 258 case BlobChannelMessage::TypeCase::kTransferBlob: | 257 case BlobChannelMessage::TypeCase::kTransferBlob: |
| 259 AddField("subtype", "TRANSFER_BLOB", output); | 258 AddField("subtype", "TRANSFER_BLOB", output); |
| 260 AddField("id", | 259 AddField("id", |
| 261 base::HexEncode( | 260 base::HexEncode( |
| 262 message.blob_channel().transfer_blob().blob_id().data(), | 261 message.blob_channel().transfer_blob().blob_id().data(), |
| 263 message.blob_channel().transfer_blob().blob_id().size()), | 262 message.blob_channel().transfer_blob().blob_id().size()), |
| 264 output); | 263 output); |
| 265 AddField("payload_size", | 264 AddField("payload_size", |
| 266 message.blob_channel().transfer_blob().payload().size(), | 265 message.blob_channel().transfer_blob().payload().size(), |
| 267 output); | 266 output); |
| 268 break; | 267 break; |
| 269 case BlobChannelMessage::TypeCase::TYPE_NOT_SET: // unknown | 268 case BlobChannelMessage::TypeCase::TYPE_NOT_SET: // unknown |
| 270 break; | 269 break; |
| 271 } | 270 } |
| 272 } | 271 } |
| 273 }; | 272 }; |
| 274 | 273 |
| 275 // No fields are extracted from |message|. | 274 void LogMessageToStream(const BlimpMessage& message, std::ostream* out) { |
| 276 class NullLogExtractor : public LogExtractor { | |
| 277 void ExtractFields(const BlimpMessage& message, | |
| 278 LogFields* output) const override {} | |
| 279 }; | |
| 280 | |
| 281 } // namespace | |
| 282 | |
| 283 BlimpMessageLogger::BlimpMessageLogger() { | |
| 284 AddHandler("COMPOSITOR", BlimpMessage::kCompositor, | |
| 285 base::WrapUnique(new CompositorLogExtractor)); | |
| 286 AddHandler("INPUT", BlimpMessage::kInput, | |
| 287 base::WrapUnique(new InputLogExtractor)); | |
| 288 AddHandler("NAVIGATION", BlimpMessage::kNavigation, | |
| 289 base::WrapUnique(new NavigationLogExtractor)); | |
| 290 AddHandler("PROTOCOL_CONTROL", BlimpMessage::kProtocolControl, | |
| 291 base::WrapUnique(new ProtocolControlLogExtractor)); | |
| 292 AddHandler("RENDER_WIDGET", BlimpMessage::kRenderWidget, | |
| 293 base::WrapUnique(new RenderWidgetLogExtractor)); | |
| 294 AddHandler("SETTINGS", BlimpMessage::kSettings, | |
| 295 base::WrapUnique(new SettingsLogExtractor)); | |
| 296 AddHandler("TAB_CONTROL", BlimpMessage::kTabControl, | |
| 297 base::WrapUnique(new TabControlLogExtractor)); | |
| 298 AddHandler("BLOB_CHANNEL", BlimpMessage::kBlobChannel, | |
| 299 base::WrapUnique(new BlobChannelLogExtractor)); | |
| 300 } | |
| 301 | |
| 302 BlimpMessageLogger::~BlimpMessageLogger() {} | |
| 303 | |
| 304 void BlimpMessageLogger::AddHandler(const std::string& feature_name, | |
| 305 BlimpMessage::FeatureCase feature_case, | |
| 306 std::unique_ptr<LogExtractor> extractor) { | |
| 307 DCHECK(extractors_.find(feature_case) == extractors_.end()); | |
| 308 DCHECK(!feature_name.empty()); | |
| 309 extractors_[feature_case] = make_pair(feature_name, std::move(extractor)); | |
| 310 } | |
| 311 | |
| 312 void BlimpMessageLogger::LogMessageToStream(const BlimpMessage& message, | |
| 313 std::ostream* out) const { | |
| 314 LogFields fields; | 275 LogFields fields; |
| 315 | 276 |
| 316 auto extractor = extractors_.find(message.feature_case()); | 277 switch (message.feature_case()) { |
| 317 if (extractor != extractors_.end()) { | 278 case BlimpMessage::kCompositor: |
| 318 // An extractor is registered for |message|. | 279 fields.push_back(std::make_pair("type", "COMPOSITOR")); |
| 319 // Add the human-readable name of |message.type|. | 280 CompositorLogExtractor::ExtractFields(message, &fields); |
| 320 fields.push_back(make_pair("type", extractor->second.first)); | 281 break; |
| 321 extractor->second.second->ExtractFields(message, &fields); | 282 case BlimpMessage::kInput: |
| 322 } else { | 283 fields.push_back(std::make_pair("type", "INPUT")); |
| 323 // Don't know the human-readable name of |message.type|. | 284 InputLogExtractor::ExtractFields(message, &fields); |
| 324 // Just represent it using its numeric form instead. | 285 break; |
| 325 AddField("type", message.feature_case(), &fields); | 286 case BlimpMessage::kNavigation: |
| 287 fields.push_back(std::make_pair("type", "NAVIGATION")); | |
| 288 NavigationLogExtractor::ExtractFields(message, &fields); | |
| 289 break; | |
| 290 case BlimpMessage::kProtocolControl: | |
| 291 fields.push_back(std::make_pair("type", "PROTOCOL_CONTROL")); | |
| 292 ProtocolControlLogExtractor::ExtractFields(message, &fields); | |
| 293 break; | |
| 294 case BlimpMessage::kRenderWidget: | |
| 295 fields.push_back(std::make_pair("type", "RENDER_WIDGET")); | |
| 296 RenderWidgetLogExtractor::ExtractFields(message, &fields); | |
| 297 break; | |
| 298 case BlimpMessage::kSettings: | |
| 299 fields.push_back(std::make_pair("type", "SETTINGS")); | |
| 300 SettingsLogExtractor::ExtractFields(message, &fields); | |
| 301 break; | |
| 302 case BlimpMessage::kTabControl: | |
| 303 fields.push_back(std::make_pair("type", "TAB_CONTROL")); | |
| 304 TabControlLogExtractor::ExtractFields(message, &fields); | |
| 305 break; | |
| 306 case BlimpMessage::kBlobChannel: | |
| 307 fields.push_back(std::make_pair("type", "BLOB_CHANNEL")); | |
| 308 BlobChannelLogExtractor::ExtractFields(message, &fields); | |
| 309 break; | |
| 310 case BlimpMessage::kIme: | |
| 311 fields.push_back(std::make_pair("type", "IME")); | |
| 312 break; | |
| 313 case BlimpMessage::FEATURE_NOT_SET: | |
| 314 fields.push_back(std::make_pair("type", "<UNKNOWN>")); | |
| 315 break; | |
| 326 } | 316 } |
| 327 | 317 |
| 328 // Append "target_tab_id" (if present) and "byte_size" to the field set. | 318 // Append "target_tab_id" (if present) and "byte_size" to the field set. |
| 329 if (message.has_target_tab_id()) { | 319 if (message.has_target_tab_id()) { |
| 330 AddField("target_tab_id", message.target_tab_id(), &fields); | 320 AddField("target_tab_id", message.target_tab_id(), &fields); |
| 331 } | 321 } |
| 332 AddField("byte_size", message.ByteSize(), &fields); | 322 AddField("byte_size", message.ByteSize(), &fields); |
| 333 | 323 |
| 334 // Format message using the syntax: | 324 // Format message using the syntax: |
| 335 // <BlimpMessage field1=value1 field2="value 2"> | 325 // <BlimpMessage field1=value1 field2="value 2"> |
| 336 *out << "<BlimpMessage "; | 326 *out << "<BlimpMessage "; |
| 337 for (size_t i = 0; i < fields.size(); ++i) { | 327 for (size_t i = 0; i < fields.size(); ++i) { |
| 338 *out << fields[i].first << "=" << fields[i].second | 328 *out << fields[i].first << "=" << fields[i].second |
| 339 << (i != fields.size() - 1 ? " " : ""); | 329 << (i != fields.size() - 1 ? " " : ""); |
| 340 } | 330 } |
| 341 *out << ">"; | 331 *out << ">"; |
| 342 } | 332 } |
| 343 | 333 |
| 334 } // namespace | |
| 335 | |
| 344 std::ostream& operator<<(std::ostream& out, const BlimpMessage& message) { | 336 std::ostream& operator<<(std::ostream& out, const BlimpMessage& message) { |
| 345 g_logger.Get().LogMessageToStream(message, &out); | 337 LogMessageToStream(message, &out); |
| 346 return out; | 338 return out; |
| 347 } | 339 } |
| 348 | 340 |
| 349 } // namespace blimp | 341 } // namespace blimp |
| OLD | NEW |