Blog Post

Capturing errors and auditing in Azure SQL DB

,

Image by Pexels from Pixabay

Logging is a necessity in the database world, well, the entire tech world. You need to know what is happening in and around your databases. It’s easy to setup in Azure SQL DB.

This post will guide you through setting up and querying diagnostic settings to access your database logs easily.

Setting up a diagnostic setting

It’s a good idea to have a dedicated log analytics workspace, rather than using the default one. You can use this to create one before setting up your diagnostic setting, or you can use an existing one.

It’s quite easy to set up capturing errors for Azure SQL DB. You need to set up a diagnostic setting at the database level, under Monitoring > Diagnostic Settings.

Click Add diagnostic setting.

Logging/metrics options

Let’s review our options for logging.

Logs CategoryWhat It Gets
SQL InsightsQuery performance analysis, execution plans, resource usage patterns, and optimization recommendations
Automatic TuningIndex recommendations, query plan corrections, automatic index creation/drop events, and tuning actions taken by SQL Server
Query Store Runtime StatisticsCaptures query execution metrics, wait statistics, performance counters, and runtime execution data for query performance monitoring.
Query Store Wait StatisticsWait events during query execution (locks, I/O waits, CPU waits, memory waits, etc.)
ErrorsSQL Server error messages, failed logins, constraint violations, deadlock victims, and other exception events
Database Wait StatisticsSystem-wide wait statistics showing resource bottlenecks and performance issues
TimeoutsQuery timeout events, connection timeouts, and other time-based failures
BlocksBlocking chains, lock escalations, and sessions waiting on resources held by other sessions
DeadlocksDeadlock graphs, victim selection details, and resources involved in deadlock scenarios
Devops Operations Audit LogsAdministrative actions, deployments, configuration changes, and operational events
SQL Security Audit Event (I don’t use this, as it doesn’t seem to work; instead, use Auditing, which is further discussed in the article.)Login attempts, permission changes, data access events, schema modifications, and security-related activities

Additionally, you have some other options with metrics.

Metric CategoryWhat It Gets
BasicCore performance counters like CPU usage, memory utilization, disk I/O rates, network throughput, active connections, transactions per second, and fundamental database operations
InstanceAndAppAdvancedAdvanced instance-level metrics, including buffer pool statistics, plan cache hit ratios, lock statistics, wait statistics, batch requests/sec, page life expectancy, memory grants, and application-specific performance counters
WorkloadManagementResource governance metrics such as resource pool statistics, workload group performance, query execution resource consumption, memory allocation per workload, CPU throttling events, and resource usage by different application workloads

The logs and metrics capture different types of information.

AspectLogs Metrics
Data TypeEvent-based records (what happened, when, why)Numerical measurements (how much, how fast, how often)
FormatStructured log entries with timestamps and detailsTime-series data points and counters
PurposeDebugging, auditing, and root cause analysisPerformance monitoring and operational alerting

For example:

  • Metrics show you that there’s a problem (high CPU, long waits)
  • Logs show you what caused it (specific queries, deadlocks, errors)
ScenarioMetrics ShowLogs Provide
Performance IssueHigh CPU usage, increased wait timesSpecific slow queries (SQL Insights), blocking chains (Blocks)
Deadlock ProblemDecreased throughput, timeout spikesDeadlock graphs and victim details (Deadlocks)
Security ConcernUnusual connection patternsFailed login attempts, permission changes (SQL Security Audit)
OptimizationResource usage trendsAuto-tuning actions taken, index recommendations (Automatic Tuning)

When choosing what to select, allLogs gives you all the logs (imagine that!), and audit gives you only Devops Operations Audit Logs and SQL Security Audit Event.

Configuring the diagnostic setting

I’ve decided to set up all logs except SQL Security Audit Event, which I will configure separately, along with all metrics, and then put it in my SQLLAW and click Save.

Now, my diagnostic setting is there.

To capture audits of what happens inside the database, you also need to enable auditing, and I’ll put it in the same Log Analytics workspace as my logs.

And once you save that auditing piece, you can revisit the diagnostic settings and see it there.

It would be nice if the SQL audit worked with the checkbox in the logging diagnostic setting I set up, but alas, it doesn’t, so I had to resort to using it with the official auditing function.

Now, we have all the bits and pieces for logging and auditing in the same log analytics workspace, and we can query it.

View the log and audit data

To do this, you need to access the Log Analytics workspace and run a Kusto query. I have a Kusto tutorial available here, but I’ll also provide some additional information below.

Before we even attempt to examine the logs, let’s make some things happen; otherwise, the results will be very uninteresting, namely, nothing returns. I logged into my database and attempted to create a table incorrectly, then created it correctly to ensure something was logged. If you are setting this up on a legit database that has things happening in it, you won’t have to do that.

That being said, I’m going to my log analytics workspace now and clicking on Logs.

A box of suggested queries pops up, but I never use it. I never found it particularly helpful for anything I wanted to do. I close that and use the query window, with KQL mode.

Querying log results

Then, I will run this query. This will display all the information in the log related to Azure SQL.

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SQL"

There are a lot more columns, too.

What I find helpful is to project this out into a table with only the columns I want to see, and I also like to include some of the other filters in that query.

Maybe you only want to see one category of logs. Here are the categories available to you with Azure SQL DB:

CategoryDescription
SQLInsightsIntelligent Insights into database performance
AutomaticTuningInformation about automatic tuning recommendations and actions
QueryStoreRuntimeStatisticsQuery runtime statistics (CPU usage, duration, execution counts)
QueryStoreWaitStatisticsQuery wait statistics (what queries waited on)
ErrorsSQL error messages and events
DatabaseWaitStatisticsDatabase-level wait statistics by wait type
TimeoutsQuery timeout events
BlocksBlocking events and lock information
DeadlocksDeadlock events with XML reports
Devops operations Audit LogsDevOps Operations Audit Logs capture infrastructure and administrative operations such as deployments, scaling, user management, and configuration changes rather than data access activities.
SQLSecurityAuditEvents Login attempts, permission changes, data access events, schema modifications, and security-related activities

Additionally, you have options for handling TimeGenerated, including functions and time units ago.

FunctionDescriptionExample
ago()Time relative to nowTimeGenerated > ago(1d)
now()Current timeTimeGenerated > now(-1d)
datetime()Specific date/timeTimeGenerated > datetime(2025-01-01)
startofday()Start of dayTimeGenerated > startofday(now())
startofweek()Start of weekTimeGenerated > startofweek(now())
startofmonth()Start of monthTimeGenerated > startofmonth(now())

Time Units for ago()

UnitAbbreviationExample
Minutesmago(30m)
Hourshago(4h)
Daysdago(7d)
Weekswago(2w)
MonthsMago(3M)
Yearsyago(1y)

And what we wind up with his something like this:

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SQL"
  and TimeGenerated > ago(1d) 
  and Category == "Errors"
| project TimeGenerated, Message, ResourceGroup, DatabaseName_s

If you have errors, you will get results similar to the following screenshot. Note that I don’t usually put things in the default resource group, but I was too lazy to create a new one for this demo, even though it’s not a lot of work.

Querying audit results

To get the audit records for people querying inside the db, you can use the following query, but note that SQL Security Audit Events can take longer (up to 2 hours delay after setting up) to process and appear compared to the other diagnostic logs like performance metrics, errors, etc.

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.SQL"
  and TimeGenerated > ago(4d) 
  and Category == "SQLSecurityAuditEvents"
| where database_name_s != 'master'
| project
event_time_t, 
        ResourceGroup,
        server_instance_name_s,
database_name_s, 
statement_s, 
server_principal_name_s, 
succeeded_s,
client_ip_s, 
application_name_s, 
additional_information_s, 
data_sensitivity_information_s

I specifically searched for the DROP TABLE statements I ran.

And if you haven’t used SQL audit before, you will be surprised at all the stuff that happens behind the scenes that also gets audited. You can configure the auditing to capture fewer actions by modifying the actions it captures. I cover that in this post.

I’m going to create a dashboard for these results, allowing anyone at my company to query this data in the future easily. That will be covered in a future post, but I will probably use Azure Workbooks.

The post Capturing errors and auditing in Azure SQL DB appeared first on sqlkitty.

Original post (opens in new tab)
View comments in original post (opens in new tab)

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating