Exemple #1
0
    def __record_change_metric_in_datadog(self, metric, change, processor=None, processing_time=None,
                                          add_case_type_tag=False):
        if change.metadata is not None:
            common_tags = {
                'datasource': change.metadata.data_source_name,
                'is_deletion': change.metadata.is_deletion,
                'pillow_name': self.get_name(),
                'processor': processor.__class__.__name__ if processor else "all_processors",
            }

            metric_tags = common_tags.copy()
            if add_case_type_tag and settings.ENTERPRISE_MODE and change.metadata.document_type == 'CommCareCase':
                metric_tags['case_type'] = change.metadata.document_subtype

            metrics_counter(metric, tags=metric_tags)

            change_lag = (datetime.utcnow() - change.metadata.publish_timestamp).total_seconds()
            metrics_gauge('commcare.change_feed.change_lag', change_lag, tags={
                'pillow_name': self.get_name(),
                'topic': _topic_for_ddog(
                    TopicPartition(change.topic, change.partition)
                    if change.partition is not None else change.topic
                ),
            })

            if processing_time:
                metrics_counter('commcare.change_feed.processing_time.total', processing_time, tags=common_tags)
                metrics_counter('commcare.change_feed.processing_time.count', tags=common_tags)
Exemple #2
0
def send_unknown_user_type_stats():
    metrics_gauge('commcare.fix_user_types.unknown_user_count',
                  _get_unknown_user_type_user_ids_approx_count(),
                  multiprocess_mode=MPM_MAX)
    metrics_gauge('commcare.fix_user_types.unknown_user_form_count',
                  FormES().user_type(UNKNOWN_USER_TYPE).count(),
                  multiprocess_mode=MPM_MAX)
Exemple #3
0
def _send_form_to_hubspot(form_id, webuser, hubspot_cookie, meta, extra_fields=None, email=False):
    """
    This sends hubspot the user's first and last names and tracks everything they did
    up until the point they signed up.
    """
    if ((webuser and not hubspot_enabled_for_user(webuser))
            or (not webuser and not hubspot_enabled_for_email(email))):
        # This user has analytics disabled
        metrics_gauge(
            'commcare.hubspot_data.rejected.send_form_to_hubspot',
            1,
            tags={
                'username': webuser.username if webuser else email,
            }
        )
        return

    hubspot_id = settings.ANALYTICS_IDS.get('HUBSPOT_API_ID')
    if hubspot_id and hubspot_cookie:
        data = {
            'email': email if email else webuser.username,
            'hs_context': json.dumps({"hutk": hubspot_cookie, "ipAddress": _get_client_ip(meta)}),
        }
        if webuser:
            data.update({
                'firstname': webuser.first_name,
                'lastname': webuser.last_name,
            })
        if extra_fields:
            data.update(extra_fields)

        response = _send_hubspot_form_request(hubspot_id, form_id, data)
        _log_response('HS', data, response)
        response.raise_for_status()
Exemple #4
0
def gauge_pending_user_confirmations():
    metric_name = 'commcare.pending_user_confirmations'
    from corehq.apps.users.models import Invitation
    for stats in (Invitation.objects.filter(is_accepted=False).all()
                  .values('domain').annotate(Count('domain'))):
        metrics_gauge(
            metric_name, stats['domain__count'], tags={
                'domain': stats['domain'],
                'user_type': 'web',
            },
            multiprocess_mode=MPM_MAX
        )

    from corehq.apps.users.analytics import get_inactive_commcare_users_in_domain
    for doc in Domain.get_all(include_docs=False):
        domain_name = doc['key']
        users = get_inactive_commcare_users_in_domain(domain_name)
        num_unconfirmed = sum(1 for u in users if not u.is_account_confirmed)
        if num_unconfirmed:
            metrics_gauge(
                metric_name, num_unconfirmed, tags={
                    'domain': domain_name,
                    'user_type': 'mobile',
                },
                multiprocess_mode=MPM_MAX
            )
Exemple #5
0
def reprocess_archive_stubs():
    # Check for archive stubs
    from corehq.form_processor.models import XFormInstance
    from couchforms.models import UnfinishedArchiveStub
    stubs = UnfinishedArchiveStub.objects.filter(attempts__lt=3)
    metrics_gauge('commcare.unfinished_archive_stubs', len(stubs),
        multiprocess_mode=MPM_MAX)
    start = time.time()
    cutoff = start + timedelta(minutes=4).total_seconds()
    for stub in stubs:
        # Exit this task after 4 minutes so that tasks remain short
        if time.time() > cutoff:
            return
        try:
            xform = XFormInstance.objects.get_form(stub.xform_id, stub.domain)
            # If the history wasn't updated the first time around, run the whole thing again.
            if not stub.history_updated:
                XFormInstance.objects.do_archive(xform, stub.archive, stub.user_id, trigger_signals=True)

            # If the history was updated the first time around, just send the update to kafka
            else:
                XFormInstance.objects.publish_archive_action_to_kafka(xform, stub.user_id, stub.archive)
        except Exception:
            # Errors should not prevent processing other stubs
            notify_exception(None, "Error processing UnfinishedArchiveStub")
Exemple #6
0
def get_valid_recipients(recipients, domain=None):
    """
    This filters out any emails that have reported hard bounces or complaints to
    Amazon SES
    :param recipients: list of recipient emails
    :return: list of recipient emails not marked as bounced
    """
    from corehq.toggles import BLOCKED_DOMAIN_EMAIL_SENDERS
    if domain and BLOCKED_DOMAIN_EMAIL_SENDERS.enabled(domain):
        # don't sent email if domain is blocked
        metrics_gauge('commcare.bounced_email', len(recipients), tags={
            'email_domain': domain,
        }, multiprocess_mode=MPM_LIVESUM)
        return []

    from corehq.util.models import BouncedEmail
    bounced_emails = BouncedEmail.get_hard_bounced_emails(recipients)
    for bounced_email in bounced_emails:
        try:
            email_domain = bounced_email.split('@')[1]
        except IndexError:
            email_domain = bounced_email
        metrics_gauge('commcare.bounced_email', 1, tags={
            'email_domain': email_domain,
        }, multiprocess_mode=MPM_LIVESUM)
    return [recipient for recipient in recipients if recipient not in bounced_emails]
Exemple #7
0
    def _record_datadog_metrics(self, changes_chunk, processing_time):
        tags = {"pillow_name": self.get_name(), "mode": "chunked"}
        change_count = len(changes_chunk)
        if settings.ENTERPRISE_MODE:
            type_counter = Counter([
                change.metadata.document_subtype
                for change in changes_chunk if change.metadata.document_type == 'CommCareCase'
            ])
            for case_type, type_count in type_counter.items():
                metrics_counter('commcare.change_feed.changes.count', type_count,
                                tags={**tags, 'case_type': case_type})

            remainder = change_count - sum(type_counter.values())
            if remainder:
                metrics_counter('commcare.change_feed.changes.count', remainder, tags=tags)
        else:
            metrics_counter('commcare.change_feed.changes.count', change_count, tags=tags)

        max_change_lag = (datetime.utcnow() - changes_chunk[0].metadata.publish_timestamp).total_seconds()
        min_change_lag = (datetime.utcnow() - changes_chunk[-1].metadata.publish_timestamp).total_seconds()
        metrics_gauge('commcare.change_feed.chunked.min_change_lag', min_change_lag, tags=tags)
        metrics_gauge('commcare.change_feed.chunked.max_change_lag', max_change_lag, tags=tags)

        # processing_time per change
        metrics_counter('commcare.change_feed.processing_time.total', processing_time / change_count, tags=tags)
        metrics_counter('commcare.change_feed.processing_time.count', tags=tags)
Exemple #8
0
def datadog_report_user_stats(metric_name, commcare_users_by_domain):
    commcare_users_by_domain = summarize_user_counts(commcare_users_by_domain,
                                                     n=50)
    for domain, user_count in commcare_users_by_domain.items():
        metrics_gauge(metric_name,
                      user_count,
                      tags={'domain': '_other' if domain is () else domain})
Exemple #9
0
def _get_contact_ids_for_email_domain(email_domain):
    """
    Searches Hubspot for an email domain and returns the list of matching
    contact IDs for that email domain.
    :param email_domain:
    :return: list of matching contact IDs
    """
    api_key = settings.ANALYTICS_IDS.get('HUBSPOT_API_KEY', None)
    if api_key:
        req = requests.get(
            "https://api.hubapi.com/contacts/v1/search/query",
            params={
                'hapikey': api_key,
                'q': f'@{email_domain}',
            },
        )
        if req.status_code == 200:
            return [
                contact.get('vid') for contact in req.json().get('contacts')
            ]
        if req.status_code == 429:
            metrics_gauge(
                'commcare.hubspot_data.rate_limited.get_contact_ids_for_email_domain',
                1)
    return []
def _report_current_global_two_factor_setup_rate_limiter():
    for window, value, threshold in global_two_factor_setup_rate_limiter.iter_rates():
        metrics_gauge('commcare.two_factor.global_two_factor_setup_threshold', threshold, tags={
            'window': window
        }, multiprocess_mode=MPM_MAX)
        metrics_gauge('commcare.two_factor.global_two_factor_setup_usage', value, tags={
            'window': window
        }, multiprocess_mode=MPM_MAX)
def _report_current_global_submission_thresholds():
    for window, value, threshold in global_submission_rate_limiter.iter_rates(
    ):
        metrics_gauge('commcare.xform_submissions.global_threshold',
                      threshold,
                      tags={'window': window})
        metrics_gauge('commcare.xform_submissions.global_usage',
                      value,
                      tags={'window': window})
Exemple #12
0
def cleanup_blocked_hubspot_contacts():
    """
    Remove any data stored about users from blocked domains and email domains
    from Hubspot in case it somehow got there.
    :return:
    """
    if not HUBSPOT_ENABLED:
        return

    # First delete any user information from users that are members of
    # blocked domains
    blocked_domains = get_blocked_hubspot_domains()
    for domain in blocked_domains:
        user_query = UserES().domain(domain).source(['email', 'username'])

        total_users = user_query.count()
        chunk_size = 30  # Hubspot recommends fewer than 100 emails per request
        num_chunks = int(math.ceil(float(total_users) / float(chunk_size)))

        for chunk in range(num_chunks):
            blocked_users = (user_query
                             .size(chunk_size)
                             .start(chunk * chunk_size)
                             .run()
                             .hits)
            blocked_emails = []
            for user in blocked_users:
                username = user.get('username')
                user_email = user.get('email')
                blocked_emails.append(username)
                if user_email and user_email != username:
                    blocked_emails.append(user_email)
            ids_to_delete = _get_contact_ids_for_emails(set(blocked_emails))
            num_deleted = sum(_delete_hubspot_contact(vid) for vid in ids_to_delete)
            metrics_gauge(
                'commcare.hubspot_data.deleted_user.blocked_domain',
                num_deleted,
                tags={
                    'domain': domain,
                    'ids_deleted': ids_to_delete,
                }
            )

    # Next delete any user info from users that have emails or usernames ending
    # in blocked email-domains
    blocked_email_domains = get_blocked_hubspot_email_domains()
    for email_domain in blocked_email_domains:
        ids_to_delete = _get_contact_ids_for_email_domain(email_domain)
        num_deleted = sum(_delete_hubspot_contact(vid) for vid in ids_to_delete)
        metrics_gauge(
            'commcare.hubspot_data.deleted_user.blocked_email_domain',
            num_deleted,
            tags={
                'email_domain': email_domain,
                'ids_deleted': ids_to_delete,
            }
        )
Exemple #13
0
 def _record_checkpoint_in_datadog(self):
     metrics_counter('commcare.change_feed.change_feed.checkpoint', tags={
         'pillow_name': self.get_name(),
     })
     checkpoint_sequence = self._normalize_checkpoint_sequence()
     for topic, value in checkpoint_sequence.items():
         metrics_gauge('commcare.change_feed.checkpoint_offsets', value, tags={
             'pillow_name': self.get_name(),
             'topic': _topic_for_ddog(topic),
         })
def record_pillow_error_queue_size():
    data = PillowError.objects.values('pillow').annotate(
        num_errors=Count('id'))
    for row in data:
        metrics_gauge('commcare.pillowtop.error_queue',
                      row['num_errors'],
                      tags={
                          'pillow_name': row['pillow'],
                          'host': 'celery',
                          'group': 'celery'
                      })
Exemple #15
0
 def get_and_report_blockage_duration(self):
     blockage_duration = self.get_blockage_duration()
     metrics_gauge('commcare.celery.heartbeat.blockage_duration',
                   blockage_duration.total_seconds(),
                   tags={'celery_queue': self.queue})
     if self.threshold:
         metrics_gauge(
             'commcare.celery.heartbeat.blockage_ok',
             1
             if blockage_duration.total_seconds() <= self.threshold else 0,
             tags={'celery_queue': self.queue})
     return blockage_duration
Exemple #16
0
def track_es_doc_counts():
    es = get_es_new()
    stats = es.indices.stats(level='shards', metric='docs')
    for name, data in stats['indices'].items():
        for number, shard in data['shards'].items():
            for i in shard:
                if i['routing']['primary']:
                    tags = {
                        'index': name,
                        'shard': f'{name}_{number}',
                    }
                    metrics_gauge('commcare.elasticsearch.shards.docs.count', i['docs']['count'], tags)
                    metrics_gauge('commcare.elasticsearch.shards.docs.deleted', i['docs']['deleted'], tags)
Exemple #17
0
def server_up(req):
    """
    Health check view which can be hooked into server monitoring tools like 'pingdom'

    Returns:
        HttpResponse("success", status_code=200)
        HttpResponse(error_message, status_code=500)

    Hit serverup.txt to check all the default enabled services (always_check=True)
    Hit serverup.txt?only={check_name} to only check a specific service
    Hit serverup.txt?{check_name} to include a non-default check (currently only ``heartbeat``)
    """
    only = req.GET.get('only', None)
    if only and only in CHECKS:
        checks_to_do = [only]
    else:
        checks_to_do = [
            check for check, check_info in CHECKS.items() if
            check_info['always_check'] or req.GET.get(check, None) is not None
        ]

    statuses = run_checks(checks_to_do)
    failed_checks = [(check, status) for check, status in statuses
                     if not status.success]

    for check_name, status in statuses:
        tags = {
            'status': 'failed' if not status.success else 'ok',
            'check': check_name
        }
        metrics_gauge('commcare.serverup.check',
                      status.duration,
                      tags=tags,
                      multiprocess_mode=MPM_MAX)

    if failed_checks and not is_deploy_in_progress():
        status_messages = [
            html.linebreaks('<strong>{}</strong>: {}'.format(
                check, html.escape(status.msg)).strip())
            for check, status in failed_checks
        ]
        create_metrics_event(
            'Serverup check failed',
            '\n'.join(status_messages),
            alert_type='error',
            aggregation_key='serverup',
        )
        status_messages.insert(0, 'Failed Checks (%s):' % os.uname()[1])
        return HttpResponse(''.join(status_messages), status=500)
    else:
        return HttpResponse("success")
    def _record_datadog_metrics(self, changes_chunk, processing_time):
        change_count = len(changes_chunk)
        by_data_source = defaultdict(list)
        for change in changes_chunk:
            by_data_source[change.metadata.data_source_name].append(change)
        for data_source, changes in by_data_source.items():
            tags = {"pillow_name": self.get_name(), 'datasource': data_source}
            if settings.ENTERPRISE_MODE:
                type_counter = Counter([
                    change.metadata.document_subtype
                    for change in changes_chunk
                    if change.metadata.document_type == 'CommCareCase'
                ])
                for case_type, type_count in type_counter.items():
                    metrics_counter('commcare.change_feed.changes.count',
                                    type_count,
                                    tags={
                                        **tags, 'case_type': case_type
                                    })

                remainder = change_count - sum(type_counter.values())
                if remainder:
                    metrics_counter('commcare.change_feed.changes.count',
                                    remainder,
                                    tags={
                                        **tags, 'case_type': 'NA'
                                    })
            else:
                metrics_counter('commcare.change_feed.changes.count',
                                change_count,
                                tags={
                                    **tags, 'case_type': 'NA'
                                })

        tags = {"pillow_name": self.get_name()}
        max_change_lag = (
            datetime.utcnow() -
            changes_chunk[0].metadata.publish_timestamp).total_seconds()
        metrics_gauge('commcare.change_feed.chunked.max_change_lag',
                      max_change_lag,
                      tags=tags,
                      multiprocess_mode=MPM_MAX)

        # processing_time per change
        metrics_counter('commcare.change_feed.processing_time.total',
                        processing_time / change_count,
                        tags=tags)
        metrics_counter('commcare.change_feed.processing_time.count',
                        tags=tags)
Exemple #19
0
def track_pg_limits():
    for db in settings.DATABASES:
        with connections[db].cursor() as cursor:
            query = """
            select tab.relname, seq.relname
              from pg_class seq
              join pg_depend as dep on seq.oid=dep.objid
              join pg_class as tab on dep.refobjid = tab.oid
              join pg_attribute as att on att.attrelid=tab.oid and att.attnum=dep.refobjsubid
              where seq.relkind='S' and att.attlen=4
            """
            cursor.execute(query)
            results = cursor.fetchall()
            for table, sequence in results:
                cursor.execute(f'select last_value from "{sequence}"')
                current_value = cursor.fetchone()[0]
                metrics_gauge('commcare.postgres.sequence.current_value', current_value, {'table': table, 'database': db})
Exemple #20
0
def pillow_datadog_metrics():
    def _is_couch(pillow):
        # text is couch, json is kafka
        return pillow['seq_format'] == 'text'

    pillow_meta = get_all_pillows_json()
    for pillow in pillow_meta:
        # The host and group tags are added here to ensure they remain constant
        # regardless of which celery worker the task get's executed on.
        # Without this the sum of the metrics get's inflated.
        tags = {
            'pillow_name': pillow['name'],
            'feed_type': 'couch' if _is_couch(pillow) else 'kafka',
            'host': 'celery',
            'group': 'celery'
        }

        metrics_gauge('commcare.change_feed.seconds_since_last_update',
                      pillow['seconds_since_last'],
                      tags=tags,
                      multiprocess_mode=MPM_MIN)

        for topic_name, offset in pillow['offsets'].items():
            if _is_couch(pillow):
                tags_with_topic = {**tags, 'topic': topic_name}
                processed_offset = pillow['seq']
            else:
                if not pillow['seq']:
                    # this pillow has never been initialized.
                    # (custom pillows on most environments)
                    continue
                topic, partition = topic_name.split(',')
                tags_with_topic = {
                    **tags, 'topic': '{}-{}'.format(topic, partition)
                }
                processed_offset = pillow['seq'][topic_name]

            if processed_offset == 0:
                # assume if nothing has been processed that this pillow is not
                # supposed to be running
                continue

            metrics_gauge('commcare.change_feed.current_offsets',
                          offset,
                          tags=tags_with_topic,
                          multiprocess_mode=MPM_MAX)
            metrics_gauge('commcare.change_feed.processed_offsets',
                          processed_offset,
                          tags=tags_with_topic,
                          multiprocess_mode=MPM_MAX)
            needs_processing = offset - processed_offset
            metrics_gauge('commcare.change_feed.need_processing',
                          needs_processing,
                          tags=tags_with_topic,
                          multiprocess_mode=MPM_MAX)
Exemple #21
0
def cleanup_blocked_hubspot_contacts():
    """
    Remove any data stored about users from blocked domains and email domains
    from Hubspot in case it somehow got there.
    :return:
    """
    if not HUBSPOT_ENABLED:
        return

    time_started = datetime.utcnow()

    remove_blocked_domain_contacts_from_hubspot()
    remove_blocked_domain_invited_users_from_hubspot()

    task_time = datetime.utcnow() - time_started
    metrics_gauge('commcare.hubspot.runtimes.cleanup_blocked_hubspot_contacts',
                  task_time.seconds,
                  multiprocess_mode=MPM_LIVESUM)
Exemple #22
0
def cleanup_stale_es_on_couch_domains(start_date=None,
                                      end_date=None,
                                      domains=None,
                                      stdout=None):
    """
    This is the response to https://dimagi-dev.atlassian.net/browse/SAAS-11489
    and basically makes sure that there are no stale docs in the most active
    domains still using the couch db backend until we can get them migrated.
    """
    end = end_date or datetime.datetime.utcnow()
    start = start_date or (end - datetime.timedelta(days=2))

    couch_domains = domains or ACTIVE_COUCH_DOMAINS.get_enabled_domains()

    for domain in couch_domains:
        form_ids, has_discrepancies = _get_all_form_ids(domain, start, end)
        if stdout:
            stdout.write(f"Found {len(form_ids)} in {domain} for between "
                         f"{start.isoformat()} and {end.isoformat()}.")
        if has_discrepancies:
            metrics_gauge(
                'commcare.es.couch_domain.couch_discrepancy_detected',
                1,
                tags={
                    'domain': domain,
                })
            if stdout:
                stdout.write(
                    f"\tFound discrepancies in form counts for domain {domain}"
                )
        forms_not_in_es = _get_forms_not_in_es(form_ids)
        if forms_not_in_es:
            metrics_gauge('commcare.es.couch_domain.stale_docs_in_es',
                          len(forms_not_in_es),
                          tags={
                              'domain': domain,
                          })
            if stdout:
                stdout.write(f"\tFound {len(forms_not_in_es)} forms not in es "
                             f"for {domain}")
            changes = _get_changes(domain, forms_not_in_es)
            form_es_processor = get_xform_pillow().processors[0]
            for change in changes:
                form_es_processor.process_change(change)
Exemple #23
0
def _get_user_hubspot_id(web_user):
    api_key = settings.ANALYTICS_IDS.get('HUBSPOT_API_KEY', None)
    if api_key and hubspot_enabled_for_user(web_user):
        req = requests.get(
            "https://api.hubapi.com/contacts/v1/contact/email/{}/profile".
            format(six.moves.urllib.parse.quote(web_user.username)),
            params={'hapikey': api_key},
        )
        if req.status_code == 404:
            return None
        req.raise_for_status()
        return req.json().get("vid", None)
    elif api_key:
        metrics_gauge('commcare.hubspot_data.rejected.get_user_hubspot_id',
                      1,
                      tags={
                          'username': web_user.username,
                      })
    return None
Exemple #24
0
def generate_partner_reports():
    """
    Generates analytics reports for partners that have requested tracking on
    specific data points.
    :return:
    """
    time_started = datetime.utcnow()

    last_month = add_months_to_date(datetime.today(), -1)
    year = last_month.year
    month = last_month.month
    generate_monthly_mobile_worker_statistics(year, month)
    generate_monthly_web_user_statistics(year, month)
    generate_monthly_submissions_statistics(year, month)
    send_partner_emails(year, month)

    task_time = datetime.utcnow() - time_started
    metrics_gauge('commcare.analytics.runtimes.generate_partner_reports',
                  task_time.seconds,
                  multiprocess_mode=MPM_LIVESUM)
Exemple #25
0
def _delete_hubspot_contact(vid):
    """
    Permanently deletes a Hubspot contact.
    :param vid:  (the contact ID)
    :return: boolean if contact was deleted
    """
    api_key = settings.ANALYTICS_IDS.get('HUBSPOT_API_KEY', None)
    if api_key:

        req = requests.delete(
            f'https://api.hubapi.com/contacts/v1/contact/vid/{vid}',
            params={
                'hapikey': api_key,
            })
        if req.status_code == 200:
            return True
        if req.status_code == 429:
            metrics_gauge(
                'commcare.hubspot_data.rate_limited.delete_hubspot_contact', 1)
    return False
    def __record_change_metric_in_datadog(self,
                                          metric,
                                          change,
                                          processing_time=None,
                                          add_case_type_tag=False):
        if change.metadata is not None:
            metric_tags = {
                'datasource': change.metadata.data_source_name,
                'pillow_name': self.get_name(),
            }

            if add_case_type_tag:
                metric_tags['case_type'] = 'NA'
                if settings.ENTERPRISE_MODE and change.metadata.document_type == 'CommCareCase':
                    metric_tags['case_type'] = change.metadata.document_subtype

            metrics_counter(metric, tags=metric_tags)

            change_lag = (datetime.utcnow() -
                          change.metadata.publish_timestamp).total_seconds()
            metrics_gauge(
                'commcare.change_feed.change_lag',
                change_lag,
                tags={
                    'pillow_name':
                    self.get_name(),
                    'topic':
                    _topic_for_ddog(
                        TopicPartition(change.topic, change.partition)
                        if change.partition is not None else change.topic),
                },
                multiprocess_mode=MPM_MAX)

            if processing_time:
                tags = {'pillow_name': self.get_name()}
                metrics_counter('commcare.change_feed.processing_time.total',
                                processing_time,
                                tags=tags)
                metrics_counter('commcare.change_feed.processing_time.count',
                                tags=tags)
def delete_old_images_on_db(db_name, cutoff):
    if isinstance(cutoff, str):
        cutoff = parse_date(cutoff, default_timezone=None)

    max_age = cutoff - timedelta(days=90)
    db = get_blob_db()

    def _get_query(db_name, max_age=max_age):
        return BlobMeta.objects.using(db_name).filter(
            type_code=CODES.form_attachment,
            domain='icds-cas',
            created_on__lt=max_age).order_by('created_on')

    bytes_deleted = 0
    query = _get_query(db_name)
    metas = list(query[:1000])
    run_again = len(metas) == 1000
    if metas:
        for meta in metas:
            bytes_deleted += meta.content_length or 0
        db.bulk_delete(metas=metas)

        tags = {'database': db_name}
        age = datetime.utcnow() - metas[-1].created_on
        metrics_gauge('commcare.icds_images.max_age',
                      value=age.total_seconds(),
                      tags=tags)
        row_estimate = estimate_row_count(query, db_name)
        metrics_gauge('commcare.icds_images.count_estimate',
                      value=row_estimate,
                      tags=tags)
        metrics_counter('commcare.icds_images.bytes_deleted',
                        value=bytes_deleted)
        metrics_counter('commcare.icds_images.count_deleted', value=len(metas))

    runtime = datetime.utcnow() - cutoff
    if run_again and runtime.total_seconds() < MAX_RUNTIME:
        delete_old_images_on_db.delay(db_name, cutoff)
Exemple #28
0
def celery_record_time_to_start(task_id=None, task=None, **kwargs):
    from corehq.util.metrics import metrics_counter, metrics_gauge
    from corehq.util.metrics.const import MPM_MAX

    tags = {
        'celery_task_name': task.name,
        'celery_queue': task.queue,
    }

    timer = TimeToStartTimer(task_id)
    try:
        time_to_start = timer.stop_and_pop_timing()
    except TimingNotAvailable:
        metrics_counter('commcare.celery.task.time_to_start_unavailable',
                        tags=tags)
    else:
        metrics_gauge('commcare.celery.task.time_to_start',
                      time_to_start.total_seconds(),
                      tags=tags,
                      multiprocess_mode=MPM_MAX)
        get_task_time_to_start.set_cached_value(task_id).to(time_to_start)

    TimeToRunTimer(task_id).start_timing()
Exemple #29
0
def report_build_time(domain, app_id, build_type):
    start = time.time()

    # Histogram of all app builds
    name = {
        "new_release": 'commcare.app_build.new_release',
        "live_preview": 'commcare.app_build.live_preview',
    }[build_type]
    buckets = (1, 10, 30, 60, 120, 240)
    with metrics_histogram_timer(name, timing_buckets=buckets):
        yield

    # Detailed information for all apps that take longer than 30s to build
    end = time.time()
    duration = end - start
    if duration > 30:
        metrics_gauge('commcare.app_build.duration',
                      duration,
                      tags={
                          "domain": domain,
                          "app_id": app_id,
                          "build_type": build_type,
                      })
Exemple #30
0
def prune_synclogs():
    """
    Drops all partition tables containing data that's older than 63 days (9 weeks)
    """
    db = router.db_for_write(SyncLogSQL)
    oldest_date = SyncLogSQL.objects.aggregate(Min('date'))['date__min']
    while oldest_date and (datetime.today() - oldest_date).days > SYNCLOG_RETENTION_DAYS:
        year, week, _ = oldest_date.isocalendar()
        table_name = "{base_name}_y{year}w{week}".format(
            base_name=SyncLogSQL._meta.db_table,
            year=year,
            week="%02d" % week
        )
        drop_query = "DROP TABLE IF EXISTS {}".format(table_name)
        with connections[db].cursor() as cursor:
            cursor.execute(drop_query)
        oldest_date += timedelta(weeks=1)

    # find and log synclogs for which the trigger did not function properly
    with connections[db].cursor() as cursor:
        cursor.execute("select count(*) from only phone_synclogsql")
        orphaned_synclogs = cursor.fetchone()[0]
        metrics_gauge('commcare.orphaned_synclogs', orphaned_synclogs)