I recently built a system to automate Slack notifications with graphs that visualize the session counts for the last 7 days. This was achieved using a combination of Cloud Run functions for data processing and graph generation, and Cloud Scheduler for scheduling the execution.
Implementation Overview
Cloud Run Function
The Cloud Run function queries BigQuery to fetch session data, uses Matplotlib to create a line chart, and then sends the chart to Slack via the Slack API. The following steps outline the setup process.
Here is the code for main.py
. Before running, you need to set the SLACK_API_TOKEN
and SLACK_CHANNEL_ID
as environment variables. You can leave them empty for now, as we will set them up later.
import os
import matplotlib.pyplot as plt
from google.cloud import bigquery
from datetime import datetime, timedelta
import io
import pytz
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
def create_weekly_total_sessions_chart(_):
SLACK_TOKEN = os.environ.get('SLACK_API_TOKEN')
SLACK_CHANNEL_ID = os.environ.get('SLACK_CHANNEL_ID')
client = bigquery.Client()
# Calculate the date range for the last 7 days
jst = pytz.timezone('Asia/Tokyo')
today = datetime.now(jst)
start_date = (today - timedelta(days=7)).strftime('%Y-%m-%d')
end_date = (today - timedelta(days=1)).strftime('%Y-%m-%d')
query = f"""
SELECT
DATE(created_at) AS date,
COUNT(DISTINCT session_id) AS unique_sessions
FROM `<project>.<dataset>.summary_all`
WHERE created_at BETWEEN '{start_date} 00:00:00' AND '{end_date} 23:59:59'
GROUP BY date
ORDER BY date;
"""
query_job = client.query(query)
results = query_job.result()
# Prepare data for the graph
dates = []
session_counts = []
for row in results:
dates.append(row['date'].strftime('%Y-%m-%d'))
session_counts.append(row['unique_sessions'])
# Generate the graph
plt.figure()
plt.plot(dates, session_counts, marker='o')
plt.title('Unique Session Counts (Last 7 Days)')
plt.xlabel('Date')
plt.ylabel('Unique Sessions')
plt.xticks(rotation=45)
plt.tight_layout()
# Save the graph as an image
image_binary = io.BytesIO()
plt.savefig(image_binary, format='png')
image_binary.seek(0)
# Send the graph to Slack
client = WebClient(token=SLACK_TOKEN)
try:
response = client.files_upload_v2(
channel=SLACK_CHANNEL_ID,
file_uploads=[{
"file": image_binary,
"filename": "unique_sessions.png",
"title": "Unique Session Counts (Last 7 Days)"
}],
initial_comment="Here are the session counts for the last 7 days!"
)
except SlackApiError as e:
return f"Error uploading file: {e.response['error']}"
return "Success"
Dependencies
Create a requirements.txt
file and include the following dependencies:
functions-framework==3.*
google-cloud-bigquery
matplotlib
slack_sdk
pytz
Granting Access to the Cloud Run Function
To allow Cloud Scheduler or other services to invoke your Cloud Run function, you need to assign the roles/run.invoker
role to the appropriate entity. Use the following command to do this:
gcloud functions add-invoker-policy-binding create-weekly-total-sessions-chart \
--region="asia-northeast1" \
--member="MEMBER_NAME"
Replace MEMBER_NAME
with one of the following:
- A service account for Cloud Scheduler:
serviceAccount:scheduler-account@example.iam.gserviceaccount.com
- For public access (not recommended):
allUsers
Setting Up Cloud Scheduler
Use Cloud Scheduler to automate the function’s execution every Monday at 10:00 AM (JST). Here’s an example configuration:
Slack API Configuration
To enable your Cloud Run function to send Slack notifications, follow these steps:
1.Go to Slack API and create a new app.
2.Assign the following Bot Token Scopes under OAuth & Permissions:
channels:read
chat:write
files:write
3.Install the app to your Slack workspace and copy the Bot User OAuth Token.
4.Add the app to the Slack channel where you want to post notifications.
5.Copy the channel ID and paste it, along with the Bot Token, into the SLACK_CHANNEL_ID
and SLACK_API_TOKEN
environment variables for your Cloud Run function.
Final Result
Once everything is set up, your Slack channel will receive a weekly notification with a graph like this:
Top comments (0)