Index: infra/tools/send_monitoring_event/send_event.py |
diff --git a/infra/tools/send_monitoring_event/send_event.py b/infra/tools/send_monitoring_event/send_event.py |
index 40d73a3d1d6a2412ad0310c048e2437ab9f2287a..14ea381c96073763e55035c91d91f221195960d5 100644 |
--- a/infra/tools/send_monitoring_event/send_event.py |
+++ b/infra/tools/send_monitoring_event/send_event.py |
@@ -10,9 +10,12 @@ import json |
import sys |
from infra_libs import event_mon |
-import infra_libs.logs |
from infra_libs import ts_mon |
+import infra_libs.logs |
+from infra_libs.event_mon.protos.log_request_lite_pb2 import LogRequestLite |
+from infra_libs.event_mon.protos.chrome_infra_log_pb2 import ChromeInfraEvent |
+from infra_libs.event_mon.protos.goma_stats_pb2 import GomaStats |
LOGGER = logging.getLogger(__name__) |
@@ -46,13 +49,10 @@ def get_arguments(argv): |
# Common fields |
common_group = parser.add_argument_group('Common event options') |
common_group.add_argument('--event-mon-timestamp-kind', |
- choices=[kind |
- for kind in event_mon.TIMESTAMP_KINDS |
- if kind], |
- default='POINT', |
+ choices=event_mon.TIMESTAMP_KINDS, |
help='General kind of event. This value is used ' |
'e.g. to\nautomatically compute durations between ' |
- 'START and STOP\nevents. Default: %(default)s') |
+ 'START and STOP\nevents.') |
common_group.add_argument('--event-mon-event-timestamp', type=int, |
help='Timestamp when the event was generated, as ' |
'number of\nmilliseconds since the Unix EPOCH.' |
@@ -121,6 +121,11 @@ def get_arguments(argv): |
'list of strings or json-encoded list of string. ' |
'Each one must be less than 20 characters long.') |
+ build_group.add_argument('--build-event-goma-stats-path', |
+ metavar='FILENAME', |
+ help='File containing a serialized GomaStats ' |
+ 'protobuf.') |
+ |
# Read events from file |
file_group = parser.add_argument_group('Read events from file') |
file_group.add_argument('--events-from-file', |
@@ -129,13 +134,23 @@ def get_arguments(argv): |
'option\nis incompatible with --build-event-type and' |
'\n--service-event-type.\nSee ' |
'send_event.read_events_from_file for details\n' |
- 'on the format. This options can be passed multiple\n' |
+ 'on the format. This option can be passed multiple\n' |
'times, and wildcards can be used.') |
file_group.add_argument('--delete-file-when-sent', |
action='store_true', default=False, |
help='If all events read from a file have been ' |
'successfully\nsent to the endpoint, delete the ' |
- 'file. By default\nfiles are kept.') |
+ 'file. By default\nfiles are kept. This does not ' |
+ 'affect the file pointed to by ' |
+ '--event-logrequest-path') |
+ |
+ file_group.add_argument('--event-logrequest-path', |
+ metavar='FILENAME', |
+ help='File containing a serialized LogRequestLite' |
+ 'proto, containing a single ChromeInfraEvent that ' |
+ 'will be used as the default event. Such a file can ' |
+ 'be generated by passing "file" to ' |
+ '--event-mon-run-type.') |
ts_mon.add_argparse_options(parser) |
event_mon.add_argparse_options(parser) |
@@ -173,10 +188,78 @@ def get_arguments(argv): |
return args |
+def _process_logrequest_path(args): |
+ """Sets the default event based on --event-logrequest-path. |
+ |
+ This function raises exceptions because if the base event is wrong, then it's |
+ not worth sending anything anyway. |
+ """ |
+ if args.event_logrequest_path: |
+ try: |
+ with open(args.event_logrequest_path, 'rb') as f: |
+ request = LogRequestLite.FromString(f.read()) |
+ |
+ if len(request.log_event) == 1: |
+ default_event = ChromeInfraEvent.FromString( |
+ request.log_event[0].source_extension) |
+ # Assume that the content is sane because we don't want to duplicate |
+ # any business logic here. |
+ # TODO(pgervais): find a better solution. |
+ event_mon.set_default_event(default_event) |
+ else: |
+ raise ValueError( |
+ 'Expected only one log_event in the LogRequestLite proto ' |
+ 'pointed by --event-logrequest-path. Found %d in %s', |
+ len(request.log_event), args.event_logrequest_path) |
+ except Exception: |
+ LOGGER.exception('Failure when reading/parsing file %s', |
+ args.event_logrequest_path) |
+ raise |
+ |
+ default_event = event_mon.get_default_event() |
+ |
+ # When the default event is set using --event-logrequest-path, passing |
+ # --build-event-type or --service-event-type is optional. These options |
+ # still takes precedence but they must keep the event type the same. |
+ if (default_event.build_event.HasField('type') and |
+ default_event.service_event.HasField('type')): |
+ msg = ('Default event contains both service_event_type and ' |
+ 'build_event_type which is incorrect. Make sure you passed ' |
+ 'a correct proto to --event-logrequest-path. Otherwise it\'s an ' |
+ 'internal error. Aborting.') |
+ LOGGER.error(msg) |
+ raise ValueError(msg) |
+ |
+ if default_event.build_event.HasField('type'): |
+ if args.service_event_type: |
+ msg = ('The default event contains a type for build_event, but a ' |
+ 'service_event type was provided on the command-line. At most ' |
+ 'one of them can be specified. Aborting.') |
+ LOGGER.error(msg) |
+ raise ValueError(msg) |
+ |
+ if not args.build_event_type: |
+ args.build_event_type = event_mon.BuildEvent.BuildEventType.Name( |
+ default_event.build_event.type) |
+ |
+ if default_event.service_event.HasField('type'): |
+ if args.build_event_type: |
+ msg = ('The default event contains a type for service_event, but a ' |
+ 'build_event type was provided on the command-line. At most ' |
+ 'one of them can be specified. Aborting.') |
+ LOGGER.error(msg) |
+ raise ValueError(msg) |
+ if not args.service_event_type: |
+ args.service_event_type = event_mon.ServiceEvent.ServiceEventType.Name( |
+ default_event.service_event.type) |
+ |
+ |
def process_argparse_options(args): # pragma: no cover |
infra_libs.logs.process_argparse_options(args) |
event_mon.process_argparse_options(args) |
+ # Put here because we want to send the presence metric as late as possible. |
ts_mon.process_argparse_options(args) |
+ _process_logrequest_path(args) |
def send_service_event(args): |
@@ -204,6 +287,16 @@ def send_service_event(args): |
def send_build_event(args): |
"""Entry point when --build-event-type is passed.""" |
+ goma_stats = None |
+ if args.build_event_goma_stats_path: |
+ try: |
+ with open(args.build_event_goma_stats_path, 'rb') as f: |
+ goma_stats = GomaStats.FromString(f.read()) |
+ except Exception: |
+ LOGGER.exception('Failure when reading/parsing file %s', |
+ args.build_event_goma_stats_path) |
+ raise |
+ |
return bool(event_mon.send_build_event( |
args.build_event_type, |
@@ -216,7 +309,8 @@ def send_build_event(args): |
result=args.build_event_result, |
extra_result_code=args.build_event_extra_result_code, |
timestamp_kind=args.event_mon_timestamp_kind, |
- event_timestamp=args.event_mon_event_timestamp)) |
+ event_timestamp=args.event_mon_event_timestamp, |
+ goma_stats=goma_stats)) |
def send_events_from_file(args): |