Source code for visualization_toolkit.helpers.dash.monitoring
import logging
import os
from dash import Dash, Input, Output
from flask import Flask, jsonify
from urllib3 import Retry
import requests
from envelop import Environment
from visualization_toolkit.constants import (
APP_ENVIRONMENT,
JINJA_ENVIRONMENT,
LIBRARY_PATH,
DATADOG_CLIENT_TOKEN,
DATADOG_APPLICATION_ID,
DATADOG_SERVICE_NAME,
DATADOG_ENVIRONMENT,
ATLAS_LOCATION_ID,
ATLAS_USER_STORE_ID,
ATLAS_ENABLE_DATADOG,
ATLAS_DEBUG,
)
logger = logging.getLogger(__name__)
[docs]
def setup_sentry(env: Environment = None, env_var: str = "SENTRY_DSN"):
"""
Intialize sentry tracking of exceptions. Will connect to sentry via the ``SENTRY_DSN`` variable set in the app environment.
:param env: Enveleop Environment client to use. Defaults to the libraries ``APP_ENVIRONMENT``. Generally not needed to be set.
:param env_var: Environment variable name that stores the sentry dsn. Defaults to ``SENTRY_DSN``.
:return:
"""
env = env or APP_ENVIRONMENT
SENTRY_DSN = env.get(env_var, None)
if SENTRY_DSN:
import sentry_sdk
sentry_sdk.init(dsn=SENTRY_DSN)
[docs]
def setup_datadog():
"""
Initialize datadog APM tracing of the dash app.
:return:
"""
if ATLAS_ENABLE_DATADOG:
from ddtrace import tracer
from ddtrace import patch_all
DD_PRIVATE_IP = get_aws_ip()
tracer.configure(hostname=DD_PRIVATE_IP)
patch_all()
def setup_datadog_rum(
app: Dash,
user_store_id: str = ATLAS_USER_STORE_ID,
location_id: str = ATLAS_LOCATION_ID,
debug: bool = ATLAS_DEBUG,
):
"""
Initialize datadog RUM tracking of the dash app on the browser. Requires adding ``user_store`` and ``location_store`` to the dash app.
:param app: Dash app to enable RUm on
:param user_store_id: ID of user store that user information will exist in. Defaults to ``ATLAS_USER_STORE_ID``.
:param location_id: Environment variable name that stores the sentry dsn. Defaults to ``USE_DATADOG``.
:param debug: If True, additional logging will be included in the client side callbacks to debug in the browser.
:return:
"""
if ATLAS_ENABLE_DATADOG:
# initialize DD rum client via the browser
with open(
os.path.join(LIBRARY_PATH, "templates/datadog/initializeDDRum.js")
) as f:
init_script = JINJA_ENVIRONMENT.from_string(f.read()).render(
parameters={
"debug": debug,
"dd_client_token": DATADOG_CLIENT_TOKEN,
"dd_application_id": DATADOG_APPLICATION_ID,
"dd_service_name": DATADOG_SERVICE_NAME,
"dd_environment": DATADOG_ENVIRONMENT,
}
)
app.clientside_callback(
init_script,
Input(location_id, "href"),
)
# Then register a callback to register the user once DD rum is initialized and user is authenticated
with open(os.path.join(LIBRARY_PATH, "templates/datadog/ddRumSetUser.js")) as f:
user_script = JINJA_ENVIRONMENT.from_string(f.read()).render(
parameters={
"debug": debug,
}
)
app.clientside_callback(
user_script,
Input(user_store_id, "data"),
)
def get_aws_ip():
if os.environ.get("AWS_EXECUTION_ENV") == "AWS_ECS_FARGATE":
return "127.0.0.1" # for fargate
# implement a retry strategy in case the EC2 Instance MetaData Server v1 endpoint isn't available yet
retry_strategy = Retry(total=3, backoff_factor=0.5)
session = requests.Session()
session.mount("http://", requests.adapters.HTTPAdapter(max_retries=retry_strategy))
r = session.get("http://169.254.169.254/latest/meta-data/local-ipv4", timeout=15)
r.raise_for_status()
return r.text
[docs]
def setup_healthcheck(server: Flask | Dash):
"""
Adds a custom healthcheck endpoint on the dash app required for deployments to AWS.
Healthcheck endpoint will return a 200 and is found on ``/status/healthcheck/``
:param server: Flask server. Generally this is accessed via the ``server`` attribute on an initialized dash app. Dash app can also be passed in and the server is retrieved inside the function.
:return:
"""
if isinstance(server, Dash):
server = server.server
@server.route("/status/healthcheck/")
def healthcheck():
response = {"status": "ok"}
return jsonify(response)