One of the features of Looker is alerts, which are notifications that are triggered when certain conditions are met. Alerts are set on query-based or Look-linked tiles on dashboards. Based on the alert’s frequency, Looker checks whether each alert’s conditions (a particular metric) have been met or exceeded; if so, Looker notifies users of this change.
Our current strategy at work is built around data democratization which encourages all Looker users to develop and schedule dashboards and alerts. However, the sheer number of users having this level of access can create inconsistencies, duplicates, and inefficient queries that can slow down the entire system. For any bulk operations, we typically use the Admin Power Pack (APP Tool), an easy-to-install open-source tool that allows admins to do bulk operations such as resending a list of scheduled dashboards, bulk enabling or disabling users, assigning emails, and updating multiple schedules using Looker SDK in Python. It is truly a power pack that can bulk configure anything but lacks support for the alerts.
It all started when I decided to certify a list of mission-critical reports and remove any duplicate and redundant reporting we accumulated over the past three years. During the cleanup, I noticed that many users also set many alerts. These alerts were either disabled or placed on top of depreciated reports. The list was eight pages long. I could have gone over the alerts one by one and deleted them, but I thought it would take the same time to use the Looker SDK and build a way to do it in bulk. I am pretty sure in the end, it took me much longer to put it all together but it is a reusable solution.
The script was written using the Looker API and the Streamlit library, enabling users to disable or delete alerts for any other user in Looker. The application will find all the alerts for a user by their email and then disable or delete those alerts.
The only prerequisites are the Looker.ini app for permissions and the Streamlit PyPI package. To set up Looker.ini, I followed the instructions on the Looker SDK PyPI site within the "Configuring the SDK" section.
The script has two parts:
- The Streamlit UI for the user's email and select the action (disable or delete).
- The Looker SDK code for the actual management of the alerts.
First, start by importing the necessary libraries and initializing the Looker SDK connection.
import streamlit as st
import looker_sdk
from looker_sdk import methods40, models40
sdk = looker_sdk.init40()
Next is using Streamlit to name the app and create a user interface that consists of text input for the email and a dropdown menu to select the action.
st.title("Looker Alerts Manager")
# The user interface asks the user to enter their email address
# and select the desired action (disable or delete).
email = st.text_input("Enter user email:")
action = st.selectbox("Select action:", ["disable", "delete"])
The Looker SDK code starts with the find_user_id function that returns the user id associated with the entered user email.
def find_user_id(email: str):
"""
The `find_user_id` function takes the user's email address as an argument
and returns the user's ID if it is found. If the user is not found,
the function returns an error message.
"""
user_id = sdk.search_users(email=email)
if len(user_id) == 0:
return 'There is no user associated with this email'
else:
return user_id[0]['id']
Looker SDK currently does not provide a method to return a list of alert ids by a specific user. The workaround to this was first returning all alerts and then building the list of alerts by a user.
def get_all_alerts(sdk):
"""The `get_all_alerts` function returns a list of all the alerts in Looker,
both active and disabled.
"""
all_alerts = sdk.search_alerts(all_owners=True)
return all_alerts
Next is the implementation of the functions. When both the email and action are entered, the code displays a message indicating that the processing is in progress. After finding the user id via the email and assigning it as the looker_user_id, it is time to get all alerts and filter them by the looker_user_id.
# The user's ID is used to get a list of alerts
# If there are no alerts for the user, a message is displayed to that effect.
# Set up looker_user_id
if email and action:
looker_user_id = find_user_id(email)
if looker_user_id == 'There is no user associated with this email':
st.error(looker_user_id)
# get alerts in a list for the looker_user_id
st.write("Processing...")
all_alerts = get_all_alerts(sdk)
alerts = [alert for alert in all_alerts if alert.owner_id == looker_user_id]
if len(alerts) == 0:
st.write(f"No alerts found for user with email {email}.")
The code then loops through the list of alerts and either disables or deletes the alerts based on the selected action and displays the results to the user. The run ends by shutting down the connection by setting the SDK object to `None`.
for alert in alerts:
# disable
if action == "disable":
sdk.update_alert_field(
alert_id=alert.id,
body=models40.AlertPatch(
owner_id=looker_user_id,
is_disabled=True,
disabled_reason="not used, disabled by streamlit alerts app",
is_public=False,
threshold=0
))
# delete
elif action == "delete":
sdk.delete_alert(alert.id)
st.write(f"{len(alerts)} alerts {action}d for user with email {email}.")
# shut down the Looker connection
sdk = None
Here is the confirmation text. Once the processing is completed, the number of alerts impacted and the user's email are displayed, notifying the user.
This script is written for the specific use case of bulk disabling and deleting alerts. Please see the link to the gist for the complete code if you would like to use it as a starting point to add your features.