| Index: appengine_module/gae_ts_mon/interface.py
|
| diff --git a/appengine_module/gae_ts_mon/interface.py b/appengine_module/gae_ts_mon/interface.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9cdeb0cce0d37b96dc20f18c07fa82f89edf5420
|
| --- /dev/null
|
| +++ b/appengine_module/gae_ts_mon/interface.py
|
| @@ -0,0 +1,129 @@
|
| +# Copyright 2015 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""Classes representing the monitoring interface for tasks or devices.
|
| +
|
| +Usage:
|
| + # symlink appengine/modules/gae_ts_mon into the top level directory
|
| + # of your appengine app
|
| +
|
| + import gae_ts_mon
|
| + from google.appengine.api import modules
|
| +
|
| + # Sets up default target
|
| + instance_id = hash(modules.get_current_instance_id()) % 10
|
| + gae_ts_mon.initialize(job_name='job', instance=instance_id,
|
| + service_name='service', endpoint='endpoint')
|
| +
|
| + # Will use the default Target set up with initialize
|
| + count_metric = gae_ts_mon.CounterMetric('my/metric/name', fields={})
|
| + count_metric.set(0)
|
| + for x in range(100):
|
| + count_metric.increment()
|
| +
|
| + # Use a custom Target:
|
| + t = ts_mon.TaskTarget('service', 'job', 'region', 'host')
|
| + g_metric = ts_mon.GaugeMetric('/my/metric/name2',
|
| + fields={'key': 'value'},
|
| + target=t)
|
| + g_metric.set(5)
|
| +
|
| + # Flush (sends metrics to monarch, already done automatically every 5m)
|
| + gae_ts_mon.flush()
|
| +
|
| +"""
|
| +
|
| +import logging
|
| +import os
|
| +import random
|
| +import time
|
| +
|
| +from monacq.proto import metrics_pb2
|
| +
|
| +from common import errors
|
| +
|
| +# The maximum number of MetricsData messages to include in each HTTP request.
|
| +# MetricsCollections larger than this will be split into multiple requests.
|
| +METRICS_DATA_LENGTH_LIMIT = 1000
|
| +
|
| +
|
| +class State(object):
|
| + """Package-level state is stored here so that it is easily accessible.
|
| +
|
| + Configuration is kept in this one object at the global level so that all
|
| + libraries in use by the same tool or service can all take advantage of the
|
| + same configuration.
|
| + """
|
| +
|
| + def __init__(self):
|
| + # The Monitor object that will be used to send all metrics.
|
| + self.global_monitor = None
|
| + # The Target object that will be paired with all metrics that don't supply
|
| + # their own.
|
| + self.default_target = None
|
| + # The flush mode being used to control when metrics are pushed.
|
| + self.flush_mode = None
|
| + # All metrics created by this application.
|
| + self.metrics = set()
|
| +
|
| +state = State()
|
| +
|
| +
|
| +def send(metric):
|
| + """Send a single metric to the monitoring api.
|
| +
|
| + This is called automatically by Metric.set - you don't need to call it
|
| + manually.
|
| + """
|
| + if state.flush_mode != 'all':
|
| + return
|
| +
|
| + if not state.global_monitor:
|
| + raise errors.MonitoringNoConfiguredMonitorError(metric._name)
|
| +
|
| + proto = metrics_pb2.MetricsCollection()
|
| + metric.serialize_to(proto, default_target=state.default_target)
|
| + state.global_monitor.send(proto)
|
| +
|
| +
|
| +def flush():
|
| + """Send all metrics that are registered in the application."""
|
| + if not state.global_monitor:
|
| + raise errors.MonitoringNoConfiguredMonitorError(None)
|
| +
|
| + proto = metrics_pb2.MetricsCollection()
|
| +
|
| + def loop_action(proto):
|
| + if len(proto.data) >= METRICS_DATA_LENGTH_LIMIT:
|
| + state.global_monitor.send(proto)
|
| + del proto.data[:]
|
| +
|
| + for metric in state.metrics:
|
| + metric.serialize_to(proto, default_target=state.default_target,
|
| + loop_action=loop_action)
|
| +
|
| + state.global_monitor.send(proto)
|
| +
|
| +
|
| +def register(metric):
|
| + """Adds the metric to the list of metrics sent by flush().
|
| +
|
| + This is called automatically by Metric's constructor.
|
| + """
|
| + # If someone is registering the same metric object twice, that's okay, but
|
| + # registering two different metric objects with the same metric name is not.
|
| + for m in state.metrics:
|
| + if metric == m:
|
| + state.metrics.remove(m)
|
| + state.metrics.add(metric)
|
| + return
|
| + if any([metric._name == m._name for m in state.metrics]):
|
| + raise errors.MonitoringDuplicateRegistrationError(metric._name)
|
| +
|
| + state.metrics.add(metric)
|
| +
|
| +
|
| +def unregister(metric):
|
| + """Removes the metric from the list of metrics sent by flush()."""
|
| + state.metrics.remove(metric)
|
|
|