‹ All essays

ServiceNow

Debugging ServiceNow: Session Debug, Slow Queries, Transaction Logs, and Script Tracing

Where to look first

When something is broken — a Business Rule is not firing, a form is slow, a notification is not sending — there are specific logs and tools for each problem. Do not guess. Go to the data.

ProblemWhere to lookNavigation path
Script errorsSystem Logs > Allsyslog_list.do
Slow forms/transactionsTransaction Logsyslog_transaction_list.do
Slow database queriesSlow Queriessys_slow_query_list.do
Email not sendingEmail Logsys_email_list.do
Business Rule not firingSession Debug > Business RuleSee below
ACL blocking accessSession Debug > SecuritySee below
Flow Designer errorsFlow Execution DetailsFlow Designer > Executions
Integration failuresOutbound HTTP logssys_outbound_http_log_list.do

Session Debug

Session Debug turns on detailed tracing for your current session. It does not affect other users. Enable it, reproduce the issue, then check the output in System Logs.

Enable via the System Diagnostics menu

// Navigate to: System Diagnostics > Session Debug > Enable All
// Or enable specific modules:
//   Debug Business Rule — shows which BRs fire, in what order, execution time
//   Debug Security Rules — shows ACL evaluation for every field/table access
//   Debug SQL — shows the raw SQL generated by GlideRecord queries
//   Debug Log — shows all gs.log/info/warn/error output

// After enabling, perform the action you want to debug (e.g., save an incident)
// Then check: System Logs > All (filter by your session)

What Debug Business Rule shows you

// Example output in System Logs after saving an incident:
// 
// === Business Rule: Set Priority (BEFORE, order 100) ===
// Table: incident
// Condition: priority changes
// Result: EXECUTED (4.2ms)
//
// === Business Rule: Auto-Assign (AFTER, order 200) ===
// Table: incident
// Condition: assignment_group is empty
// Result: SKIPPED (condition false)
//
// This tells you exactly which rules ran, which were skipped, and why.

What Debug Security shows you

// Example output when a user can't see a field:
//
// ACL: incident.caller_id (read)
// Role required: itil — PASS
// Condition: active=true — PASS
// Script: answer = ... — FAIL
// Result: DENIED
//
// Now you know exactly which ACL is blocking and which check failed.

System Logs

// Everything you write with gs.info, gs.warn, gs.error shows up here
// Filter by source to find your script's output:
gs.info('My debug output', 'MyScriptInclude');

// In the syslog table, filter:
//   Source = MyScriptInclude
//   Level = Info/Warning/Error
//   Created > last 10 minutes

Transaction Log

Every HTTP request to the instance is logged with timing data. When a form is slow, find the transaction here.

// Navigate to: syslog_transaction_list.do
// Key fields:
//   URL — which page/form/API was requested
//   Response time — total milliseconds
//   SQL count — number of database queries
//   Business Rule time — time spent in BRs
//
// Red flags:
//   Response time > 5000ms — slow transaction
//   SQL count > 100 — too many queries (N+1 problem likely)
//   Business Rule time > 2000ms — heavy BR logic

Slow Query Log

Queries that take longer than the threshold (default 500ms) are automatically logged here.

// Navigate to: sys_slow_query_list.do
// Key fields:
//   Table — which table was queried
//   Execution time — how long the query took
//   Source — which script/BR triggered it
//   Query — the encoded query string
//
// Common causes:
//   Missing index on a filtered field
//   No setLimit() on a large table query
//   Dot-walking through multiple reference fields
//   GlideRecord loop inside another GlideRecord loop (N+1)

Email debugging

// When a notification does not send, check these in order:
// 1. sys_email_list.do — is the email record created? What is its state?
//    States: ready, sent, send-failed, skipped
//
// 2. If state = skipped:
//    Check the notification's conditions and "Who will receive" config
//    Check if the user unsubscribed (notification_preference table)
//
// 3. If state = send-failed:
//    Check syslog for SMTP errors
//
// 4. In sub-production instances:
//    Check glide.email.test.user property — it redirects ALL email
//    to a single address. This is by design to prevent test emails
//    going to real users.

Script debugging without session debug

// Quick debugging pattern for Business Rules:
(function executeRule(current, previous) {
    // Temporarily add targeted logging
    gs.info('[BR:SetPriority] Fired on ' + current.number +
            ' | impact=' + current.getValue('impact') +
            ' | urgency=' + current.getValue('urgency') +
            ' | old_priority=' + (previous ? previous.getValue('priority') : 'N/A'));

    // Your logic here...

    gs.info('[BR:SetPriority] Result: priority set to ' + current.getValue('priority'));
})(current, previous);

// Find your logs: System Logs > All, filter Source CONTAINS SetPriority

Stats.do — Quick instance diagnostics

Navigate to your-instance.service-now.com/stats.do for a quick overview of instance health: memory usage, active transactions, semaphore counts, node status, and session counts. Useful during performance incidents when you need a fast read on whether the instance itself is under stress.

Common traps

  • Session debug left on: Debug sessions generate large amounts of log data. Always disable after you are done. Leaving it on in production degrades performance.
  • Logging sensitive data: gs.info writes to syslog which is visible to admins. Never log passwords, PII, or API keys.
  • Debug output not showing: If you enabled debug but see nothing, check that you are looking at the correct time window and that your script actually executed. Also verify you are on the correct node in a multi-node instance.
  • Transaction log vs slow query: A slow transaction does not always mean a slow query. The time could be in Business Rule execution, external REST calls, or Flow Designer actions. Check the breakdown columns.