What It Is
Script Execution History is ServiceNow's comprehensive log of every background script, scheduled job, and server-side script that executes outside the normal user interface flow. It captures the complete execution context including start time, duration, output, errors, user who triggered it, and the actual script source code. This isn't just a simple log file—it's a queryable database table (syslog_script_execution) that stores detailed forensic information about script performance and failures. The system automatically creates these records whenever scripts run through the background script runner, scheduled script execution jobs, or other automated execution contexts.
Architecturally, Script Execution History lives within the System Logs application under the broader logging and monitoring framework. It operates at the platform level, below individual scoped applications, which means it captures script executions from all scopes including global and custom applications. The logging mechanism hooks into the JavaScript execution engine itself, intercepting script runs before they complete and persisting the execution metadata. This positioning makes it independent of application scope boundaries—you'll see executions from scoped apps, global scripts, and platform maintenance scripts all in the same unified view.
The underlying data model extends beyond simple logging to provide script debugging capabilities. Each execution record stores the complete script source, input parameters, output results, and any JavaScript errors or exceptions. The syslog_script_execution table includes execution statistics like memory usage patterns and processing time breakdowns. ServiceNow's script engine automatically populates fields for script type (Background Script, Scheduled Job, Fix Script), execution context, and related records when scripts modify data. The execution environment maintains transaction isolation, so you can see exactly what database changes occurred during each script run.
You cannot function without Script Execution History when debugging scheduled jobs that fail silently, background scripts that timeout or produce unexpected results, or data imports that corrupt records. When a scheduled script execution job stops working—maybe it was processing user provisioning or generating reports—the execution history shows you the exact error message, which line failed, and what data the script was processing when it broke. For background scripts that admins run during maintenance windows, the execution history provides the only way to verify the script completed successfully and see how many records were affected. During major data migrations or fixes, you need this history to prove to stakeholders exactly what changes were made and when.
Platform owners and system administrators primarily manage Script Execution History retention and access controls, while developers and application administrators use it daily for debugging their scripts. The platform owner controls the Script Execution History Retention system property and determines who can access execution records across all applications. Developers rely on it to debug their background scripts and scheduled jobs, while application administrators use it to monitor the health of their automated processes. The admin role can see all script executions regardless of who ran them, but developers typically only see executions they triggered or scripts within their application scope.
Recent ServiceNow releases have improved Script Execution History with better performance metrics and expanded script type coverage. Vancouver introduced enhanced memory usage tracking and execution time breakdowns that help identify inefficient scripts before they impact system performance. Xanadu added better integration with the Script Debugger, allowing you to launch debugging sessions directly from execution history records. The Tokyo release expanded coverage to include more automated script types like ATF test scripts and integration hub flows, giving you a more complete picture of all automated processing on your instance. These improvements make the execution history more actionable for performance tuning and proactive script maintenance.
Where to Find and Configure It
The primary location for Script Execution History is System Logs > Script Execution History where you view, filter, and analyze all script execution records. For configuration settings, navigate to System Properties > System and search for properties starting with glide.script.log to control logging behavior and retention. Access the underlying table directly at System Definition > Tables and search for syslog_script_execution when you need to create custom reports or configure advanced filtering.
In Studio, find script execution records through Application Explorer > System Logs > Script Execution History where you can filter to see only executions related to your current application scope. App Engine Studio users access it via Data > Tables > Script Execution History for creating custom views of script execution data. When debugging background scripts, launch the script runner from System Definition > Scripts - Background and your execution will automatically appear in the history with a direct link back to this interface.
For scoped applications, execution records show the application scope in the Application field, but global scope scripts appear with an empty application value. The execution history respects application scope security, so developers working in scoped applications only see their own script executions unless they have elevated privileges. Configure retention policies by modifying the glide.script.log.retention_days system property, which defaults to 30 days but can be extended for compliance or debugging requirements.
How It Works Step by Step
Script Execution History operates through ServiceNow's JavaScript engine interceptor that captures script execution context before, during, and after script runs. When any background script, scheduled job, or automated script executes, the platform creates a pre-execution record with the script source, user context, and timestamp. The script then runs within a monitored execution environment that tracks memory usage, database queries, and processing time. Upon completion—whether successful or failed—the system updates the execution record with results, output, error messages, and performance metrics.
The logging mechanism distinguishes between different script execution contexts to provide appropriate detail levels. Background scripts executed through the script runner capture complete source code and detailed output, while scheduled script execution jobs log the job definition, parameters, and execution results. The system maintains execution isolation, so concurrent script runs don't interfere with each other's logging data. Failed executions receive enhanced logging that includes stack traces, the specific line where failure occurred, and any database transaction rollback information.
Enjoying this? Get one deep-dive per week.
Join 1,000+ ServiceNow pros — scripts, GlideRecord patterns, Flow Designer techniques, and career moves. Free.
The Execution Order
- Script execution request enters the JavaScript engine from background script runner, scheduled job, or automated process
- System creates initial execution record in
syslog_script_executiontable with script source, user context, and start timestamp - JavaScript engine begins script execution within monitored transaction scope, tracking memory and database operations
- Script runs to completion or encounters error/timeout condition
- Execution engine captures final output, error messages, performance metrics, and transaction results
- System updates execution record with completion status, duration, output text, and any error details
- Record becomes available in Script Execution History interface for review and debugging
// This background script will appear in Script Execution History
// with complete source, output, and performance metrics
var gr = new GlideRecord('incident');
gr.addQuery('state', '1'); // New incidents
gr.addQuery('assigned_to', '');
gr.query();
var count = 0;
while (gr.next()) {
// Log output appears in execution history
gs.info('Processing incident: ' + gr.number);
// Auto-assign to default group
gr.assignment_group = '287ebd7da9fe198100f92cc8d1d2154e';
gr.update();
count++;
}
gs.info('Updated ' + count + ' incidents');
// Final output: "Updated X incidents" shows in execution recordReal-World Scenarios
Debugging Silent Scheduled Job Failures
Your scheduled script execution job that automatically closes resolved incidents after 7 days has stopped working, but the job shows as "Success" in the scheduled jobs list. Users are complaining that old resolved incidents remain open indefinitely.
Navigate to System Logs > Script Execution History and filter by Script type equals Scheduled Script Execution and Created in the last 7 days. Look for executions matching your job name in the Source field. Open the most recent execution record and examine the Output field—you'll likely find a JavaScript error like "Cannot read property 'setValue' of undefined" or a database query that returns zero records due to changed field names or table structure.
Check the Duration field to see if the script is timing out before completion. Watch for executions that show "Success" status but have empty or truncated output, indicating the script failed silently without throwing an exception. The execution history will reveal whether the script is running but finding no records to process, encountering permission errors, or failing on specific record updates that don't halt overall execution.
Tracking Data Migration Script Progress
You're running a large background script to migrate 50,000 user records from an old table structure to a new format during a maintenance window. You need to prove to stakeholders exactly how many records were processed and verify no data was corrupted.
// Background script for user migration - execution tracked automatically
var startTime = new GlideDateTime();
var processed = 0, errors = 0;
var gr = new GlideRecord('sys_user_old');
gr.query();
gs.info('Starting user migration at ' + startTime.getDisplayValue());
while (gr.next()) {
try {
var newUser = new GlideRecord('sys_user');
newUser.user_name = gr.old_username;
newUser.email = gr.old_email;
newUser.first_name = gr.old_first;
newUser.last_name = gr.old_last;
newUser.insert();
processed++;
if (processed % 1000 == 0) {
gs.info('Processed ' + processed + ' users');
}
} catch (e) {
gs.error('Failed to migrate user ' + gr.old_username + ': ' + e.message);
errors++;
}
}
gs.info('Migration complete: ' + processed + ' successful, ' + errors + ' errors');After running the script, find your execution in Script Execution History by filtering on your user name and the current date. The Output field contains all your gs.info() statements showing progress milestones and final counts. Use the Duration field to document total processing time for capacity planning. The complete script source in the Source field provides an exact record of what logic was executed, crucial for audit trails and troubleshooting any data discrepancies discovered later.
Identifying Performance Bottlenecks in Background Scripts
Your weekly report generation background script has started taking hours instead of minutes to complete, causing other scheduled jobs to queue up and delay critical automated processes. Performance complaints are escalating and you need to identify the bottleneck.
Access System Logs > Script Execution History and filter for your report script executions over the past month. Create a list view that shows Created, Duration, and Status to identify when the performance degradation started. Sort by Duration descending to find the slowest executions. Open recent slow execution records and examine the Source field to see if the script logic has changed, then check output for any error messages or warnings about large result sets.
Compare execution duration trends against your system's overall performance metrics and recent changes to related tables or business rules that might affect query performance. Look for executions that completed successfully but took significantly longer, indicating data volume growth rather than script errors. The execution history will reveal whether the script is processing more records over time, encountering new data patterns that slow down processing, or if recent platform updates changed the performance characteristics of specific API calls used in your script.
The Classic Mistake
Running background scripts with infinite loops or uncontrolled recursion without timeout safeguards.
var gr = new GlideRecord('incident');
gr.query();
while (gr.next()) {
// Process each incident
var relatedGr = new GlideRecord('incident');
relatedGr.addQuery('parent', gr.sys_id);
relatedGr.query();
while (relatedGr.next()) {
// This creates exponential processing
var childGr = new GlideRecord('incident');
childGr.addQuery('parent', relatedGr.sys_id);
childGr.query();
// No timeout check, no break condition
while (childGr.next()) {
// Nested processing without limits
}
}
}This pattern causes the script execution to consume excessive server resources and may run for hours without completing. The Script Execution History shows a Running status that never changes to Success or Error. ServiceNow eventually terminates the script due to execution time limits, but by then it has consumed significant CPU and memory resources. The issue is non-obvious because nested loops with database queries appear logical but create exponential complexity that scales poorly with data growth.
var startTime = new GlideDateTime();
var maxRunTime = 30 * 60 * 1000; // 30 minutes in milliseconds
var processCount = 0;
var maxRecords = 1000;
var gr = new GlideRecord('incident');
gr.addQuery('state', 'IN', '1,2,3');
gr.setLimit(maxRecords);
gr.query();
while (gr.next()) {
var currentTime = new GlideDateTime();
if (currentTime.getNumericValue() - startTime.getNumericValue() > maxRunTime) {
gs.error('Script timeout reached, processed: ' + processCount + ' records');
break;
}
// Process record with controlled scope
processCount++;
if (processCount >= maxRecords) break;
}Always implement timeout checks and record limits in background scripts - set maximum execution time and maximum record processing counts before starting any loop.
When to Use This vs Alternatives
Script Execution History is the primary tool for monitoring and debugging any server-side script that runs outside of user sessions - background scripts, scheduled jobs, data imports, and script includes called by system processes. Use this when you need to verify script execution results, diagnose performance issues, or track down errors in automated processes.
When Script Execution History is the Right Choice
Use this for debugging scheduled jobs, background scripts, and import scripts where you need complete execution context including duration, output, and error details. The System Log only shows error messages without execution context, while Script Execution History provides the full picture including successful runs and performance metrics. This is essential when troubleshooting why a scheduled script didn't run, ran too slowly, or produced unexpected results.
When to Use System Logs Instead
Use System Log > All for debugging business rules, client scripts, and UI actions where you need real-time error tracking during user interactions. Script Execution History doesn't capture client-side script errors or business rule failures triggered by user actions. For workflow debugging, use Workflow > Context which provides workflow-specific execution details that Script Execution History cannot show.
When You Need Both Tools Together
Use Script Execution History alongside Performance Analytics when monitoring scheduled data collection scripts that populate PA indicators - Script Execution History confirms the script ran successfully while PA shows whether the data was collected correctly. For complex integrations, combine this with REST Message Logs to see both the script execution results and the external system responses. This dual approach reveals whether failures occur in the script logic or in external system communication.
Platform Interactions & Side Effects
- Creates records in
sys_script_execution_historytable with execution duration, user context, and full script output - these records can consume significant storage for high-volume scheduled jobs - Scheduled jobs triggered by
sysauto_scriptrecords automatically generate execution history entries, but manually triggered background scripts only create entries if they complete or error - Business rules triggered within background scripts do not appear in Script Execution History - only the parent script execution is logged, masking business rule failures
- Import set transformations called by scheduled scripts generate separate execution history records, creating multiple entries for a single logical data processing operation
- User session impersonation in background scripts affects the
Run asfield in execution history, potentially masking security context issues when scripts run with elevated privileges - Workflow script activities do not generate Script Execution History records - use
wf_contexttable instead for workflow-triggered script debugging - Update Sets capture changes to
sys_auto_scriptrecords but not their execution history, causing confusion when troubleshooting scheduled job behavior across environments - Email notifications triggered from background scripts generate
sys_emailrecords with the script execution context, but notification failures are not reflected in Script Execution History status - Memory usage and CPU consumption during script execution can trigger node performance alerts, but the connection to specific script execution history records requires correlation by timestamp
- Database transaction rollbacks in background scripts leave execution history records with
Successstatus even when all database changes were reverted, creating misleading audit trails
Debugging and Troubleshooting
The most common failure symptoms include scheduled jobs showing Running status indefinitely, background scripts completing with Success status but producing no visible output or changes, and execution history records missing for scripts that should have run. Users typically see these issues as data not being processed, scheduled reports not generating, or integration processes failing silently. The execution history output field may show JavaScript errors, timeout messages, or be completely empty despite the script running.
Start troubleshooting by checking System Diagnostics > Stats > Node Stats for current CPU and memory usage, then examine System Log > All for JavaScript errors occurring during the script execution timeframe. Check the sys_trigger table to verify scheduled jobs are being queued correctly, and review glide.script.execution.timeout system property to understand execution time limits. Look for specific error patterns like "RhinoException", "java.lang.OutOfMemoryError", or "Transaction timed out" in both the execution history output and system logs.
Common error messages include "Script execution cancelled due to timeout" indicating the script exceeded maximum execution time, "GlideRecord operation failed" suggesting database connection issues or record locking problems, and "Cannot instantiate abstract class" pointing to script include inheritance problems. Empty output fields with "Success" status usually indicate the script completed but didn't produce any gs.print() or gs.log() output, while missing execution history records entirely suggest the script never started due to scheduling issues or node availability problems.
Diagnostic Checklist:
- Filter execution history by script name and check if recent runs exist - missing entries indicate scheduling failures
- Compare execution duration with previous successful runs to identify performance degradation patterns
- Verify the "Run as" user has necessary ACL permissions for all tables and operations the script performs
- Check for concurrent executions of the same script that might be causing resource contention or database locks
- Review system property
glide.scheduler.worker.countto ensure sufficient scheduler threads are available - Test the script manually using
System Definition > Scripts - Backgroundto isolate scheduling from logic issues - Query
sys_script_execution_historydirectly to check for execution records with null or corrupted output fields
Quick Reference
- Execution history records are purged automatically after 30 days by default, controlled by
glide.script.execution.history.agesystem property - Maximum script output captured is 8000 characters - longer output gets truncated without warning, potentially losing critical error messages
- Default script execution timeout is 300 seconds (5 minutes), but can be overridden per script using
setTimeoutSeconds()in the script body - Scripts running as "System" user bypass all ACL restrictions but still respect data policy and client script validations
- Concurrent execution of the same scheduled script is prevented by default - subsequent runs are skipped with a "Previous execution still running" message
- Background scripts inherit the timezone of the "Run as" user, affecting date calculations and query filters with relative dates
- Memory consumption by background scripts is not logged in execution history - use Node Log Stats or
sys_db_transactionfor resource usage tracking - Script execution status remains "Running" if the node crashes during execution, requiring manual cleanup of orphaned execution records
- Export operations and large data imports do not generate execution history records despite being server-side script operations
- Scheduled script conditions are evaluated separately from script execution and condition failures do not appear in execution history