Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 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 import logging | 5 import logging |
| 6 | 6 |
| 7 from google.protobuf.message import DecodeError | 7 from google.protobuf.message import DecodeError |
| 8 from infra_libs.event_mon.protos.chrome_infra_log_pb2 import ( | 8 from infra_libs.event_mon.protos.chrome_infra_log_pb2 import ( |
| 9 ChromeInfraEvent, ServiceEvent, BuildEvent) | 9 ChromeInfraEvent, ServiceEvent, BuildEvent) |
| 10 from infra_libs.event_mon.protos.goma_stats_pb2 import GomaStats | 10 from infra_libs.event_mon.protos.goma_stats_pb2 import GomaStats |
| 11 from infra_libs.event_mon.protos.log_request_lite_pb2 import LogRequestLite | 11 from infra_libs.event_mon.protos.log_request_lite_pb2 import LogRequestLite |
| 12 from infra_libs.event_mon import config, router | 12 from infra_libs.event_mon import config, router |
| 13 | 13 |
| 14 | 14 |
| 15 # These constants are part of the API. | 15 # These constants are part of the API. |
| 16 EVENT_TYPES = ('START', 'STOP', 'UPDATE', 'CURRENT_VERSION', 'CRASH') | 16 EVENT_TYPES = ('START', 'STOP', 'UPDATE', 'CURRENT_VERSION', 'CRASH') |
| 17 BUILD_EVENT_TYPES = ('SCHEDULER', 'BUILD', 'STEP') | 17 BUILD_EVENT_TYPES = ('SCHEDULER', 'BUILD', 'STEP') |
| 18 BUILD_RESULTS = (None, 'UNKNOWN', 'SUCCESS', 'FAILURE', 'INFRA_FAILURE', | 18 BUILD_RESULTS = ('UNKNOWN', 'SUCCESS', 'FAILURE', 'INFRA_FAILURE', |
| 19 'WARNING', 'SKIPPED', 'RETRY') | 19 'WARNING', 'SKIPPED', 'RETRY') |
| 20 TIMESTAMP_KINDS = (None, 'UNKNOWN', 'POINT', 'BEGIN', 'END') | 20 TIMESTAMP_KINDS = ('UNKNOWN', 'POINT', 'BEGIN', 'END') |
| 21 | 21 |
| 22 # Maximum size of stack trace sent in an event, in characters. | 22 # Maximum size of stack trace sent in an event, in characters. |
| 23 STACK_TRACE_MAX_SIZE = 1000 | 23 STACK_TRACE_MAX_SIZE = 1000 |
| 24 | 24 |
| 25 | 25 |
| 26 class Event(object): | 26 class Event(object): |
| 27 """Wraps the event proto with the necessary boilerplate code.""" | 27 """Wraps the event proto with the necessary boilerplate code.""" |
| 28 | 28 |
| 29 def __init__(self, timestamp_kind='POINT', | 29 def __init__(self, timestamp_kind='POINT', |
| 30 event_timestamp_ms=None, service_name=None): | 30 event_timestamp_ms=None, service_name=None): |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 | 79 |
| 80 The proto is filled using values provided in setup_monitoring() at | 80 The proto is filled using values provided in setup_monitoring() at |
| 81 initialization time, and args. | 81 initialization time, and args. |
| 82 | 82 |
| 83 Args: | 83 Args: |
| 84 timestamp_kind (string): any of ('POINT', 'BEGIN', 'END'). | 84 timestamp_kind (string): any of ('POINT', 'BEGIN', 'END'). |
| 85 | 85 |
| 86 Returns: | 86 Returns: |
| 87 event (chrome_infra_log_pb2.ChromeInfraEvent): | 87 event (chrome_infra_log_pb2.ChromeInfraEvent): |
| 88 """ | 88 """ |
| 89 if timestamp_kind not in TIMESTAMP_KINDS: | 89 # Testing for None because we want an error message when timestamp_kind == ''. |
| 90 if timestamp_kind is not None and timestamp_kind not in TIMESTAMP_KINDS: | |
| 90 logging.error('Invalid value for timestamp_kind: %s', timestamp_kind) | 91 logging.error('Invalid value for timestamp_kind: %s', timestamp_kind) |
| 91 return None | 92 return None |
| 92 | 93 |
| 93 # We must accept unicode here. | 94 # We must accept unicode here. |
| 94 if service_name is not None and not isinstance(service_name, basestring): | 95 if service_name is not None and not isinstance(service_name, basestring): |
| 95 logging.error('Invalid type for service_name: %s', type(service_name)) | 96 logging.error('Invalid type for service_name: %s', type(service_name)) |
| 96 return None | 97 return None |
| 97 | 98 |
| 98 event = ChromeInfraEvent() | 99 event = ChromeInfraEvent() |
| 99 event.CopyFrom(config._cache['default_event']) | 100 event.CopyFrom(config._cache['default_event']) |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 247 hostname, | 248 hostname, |
| 248 build_name, | 249 build_name, |
| 249 build_number=None, | 250 build_number=None, |
| 250 build_scheduling_time=None, | 251 build_scheduling_time=None, |
| 251 step_name=None, | 252 step_name=None, |
| 252 step_number=None, | 253 step_number=None, |
| 253 result=None, | 254 result=None, |
| 254 extra_result_code=None, | 255 extra_result_code=None, |
| 255 timestamp_kind='POINT', | 256 timestamp_kind='POINT', |
| 256 event_timestamp=None, | 257 event_timestamp=None, |
| 257 service_name=None): | 258 service_name=None, |
| 259 goma_stats=None): | |
| 258 """Compute a ChromeInfraEvent filled with a BuildEvent. | 260 """Compute a ChromeInfraEvent filled with a BuildEvent. |
| 259 | 261 |
| 260 Arguments are identical to those in send_build_event(), please refer | 262 Arguments are identical to those in send_build_event(), please refer |
| 261 to this docstring. | 263 to this docstring. |
| 262 | 264 |
| 263 Returns: | 265 Returns: |
| 264 event (log_request_lite_pb2.LogRequestLite.LogEventLite): can be None | 266 event (log_request_lite_pb2.LogRequestLite.LogEventLite): can be None |
| 265 if there is a major processing issue. | 267 if there is a major processing issue. |
| 268 | |
|
Yoshisato Yanagisawa
2015/10/29 02:42:52
nit: unnecessary space?
| |
| 266 """ | 269 """ |
| 267 if event_type not in BUILD_EVENT_TYPES: | 270 if event_type not in BUILD_EVENT_TYPES: |
| 268 logging.error('Invalid value for event_type: %s', event_type) | 271 logging.error('Invalid value for event_type: %s', event_type) |
| 269 return Event.null() | 272 return Event.null() |
| 270 | 273 |
| 271 event_wrapper = Event(timestamp_kind, event_timestamp, | 274 event_wrapper = Event(timestamp_kind, event_timestamp, |
| 272 service_name=service_name) | 275 service_name=service_name) |
| 273 if event_wrapper.is_null: | 276 if event_wrapper.is_null: |
| 274 return event_wrapper | 277 return event_wrapper |
| 275 | 278 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 step_number) | 332 step_number) |
| 330 | 333 |
| 331 if step_number is not None: | 334 if step_number is not None: |
| 332 event.build_event.step_number = step_number | 335 event.build_event.step_number = step_number |
| 333 | 336 |
| 334 # TODO(pgervais) remove this. | 337 # TODO(pgervais) remove this. |
| 335 # Hack to work around errors in the proto | 338 # Hack to work around errors in the proto |
| 336 mapping = {'WARNINGS': 'WARNING', 'EXCEPTION': 'INFRA_FAILURE'} | 339 mapping = {'WARNINGS': 'WARNING', 'EXCEPTION': 'INFRA_FAILURE'} |
| 337 result = mapping.get(result, result) | 340 result = mapping.get(result, result) |
| 338 | 341 |
| 339 if result not in BUILD_RESULTS: | 342 if result is not None: # we want an error message if result==''. |
| 340 logging.error('Invalid value for result: %s', result) | 343 if result not in BUILD_RESULTS: |
| 341 else: | 344 logging.error('Invalid value for result: %s', result) |
| 342 if result: # can be None | 345 else: |
| 343 event.build_event.result = getattr(BuildEvent, result) | 346 event.build_event.result = getattr(BuildEvent, result) |
| 344 | 347 |
| 345 if event_type == 'SCHEDULER': | 348 if event_type == 'SCHEDULER': |
| 346 logging.error('A result was provided for a "SCHEDULER" event type ' | 349 logging.error('A result was provided for a "SCHEDULER" event type ' |
| 347 '(%s). This is only accepted for BUILD and TEST types.', | 350 '(%s). This is only accepted for BUILD and TEST types.', |
| 348 result) | 351 result) |
| 349 | 352 |
| 350 if isinstance(extra_result_code, basestring): | 353 if isinstance(extra_result_code, basestring): |
| 351 extra_result_code = (extra_result_code, ) | 354 extra_result_code = (extra_result_code, ) |
| 352 if not isinstance(extra_result_code, (list, tuple)): | 355 if not isinstance(extra_result_code, (list, tuple)): |
| 353 if extra_result_code is not None: | 356 if extra_result_code is not None: |
| 354 logging.error('extra_result_code must be a string or list of strings. ' | 357 logging.error('extra_result_code must be a string or list of strings. ' |
| 355 'Got %s' % type(extra_result_code)) | 358 'Got %s' % type(extra_result_code)) |
| 356 else: | 359 else: |
| 357 non_strings = [] | 360 non_strings = [] |
| 358 extra_result_strings = [] | 361 extra_result_strings = [] |
| 359 for s in extra_result_code: | 362 for s in extra_result_code: |
| 360 if not isinstance(s, basestring): | 363 if not isinstance(s, basestring): |
| 361 non_strings.append(s) | 364 non_strings.append(s) |
| 362 else: | 365 else: |
| 363 extra_result_strings.append(s) | 366 extra_result_strings.append(s) |
| 364 | 367 |
| 365 if non_strings: | 368 if non_strings: |
| 366 logging.error('some values provided to extra_result_code are not strings:' | 369 logging.error('some values provided to extra_result_code are not strings:' |
| 367 ' %s' % str(non_strings)) | 370 ' %s' % str(non_strings)) |
| 368 for s in extra_result_strings: | 371 for s in extra_result_strings: |
| 369 event.build_event.extra_result_code.append(s) | 372 event.build_event.extra_result_code.append(s) |
| 370 | 373 |
| 374 if goma_stats: | |
| 375 if isinstance(goma_stats, GomaStats): | |
| 376 event.build_event.goma_stats.MergeFrom(goma_stats) | |
| 377 else: | |
| 378 logging.error('expected goma_stats to be an instance of GomaStats, ' | |
| 379 'got %s', type(goma_stats)) | |
| 380 | |
| 371 return event_wrapper | 381 return event_wrapper |
| 372 | 382 |
| 373 | 383 |
| 374 def send_build_event(event_type, | 384 def send_build_event(event_type, |
| 375 hostname, | 385 hostname, |
| 376 build_name, | 386 build_name, |
| 377 build_number=None, | 387 build_number=None, |
| 378 build_scheduling_time=None, | 388 build_scheduling_time=None, |
| 379 step_name=None, | 389 step_name=None, |
| 380 step_number=None, | 390 step_number=None, |
| 381 result=None, | 391 result=None, |
| 382 extra_result_code=None, | 392 extra_result_code=None, |
| 383 timestamp_kind='POINT', | 393 timestamp_kind='POINT', |
| 384 event_timestamp=None): | 394 event_timestamp=None, |
| 395 goma_stats=None): | |
| 385 """Send a ChromeInfraEvent filled with a BuildEvent | 396 """Send a ChromeInfraEvent filled with a BuildEvent |
| 386 | 397 |
| 387 Args: | 398 Args: |
| 388 event_type (string): any name of enum BuildEvent.BuildEventType. | 399 event_type (string): any name of enum BuildEvent.BuildEventType. |
| 389 (listed in infra_libs.event_mon.monitoring.BUILD_EVENT_TYPES) | 400 (listed in infra_libs.event_mon.monitoring.BUILD_EVENT_TYPES) |
| 390 hostname (string): fqdn of the machine that is running the build / step. | 401 hostname (string): fqdn of the machine that is running the build / step. |
| 391 aka the bot name. | 402 aka the bot name. |
| 392 build_name (string): name of the builder. | 403 build_name (string): name of the builder. |
| 393 | 404 |
| 394 Keyword args: | 405 Keyword args: |
| 395 build_number (int): as the name says. | 406 build_number (int): as the name says. |
| 396 build_scheduling_time (int): timestamp telling when the build was | 407 build_scheduling_time (int): timestamp telling when the build was |
| 397 scheduled. This is required when build_number is provided to make it | 408 scheduled. This is required when build_number is provided to make it |
| 398 possibly to distinguish two builds with the same build number. | 409 possibly to distinguish two builds with the same build number. |
| 399 step_name (str): name of the step. | 410 step_name (str): name of the step. |
| 400 step_number (int): rank of the step in the build. This is mandatory | 411 step_number (int): rank of the step in the build. This is mandatory |
| 401 if step_name is provided, because step_name is not enough to tell the | 412 if step_name is provided, because step_name is not enough to tell the |
| 402 order. | 413 order. |
| 403 result (string): any name of enum BuildEvent.BuildResult. | 414 result (string): any name of enum BuildEvent.BuildResult. |
| 404 (listed in infra_libs.event_mon.monitoring.BUILD_RESULTS) | 415 (listed in infra_libs.event_mon.monitoring.BUILD_RESULTS) |
| 405 extra_result_code (string or list of): arbitrary strings intended to provide | 416 extra_result_code (string or list of): arbitrary strings intended to provide |
| 406 more fine-grained information about the result. | 417 more fine-grained information about the result. |
| 418 goma_stats (goma_stats_pb2.GomaStats): statistics output by the Goma proxy. | |
| 407 | 419 |
| 408 Returns: | 420 Returns: |
| 409 success (bool): False if some error happened. | 421 success (bool): False if some error happened. |
| 410 """ | 422 """ |
| 411 return get_build_event(event_type, | 423 return get_build_event(event_type, |
| 412 hostname, | 424 hostname, |
| 413 build_name, | 425 build_name, |
| 414 build_number=build_number, | 426 build_number=build_number, |
| 415 build_scheduling_time=build_scheduling_time, | 427 build_scheduling_time=build_scheduling_time, |
| 416 step_name=step_name, | 428 step_name=step_name, |
| 417 step_number=step_number, | 429 step_number=step_number, |
| 418 result=result, | 430 result=result, |
| 419 extra_result_code=extra_result_code, | 431 extra_result_code=extra_result_code, |
| 420 timestamp_kind=timestamp_kind, | 432 timestamp_kind=timestamp_kind, |
| 421 event_timestamp=event_timestamp).send() | 433 event_timestamp=event_timestamp, |
| 434 goma_stats=goma_stats).send() | |
| 422 | 435 |
| 423 | 436 |
| 424 def send_events(events): | 437 def send_events(events): |
| 425 """Send several events at once to the endpoint. | 438 """Send several events at once to the endpoint. |
| 426 | 439 |
| 427 Args: | 440 Args: |
| 428 events (iterable of Event): events to send | 441 events (iterable of Event): events to send |
| 429 | 442 |
| 430 Return: | 443 Return: |
| 431 success (bool): True if data was successfully received by the endpoint. | 444 success (bool): True if data was successfully received by the endpoint. |
| 432 """ | 445 """ |
| 433 return config._router.push_event(tuple(e.log_event() for e in events)) | 446 return config._router.push_event(tuple(e.log_event() for e in events)) |
| OLD | NEW |