コード例 #1
0
    def TimeseriesData(self, **unused_args):
        """Returns data for the timeseries view in JSON format."""
        device_id = self.request.get('device_id')
        start_time = self.request.get('start_time')
        end_time = self.request.get('start_time')
        limit = self.request.get('limit')

        # Used to trigger permission check
        unused_device = model.DeviceInfo.GetDeviceWithAcl(device_id)
        if start_time:
            start_time = util.MicrosecondsSinceEpochToTime(int(start_time))
        if end_time:
            end_time = util.MicrosecondsSinceEpochToTime(int(end_time))
        if limit:
            limit = int(limit)

        measurements = model.Measurement.GetMeasurementListWithAcl(
            limit=limit,
            device_id=device_id,
            start_time=start_time,
            end_time=end_time)

        tsdata = []
        for meas in measurements:
            ms_time = util.TimeToMicrosecondsSinceEpoch(meas.timestamp) / 1000
            rssi = meas.device_properties.rssi or 0
            battery = meas.device_properties.battery_level or 0
            val = ('new Date(%d)' % ms_time, rssi, battery)
            tsdata.append(val)

        self.response.out.write(json.dumps(tsdata))
コード例 #2
0
    def TimeseriesData(self, **unused_args):
        """Returns data for the timeseries view in JSON format."""
        start_time = self.request.get('start_time')
        end_time = self.request.get('start_time')
        limit = self.request.get('limit')
        sample_type = self.request.get('type')

        summaries = model.ValidationSummary.all()

        if start_time:
            start_time = util.MicrosecondsSinceEpochToTime(int(start_time))
            summaries.filter('timestamp_start > ', start_time)
        if end_time:
            end_time = util.MicrosecondsSinceEpochToTime(int(end_time))
            summaries.filter('timestamp_end < ', end_time)
        if limit:
            limit = int(limit)
        else:
            limit = 1000

        summaries.filter('timestamp_start > ', 0)
        summaries.order('timestamp_start')
        time_to_type_to_count = dict()
        tsdata = []

        # group data by timestamp for timeline printing
        for summary in summaries.fetch(limit):
            ms_time = util.TimeToMicrosecondsSinceEpoch(
                summary.timestamp_start) / 1e3
            if not time_to_type_to_count.has_key(ms_time):
                time_to_type_to_count[ms_time] = dict()

            if sample_type:
                time_to_type_to_count[ms_time][summary.measurement_type] = \
                  getattr(summary, sample_type)
            else:                time_to_type_to_count[ms_time][summary.measurement_type] = \
            summary.record_count

        # gather data into timeline-friendly output format
        for time, type_to_count in time_to_type_to_count.items():
            row = ['new Date(%d)' % time]
            for meas, name in measurement.MEASUREMENT_TYPES:
                if type_to_count.has_key(meas):
                    row.append(type_to_count[meas])
                else:
                    row.append(0)
            tsdata.append(row)

        self.response.out.write(json.dumps(tsdata))
コード例 #3
0
    def Validate(self, **unused_args):
        """Main handler for the validation view.
    Note that this method is called from a request that is restricted to 
    admin privileges. 
      
    Args (HTTP request parameters):
      start_time: start time for validation period (ISO8601 format)
      end_time: end time for validation period (ISO8601 format)
      iters: (optional) Number of days to do bulk validation on. (int)
      use_webpage: (optional) Show validation results in HTML. If set to false, 
          send an e-mail with results. (boolean)
      worker: (optional) True if running as a queued task. (boolean)
  
    Returns:
      Result of validation, or nothing.
  
    Raises:
       No exceptions handled here.
       No new exceptions generated here.      
    
    """

        iters = self.request.get('iters')
        start_time = self.request.get('start_time')
        end_time = self.request.get('end_time')

        # if iterating, set up and enqueue validation tasks
        while iters and int(iters) > 1:
            start_time = 24 * 60 * 60 * 1000 * 1000 + \
                util.TimeToMicrosecondsSinceEpoch(util.StringToTime(start_time))
            start_time = util.MicrosecondsSinceEpochToTime(start_time)
            start_time = util.TimeToString(start_time)
            end_time = 24 * 60 * 60 * 1000 * 1000 + \
                util.TimeToMicrosecondsSinceEpoch(util.StringToTime(end_time))

            end_time = util.MicrosecondsSinceEpochToTime(end_time)
            end_time = util.TimeToString(end_time)
            # Add the task to the 'validation' queue.
            taskqueue.add(
                url='/validation/data?worker=true&start_time=%s&end_time=%s' %
                (start_time, end_time),
                method='GET',
                queue_name='validation')
            iters = int(iters) - 1

        # return here if iterating using task queue
        if iters:
            self.response.out.write("{Success:true}")
            return

        # contains validation results for printing
        self.validation_results = dict()

        # support only the measurements specified in MEASUREMENT_TYPES
        for mtype, name in measurement.MEASUREMENT_TYPES:
            self.type_to_summary[mtype] = \
               model.ValidationSummary(measurement_type=mtype)
            self.type_to_details[mtype] = []

        # validate all the data in one pass
        self._DoValidation()

        # validation results are in type_to_details, now write them to datastore
        for mtype, data in self.type_to_summary.items():
            data.put(
            )  # must put summary before putting details that reference them
            if self.type_to_details.has_key(mtype):
                for detail in self.type_to_details[mtype]:
                    detail.summary = data
                    detail.put()

        # if this was a queued task, return here
        if self.request.get('worker'):
            self.response.out.write("{Success:true}")
            return

        # for display purposes, render HTML of results
        html = template.render('templates/validation.html',
                               self.validation_results)

        # send to response, or e-mail user
        if self.request.get('use_webpage'):
            self.response.out.write(html)
        else:
            message = mail.EmailMessage(sender=config.VALIDATION_EMAIL_SENDER,
                                        subject="Daily validation results")
            message.to = config.VALIDATION_EMAIL_RECIPIENT
            message.body = html
            message.html = html
            message.send()
コード例 #4
0
    def _DoValidation(self):
        """Gets all the records for a specified type, subject
    to request parameters. 
      
    Args:
      None. This reads from the measurement request
  
    Returns:
      Nothing. It writes results to an instance variable.
  
    Raises:
       No exceptions handled here.
       No new exceptions generated here.      
    
    """
        start_time = self.request.get('start_time')
        end_time = self.request.get('end_time')
        limit = self.request.get('limit')

        # manually specified parameters for testing
        if self.TESTING:
            limit = 100
            start_time = util.TimeToMicrosecondsSinceEpoch(
                util.StringToTime("2012-03-20T00:00:00Z"))
            end_time = util.TimeToMicrosecondsSinceEpoch(
                util.StringToTime("2012-03-21T00:00:00Z"))

        # set up query filters according to parameters
        query = model.Measurement.all()

        if start_time:
            dt_start = util.TimeToMicrosecondsSinceEpoch(
                util.StringToTime(start_time))
        else:
            dt_start = util.TimeToMicrosecondsSinceEpoch(
                datetime.datetime.utcfromtimestamp(time.time()) -
                datetime.timedelta(days=1))
        self.validation_results['start_time'] = \
           util.MicrosecondsSinceEpochToTime(dt_start)
        query.filter('timestamp >=', dt_start)

        if end_time:
            dt = util.TimeToMicrosecondsSinceEpoch(util.StringToTime(end_time))
        else:
            dt = util.TimeToMicrosecondsSinceEpoch(
                datetime.datetime.utcfromtimestamp(time.time()))
        self.validation_results[
            'end_time'] = util.MicrosecondsSinceEpochToTime(dt)

        query.filter('timestamp <', dt)
        query.order('timestamp')
        if limit:
            results = query.fetch(int(limit))
        else:
            results = query

        error_type_to_count = dict()  # map of error type to count
        num_invalid = dict()  # map of measurement type to count of invalid

        for measurement in results:
            # Need to catch case where device has been deleted
            try:
                unused_device_info = measurement.device_properties.device_info
            except db.ReferencePropertyResolveError:
                logging.exception('Device deleted for measurement %s',
                                  measurement.key().id())
                # Skip this measurement
                continue

            # catch case where measurement is not supported
            if not self.type_to_summary.has_key(measurement.type):
                self.type_to_summary[measurement.type] = \
                 model.ValidationSummary(measurement_type=measurement.type,
                                         error="UnknownType")

            # set initial data for validation summary
            if not self.type_to_summary[measurement.type].timestamp_start:
                self.type_to_summary[measurement.type].timestamp_start = \
                    util.MicrosecondsSinceEpochToTime(dt_start)
                self.type_to_summary[measurement.type].timestamp_end = \
                    util.MicrosecondsSinceEpochToTime(dt)
                self.type_to_summary[measurement.type].record_count = 1
                self.type_to_summary[measurement.type].error_count = 0
                num_invalid[measurement.type] = 0
            else:
                self.type_to_summary[measurement.type].record_count += 1

            # Make a measurement-specific validation object
            try:
                validator = MeasurementValidatorFactory.CreateValidator(
                    measurement)
            except RuntimeError:
                continue  # no validator defined, continue

            valid = validator.Validate()
            if not valid['valid']:
                if not num_invalid.has_key(measurement.type):
                    num_invalid[measurement.type] = 0
                num_invalid[measurement.type] += 1

            # print the error details
            if self.PRINT_VALUES or (self.PRINT_INVALID
                                     and not valid['valid']):
                if not self.validation_results.has_key(
                        '%s_invalid_detail' % measurement.type):
                    self.validation_results['%s_invalid_detail' %
                                            measurement.type] = []
                self.validation_results[
                    '%s_invalid_detail' % measurement.type].append(
                        'Errors: %s <br>\nTime: %s<br>\nDevice: %s<br>\nDetails: %s'
                        % (", ".join(
                            valid['error_types']), str(measurement.timestamp),
                           measurement.device_properties.device_info.id,
                           validator.PrintData()))

                # update error counters
                for error in valid['error_types']:
                    if not error_type_to_count.has_key(measurement.type):
                        error_type_to_count[measurement.type] = dict()
                    if not error_type_to_count[measurement.type].has_key(
                            error):
                        error_type_to_count[measurement.type][error] = 1
                    else:
                        error_type_to_count[measurement.type][error] += 1

                # create ValidationEntry for each error
                if len(valid['error_types']) > 0:
                    error_detail = model.ValidationEntry()
                    #error_detail.summary = self.type_to_summary[measurement.type]
                    error_detail.measurement = measurement
                    error_detail.error_types = valid['error_types']
                    self.type_to_details[measurement.type].append(error_detail)

            # update number of invalid measurements
            self.validation_results['%s_invalid' % measurement.type] = \
              num_invalid[measurement.type]

        # update validation summary entity for each data type
        for data_type in self.type_to_summary.keys():
            if num_invalid.has_key(data_type):
                self.type_to_summary[data_type].error_count = num_invalid[
                    data_type]
            if error_type_to_count.has_key(data_type):
                self.type_to_summary[data_type].SetErrorByType(
                    error_type_to_count[data_type])

            self.validation_results[data_type + "_count"] = \
              self.type_to_summary[data_type].record_count