Happyface4

Submodules

Happyface4.apps module

class Happyface4.apps.Happyface4Config(app_name, app_module)[source]

Bases: AppConfig

name = 'Happyface4'

Happyface4.forms module

class Happyface4.forms.DateTimeForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None, bound_field_class=None)[source]

Bases: Form

base_fields = {'date': <django.forms.fields.DateField object>, 'time': <django.forms.fields.TimeField object>}
declared_fields = {'date': <django.forms.fields.DateField object>, 'time': <django.forms.fields.TimeField object>}
property media

Return all media required to render the widgets on this form.

Happyface4.helpers module

Happyface4.helpers.field_index(name, fields, key='name') → int | None[source]
Happyface4.helpers.get_data_from_elasticsearch(base_url, header, query_head, query_body, logger, timeout=600)[source]
Happyface4.helpers.get_data_from_grafana(url, datasource, queries, logger, token=None, time_range={'from': 'now-24h', 'to': 'now'}) → dict[source]

Simple helper function to get the resource data from a grafana service in JSON format.

Args:

url (str): Url to the grafana instance. Should look like https://grafana_instance.com/api/ds/query. datasource (dict): Datasource to fetch data from. Usually something like {‘uid’: ‘foobar’} queries (dict): The queries to run against the datasource. The keys are used as refId, values are the queries. logger (logging.logger): A logger. Usually self.logger. token (str, optional): The identification token for the grafana instance if necessary. Defaults to None. time_range (dict): Time range. Defaults to {“from”: “now-24h”, “to”: “now”}.

Returns:

dict: The results member of the Grafana response JSON.

Happyface4.managers module

class Happyface4.managers.InstanceStatusManager(*args, **kwargs)[source]

Bases: Manager

get_instance_status(time, instance_name, category, time_range)[source]
update_or_create(time, instance, category, status)[source]

Save a status for the given instance and category at the given time.

Existing instances and categories are used if they already exist, otherwise they are created. This method does not return anything.

Parameters:
  • time (datetime) – The time the status was recorded.

  • instance (str) – Name of the analysis instance.

  • category (str) – Name of the category of the instance.

  • status (int) – The status as a number.

Happyface4.middleware module

Custom middleware for HappyFace4.

ConditionalCacheMiddleware: Prevents cache updates during getData execution to avoid caching incomplete data when database updates are in progress.

TimezoneMiddleware: Activates the browser’s timezone per request (HFC #14) and keys the page cache by it.

class Happyface4.middleware.ConditionalCacheMiddleware(get_response)[source]

Bases: MiddlewareMixin

Prevents cache updates during getData execution.

When getData is running, database updates may be in progress (deleting old records and inserting new ones). To prevent users from seeing and caching incomplete data, this middleware:

  1. Checks for ‘getData_in_progress’ flag in Redis before each request

  2. If flag is set, disables cache updates for that request

  3. User still gets served from existing cache (stale but complete data)

  4. After getData completes, old cache is invalidated and fresh data cached

This ensures users always see complete datasets, never partial data during database updates.

process_request(request)[source]

Check if getData is currently running. If so, mark this request to skip cache updates.

process_response(request, response)[source]

If getData is running, add headers to prevent caching this response. This works with UpdateCacheMiddleware to skip cache storage.

class Happyface4.middleware.TimezoneMiddleware(get_response)[source]

Bases: MiddlewareMixin

Activate the browser’s timezone for the current request (HFC #14).

The timezone travels in the hf_timezone cookie, which a small script in index.html sets from Intl.DateTimeFormat().resolvedOptions().timeZone. With USE_TZ = True template rendering of aware datetimes then happens in the browser’s timezone; the fallback (no/unknown cookie) is the server default settings.TIME_ZONE.

The page cache is keyed per timezone: the request is tagged with a synthetic X-HF-Timezone header and the response carries Vary: X-HF-Timezone, which the cache middlewares include in the cache key. Requests without the cookie (e.g. the getData cache warmup) share the default entry, so the warmup does not multiply.

process_request(request)[source]
process_response(request, response)[source]

Happyface4.models module

class Happyface4.models.Category(id, name)[source]

Bases: Model

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

exception NotUpdated

Bases: ObjectNotUpdated, DatabaseError

id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

instancestatus_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_reverse_many_to_one_manager() defined below.

name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>
class Happyface4.models.Instance(id, name)[source]

Bases: Model

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

exception NotUpdated

Bases: ObjectNotUpdated, DatabaseError

id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

instancestatus_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_reverse_many_to_one_manager() defined below.

name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>
class Happyface4.models.InstanceStatus(*args, **kwargs)[source]

Bases: Model

Model that saves the status of the instances in the db.

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

exception NotUpdated

Bases: ObjectNotUpdated, DatabaseError

STATUS_CHOICES = [(-2, 'technical issue'), (-1, 'info'), (0, 'ok'), (1, 'warning'), (2, 'critical')]
category

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

category_id
get_next_by_time(*, field=<django.db.models.fields.DateTimeField: time>, is_next=True, **kwargs)
get_previous_by_time(*, field=<django.db.models.fields.DateTimeField: time>, is_next=False, **kwargs)
get_status_display(*, field=<django.db.models.fields.SmallIntegerField: status>)
id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

instance

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

instance_id
objects = <Happyface4.managers.InstanceStatusManager object>
status

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

time

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

Happyface4.settings module

Django settings for Happyface4 project.

Generated by ‘django-admin startproject’.

For more information on this file, see https://docs.djangoproject.com/en/6.0/topics/settings/

For the full list of settings and their values, see https://docs.djangoproject.com/en/6.0/ref/settings/

Happyface4.status module

final class Happyface4.status.STATUS[source]

Bases: object

A small object to access the numeric codes of the different statuses.

CRITICAL = 2
INFO = -1
OK = 0
TECHNICAL_ISSUE = -2
WARNING = 1

Happyface4.urls module

HappyFaceV4 URL Configuration

This module defines the top-level URL configuration of the Happyface application. The urlpatterns list routes URLs to views; for the URL dispatcher reference see https://docs.djangoproject.com/en/6.0/ref/urls/.

The home page ("") is served by Happyface4.views.home() and the status categories by categories/<category>/ via Happyface4.views.index(). In addition, the urls of every registered analysis app are appended dynamically (see Happyface4.utilities.get_Analyses_from_apps()). Media files are only served from disk when DEBUG is set.

Happyface4.utilities module

class Happyface4.utilities.CategoryNav(name, instance)[source]

Bases: object

latest_status()[source]
statuses_list()[source]
class Happyface4.utilities.DummyInstanceStatus(time, status)[source]

Bases: object

Helper object that can be used to propagate a single instance status to the template. This is generally only used for the statuses info(-1) and technical issue(-2).

last()[source]
latest(_)[source]
class Happyface4.utilities.DummyInstanceStatusList(iterable=(), /)[source]

Bases: list

Sequence of DummyInstanceStatus objects that mimics the QuerySet interface consumed by the templates and the nav aggregation (iteration, len, latest and last).

Like the stored-status QuerySets (see InstanceStatusManager.get_instance_status) the sequence is ordered chronologically ascending, so last() returns the newest entry.

last()[source]
latest(field)[source]
class Happyface4.utilities.InstanceNav(name, verbose_name, status, order=-1, carry_over=None)[source]

Bases: object

latest_status()[source]
Happyface4.utilities.build_overview_grid(categories, time, slot_count=None, anchor=None)[source]

Map the nav categories onto a fixed overview slot grid.

The grid holds slot_count equidistant slots of PULL_INTERVAL covering the overview range, anchored at the globally newest stored status at or before time, snapped onto the PULL_INTERVAL lattice (fallback: time, snapped likewise). Every category and every instance is mapped onto exactly these slots, so all rows of the overview page are horizontally aligned regardless of how much data each instance has.

Mapping rules:

  • stored statuses are assigned to their nearest slot; a slot without a status renders as “no data” (status = None),

  • per-module carry-over (InstanceNav.carry_over, from the instance config key carry_over): the last known status stays valid for the configured window — every slot whose latest stored status is at most carry_over old shows that status instead of “no data” (for modules that report sparsely, e.g. SAM tests every hour or SITECONF once a day). Without the key only the nearest slot is filled (unchanged default),

  • the link target of a slot is the nearest stored status time of that instance (ties resolved to the earlier time) — for carried slots it is the carried status’s own time, so the shown page matches the displayed status; slots of placeholder series (info / technical issue, no stored rows) link to the slot time itself,

  • placeholder series fill every slot with their constant status,

  • a category slot shows the worst status of its instances at that slot and links to the nearest stored time across the category.

Parameters:
  • categories – list of CategoryNav as produced by get_statuses_of_instances()

  • time – the requested time

  • slot_count – number of slots (default OVERVIEW_RANGE / PULL_INTERVAL)

  • anchor – newest slot time (default: the newest stored status time at or before time, snapped onto the PULL_INTERVAL lattice; fallback: time snapped likewise). An explicitly passed anchor is snapped onto the lattice too (a no-op for on-lattice times)

Returns:

template-friendly category dicts {"name", "slots": [{"time", "status", "link_time"}...], "instances": [{"name", "verbose_name", "slots": [...]}]}

Happyface4.utilities.expand_dummy_status(dummy, time, time_range, instance, anchor=None)[source]

Spread a single DummyInstanceStatus over the requested time range.

Info and technical-issue instances (and instances without any stored status in the range) previously rendered a single overview bar, which broke the timestep alignment on the overview page (HFC #23). This helper builds a chronological series on the same grid as real instances: one step per PULL_INTERVAL * get_data_every going back from anchor.

The series is anchored to the data grid, not to the request time, so overlapping requests for the same time-slot always render the same bar timestamps and the bars line up with the stored-status rows (the newest bar sits at the instance’s last real check before time). Without any stored status at all the series falls back to anchoring at time.

Parameters:
  • dummy – the single placeholder status to expand

  • time – the requested time

  • time_range – the range to cover; may be None

  • instance – the instance configuration dict (for get_data_every)

  • anchor – newest timestep of the series (defaults to time); callers pass the instance’s last real check time for grid alignment

Returns:

a DummyInstanceStatusList covering the range

Happyface4.utilities.extract_time_from_request(request)[source]
Happyface4.utilities.get_Analyses_from_apps(apps)[source]
Happyface4.utilities.get_apps_with_instances_in_category(app_config_list, category)[source]

Creates a list of all apps with their respective instances that are in the category.

This is another filtering step that is used to determine which analyses to call with what arguments to get all the divs in the category.

Parameters:
  • app_config_list (list of Subclasses of the django.apps.AppConfig class) – list of configuration objects of the Analyses.

  • category (str) – the name of the category in which the analyses have registered an instance

Returns:

all apps that have an instance in the category

Return type:

list of tuples of the AppConfig subclass of an analysis with the instances of the corresponding class

Note

The returned tuples contain the AppConfig subclass as well as the entire configuration dict of that particular instance.

Happyface4.utilities.get_statuses_of_instances(app_list, time, time_range)[source]

generates a list of nav_elements from a list of analyses

Parameters:
  • app_list (list of django.apps.AppConfig subclasses) – list of the analysis configurations.

  • time (datetime) – the requested time of the statuses.

  • time_range (timedelta) – the time range in which to look for the statuses.

Returns:

the sorted list of CategoryNav elements.

Return type:

list

Happyface4.utilities.render_instances(analyses_list, category, time, request)[source]
Happyface4.utilities.sort_categories(categories_list, sort_key='name')[source]

Sort nav categories for the overview page (HFC #2).

Parameters:
  • categories_list – the list of CategoryNav objects as produced by get_statuses_of_instances()

  • sort_key – name (default, alphabetical, unchanged behavior) or status (most severe category first: critical > warning > technical issue > ok > info, ties broken alphabetically)

Returns:

a newly sorted list; the input list is not modified

Happyface4.views module

Happyface4.views.home(request)[source]
Happyface4.views.index(request, category)[source]

Happyface4.wsgi module

WSGI config for Happyface4 project.

It exposes the WSGI callable as a module-level variable named application.

For more information on this file, see https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/

Module contents

Happyface4 - The Django package of the Happyface monitoring application.

This package provides the top-level URL configuration, settings, models and utility functions used by the Happyface analyses. The analyses themselves live in separate applications (see HF4-Analyses submodule).