Snowflake Audit Logs and Alerts: How to Monitor, Detect, and Respond to Critical Events

Key Takeaways
- Snowflake audit logs provide essential visibility into user activity, data access, and resource consumption.
- Snowflake alerts enable proactive monitoring by automatically executing SQL conditions and triggering actions (like emails or webhooks) when predetermined thresholds are exceeded.
- Audit logs and alerts cover investigation and early warning. Automated warehouse optimization from Keebo adds continuous tuning on top.
Snowflake gives you two complementary tools for keeping cost and performance in check. Audit logs record what happened across your account. Alerts check conditions on a schedule and act when something crosses a line.
This short but comprehensive guide will cover the details of Snowflake audit logs, alerts, and integrations with external notification systems. We’ll cover how to configure each one, what it’s best at, and where it fits alongside other tools.
Table of Contents
- Key Takeaways
- What Are Snowflake Audit Logs?
- How to Query and Analyze Snowflake Audit Logs
- How to Set Up Snowflake Alerts
- How to Integrate Snowflake Alerts with External Notification Tools
- Best Practices for Audit Logs and Alerts
- Limitations and Common Pitfalls
- Final Thoughts on Snowflake Audit Logs and Alerts
What Are Snowflake Audit Logs?
Let’s start with Snowflake audit logs. These logs automatically capture detailed records of all account- and user-level activity, and provide the foundation for governance, compliance, and monitoring.
Users can access these logs through the ACCOUNT_USAGE and ORGANIZATION_USAGE schemas. Both schemas record all kinds of data, including user queries, login attempts, and more.
Although ACCOUNT_USAGE and ORGANIZATION_USAGE offer a large number of audit views (Snowflake provides the complete list in their documentation), here are some of the most relevant for cost and performance optimization:
| View | Description |
| WAREHOUSE_METERING_HISTORY | Tracks compute credit usage by warehouse, which is essential for analyzing and optimizing warehouse cost and performance. |
| QUERY_HISTORY | Contains statistics on queries executed, allowing review and optimization of query performance and detection of resource-intensive workloads. |
| CREDIT_USAGE_DAILY/CREDIT_USAGE | Shows daily or total credit consumption at the account level, useful for overall cost monitoring. |
| TABLE_STORAGE_METRICS | Provides metrics on table storage usage and helps identify tables that drive storage costs. |
| STAGE_STORAGE_USAGE_HISTORY | Reports storage usage on external/internal stages for cost attribution. |
| DATABASE_STORAGE_USAGE_HISTORY | Shows storage consumption at the database level to attribute and optimize database-related costs. |
| PIPE_USAGE_HISTORY | Reports credits consumed by Snowpipe and serverless loads, helpful for controlling ingestion-related compute spend. |
| SNOWFLAKE_COST | Tracks total cost for Snowflake resources attributed to objects. |
| LOGIN_HISTORY: | Useful for performance monitoring by correlating user activity with cost spikes, though more security-related. |
How to Query and Analyze Snowflake Audit Logs
Querying and analyzing Snowflake audit logs is a core part of maintaining visibility into user activity, data access, and system behavior.
By default, only the ACCOUNTADMIN role can query these views, since they contain sensitive metadata. To give other roles access, grant them a SNOWFLAKE database role such as USAGE_VIEWER (cost and usage views) or GOVERNANCE_VIEWER (QUERY_HISTORY, ACCESS_HISTORY).
Here’s an example of a SQL query you could use to access data from a Snowflake audit log:
SELECT user_name, warehouse_name, query_text, start_time, execution_status FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY WHERE start_time >= DATEADD(day, -7, CURRENT_TIMESTAMP());Note the use of the WHERE clause to limit results to only those data added in the last seven days. You can use WHERE to filter and limit results by any parameters.
Here’s another example, if you wanted to gain a record of the information accessed by a specific user over the last 45 days:
SELECT query_id, query_start_time, user_name, direct_objects_accessed, objects_modified FROM SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY WHERE user_name = 'NAME' AND query_start_time >= DATEADD(day, -45, CURRENT_TIMESTAMP());Keep in mind that ACCOUNT_USAGE retains data for one year, and that data arrives with some latency: from 45 minutes (QUERY_HISTORY) to 3 hours (WAREHOUSE_METERING_HISTORY, ACCESS_HISTORY) for the views above, and longer for a few others. That makes these views best suited for investigation, trend analysis, and compliance.
Audit logs answer the questions you bring to them, which makes them strongest for investigation and compliance. To catch issues as they emerge, pair them with Snowflake alerts, which run those same queries on a schedule and act on the result.
How to Set Up Snowflake Alerts
Snowflake alerts are schema-level objects that automatically evaluate SQL conditions on a defined schedule and trigger actions when certain criteria are met. While audit logs are great for investigation, Snowflake alerts are designed for proactive monitoring.
Each alert has three components:
- Condition (what the alert checks)
- Schedule (how often the alert runs)
- Action (what the alert does when the condition evaluates to true)
Setting up an alert in Snowflake is fairly straightforward. The example below emails an admin when any warehouse uses more than 20 credits in a single hour.
-- One-time setup: email integration CREATE NOTIFICATION INTEGRATION my_email_int TYPE = EMAIL ENABLED = TRUE ALLOWED_RECIPIENTS = ('admin@example.com'); CREATE OR REPLACE ALERT high_credit_usage WAREHOUSE = alert_wh -- small, dedicated warehouse SCHEDULE = '60 MINUTE' -- match the view's latency, not the clock IF (EXISTS ( SELECT warehouse_name FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY WHERE start_time >= DATEADD(hour, -4, CURRENT_TIMESTAMP()) GROUP BY warehouse_name HAVING SUM(credits_used) > 100 )) THEN CALL SYSTEM$SEND_EMAIL( 'my_email_int', 'admin@example.com', 'High credit usage', 'A warehouse used more than 100 credits in the last 4 hours.' ); -- Alerts are created suspended ALTER ALERT high_credit_usage RESUME;A few details are worth calling out:
- Each hour is checked once. The condition looks at a single completed hour, so the alert doesn’t fire repeatedly on the same spike.
- The schedule matches the data. WAREHOUSE_METERING_HISTORY can lag up to 3 hours, so checking every minute would spend compute without adding signal. The tradeoff is that this alert reports a spike a few hours after it happens. For a hard limit that acts immediately, use a resource monitor (covered below).
- The alert runs as its owner role. That role needs access to the view it queries (for example, the USAGE_VIEWER database role) and USAGE on the integration.
Some of the most common alert types include:
- Monitoring credit consumption spikes to evaluate usage and cost
- Detecting failed logins and unauthorized access attempts to improve security
- Catching pipeline lag to surface operational anomalies
Alerts bill like any other query, so match the schedule to how often the underlying data changes.
How to Integrate Snowflake Alerts with External Notification Tools
One of the advantages of Snowflake’s monitoring tools is the ability to integrate alerts with external notification systems. This enables teams to centralize their monitoring efforts and increase the speed of insights, all of which enables faster identification and resolution of cost or performance issues.
Snowflake’s integration options include the following:
- Cloud provider queues (Amazon SNS, Azure Event Grid, Google Cloud Pub/Sub). Broadcast alerts to multiple subscribers or downstream automation.
- Webhooks. Send messages directly to Slack, Microsoft Teams, PagerDuty, Jira, or ServiceNow.
- Email. Notify admins and stakeholders who are users in the account.
For example, let’s say you want to monitor credit usage and send a webhook message to a Slack channel when a certain threshold has been reached. You could write a SQL command similar to the following:
-- One-time setup: store the part of the Slack webhook URL after /services/ CREATE OR REPLACE SECRET my_slack_webhook_secret TYPE = GENERIC_STRING SECRET_STRING = 'T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'; CREATE OR REPLACE NOTIFICATION INTEGRATION slack_webhook TYPE = WEBHOOK ENABLED = TRUE WEBHOOK_URL = 'https://hooks.slack.com/services/SNOWFLAKE_WEBHOOK_SECRET' WEBHOOK_SECRET = my_db.my_schema.my_slack_webhook_secret WEBHOOK_BODY_TEMPLATE = '{"text": "SNOWFLAKE_WEBHOOK_MESSAGE"}' WEBHOOK_HEADERS = ('Content-Type' = 'application/json'); CREATE OR REPLACE ALERT cost_alert WAREHOUSE = my_wh SCHEDULE = 'USING CRON 15 * * * * UTC' IF (EXISTS ( SELECT warehouse_name FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY WHERE start_time = DATEADD(hour, -4, DATE_TRUNC(hour, CURRENT_TIMESTAMP())) GROUP BY warehouse_name HAVING SUM(credits_used) > 500 )) THEN CALL SYSTEM$SEND_SNOWFLAKE_NOTIFICATION( SNOWFLAKE.NOTIFICATION.TEXT_PLAIN( SNOWFLAKE.NOTIFICATION.SANITIZE_WEBHOOK_CONTENT('High credit usage detected') ), SNOWFLAKE.NOTIFICATION.INTEGRATION('slack_webhook') ); ALTER ALERT cost_alert RESUME;Best Practices for Audit Logs and Alerts
To get the most out of Snowflake audit logs and alerts while keeping their own compute cost low:
- Use ACCESS_HISTORY (Enterprise Edition and higher) to monitor access patterns on sensitive tables
- Create dedicated audit roles with read-only privileges restricted to ACCOUNT_USAGE and ORGANIZATION_USAGE views
- Schedule periodic exports of audit logs to long-term cloud storage (e.g., Amazon S3, Azure Blob)
- Set clear, meaningful alert thresholds that reflect real operational risk; this will help reduce alert fatigue and prioritize critical events
- Automate real-time actions based on alerts (e.g. pausing a warehouse when credit usage exceeds a defined threshold)
- Use ALERT_HISTORY() and ACCOUNT_USAGE.ALERTS to track alert execution performance, identify failed runs, and fine-tune alert logic
- Assign alerts to lightweight, dedicated warehouses to avoid contention with production workloads
- Correlate alerts with query, user, and warehouse metadata to build richer investigative context and accelerate root cause analysis
Limitations and Common Pitfalls
For all the insight that Snowflake notifications and alerts can offer, there are some limitations and pitfalls to keep in mind. Here are a few of the most relevant:
| Limitation | Description |
| Latency | ACCOUNT_USAGE views can lag by 45-180 minutes, so logs and query data are not truly real-time. |
| Alert performance | Alert runs bill like any query. Schedules faster than the data refreshes add cost without adding signal. |
| Error handling | Failed alerts don’t auto-restart and must be manually checked or managed using ALERT_HISTORY(). |
| Retention limits | Audit logs are retained for up to 365 days; long-term record-keeping requires scheduled exports. |
| Operational overhead | Needs an owner. Schedules, integrations, and exports have to be maintained as the account changes. |
Final Thoughts on Snowflake Audit Logs and Alerts
Snowflake audit logs and alerts can be helpful tools for maintaining visibility into costs and performance. They’re especially useful as diagnostic and troubleshooting tools: once you notice a problem, you can use these features to drill down into the root cause.
Audit logs and alerts give you the record and the early warning. What they don’t do on their own is decide what to change: which warehouse is oversized this week, or which suspend setting stopped fitting the workload last month. Keeping those settings current as workloads shift is the layer Keebo adds on top of what Snowflake provides.



