Health Check Report for EBS and Database
Keeping an Oracle Database and Oracle E-Business Suite (EBS) environment healthy requires continuous monitoring across multiple layers—database, RAC, application services, and infrastructure. Manual checks are time-consuming and error-prone, especially in large enterprise systems.
This article explains a lightweight yet powerful automated health check framework built using Shell scripting, SQL*Plus, and HTML reporting, suitable for daily operational monitoring by DBAs and Apps DBAs.
High-Level Architecture
The health check script performs the following:
- Connects to the Oracle Database (CDB / RAC aware)
- Collects database and EBS metrics
- Evaluates thresholds (OK / WARNING / CRITICAL)
- Generates an HTML report
- Sends the report via email
This makes it ideal for daily scheduled execution via cron.
Instead of plain text logs, the script generates a color-coded HTML report, making it easy for support teams and managers to quickly understand system health.
Status indicators:
Green (OK) – No action requiredOrange (WARN) – Monitor / plan corrective action
Red (CRIT) – Immediate attention required
#!/bin/bash. ~/EBSCDB_db.envINST=$1TNS_ALIAS=$INST # Use INST name as TNS aliasAPPS_PWD="apps" # Set apps password hereEBS_URL="http://erpfoalabs.training:8000/OA_HTML/AppsLogin"LOG_FILE="/tmp/ebs_health_check_${INST}.html"DATE=$(date '+%Y-%m-%d %H:%M:%S')MAIL_TO="support@funoracleapps.com"MAIL_SUBJECT="EBS Health Check Report $INST - $DATE"OK_COUNT=0WARN_COUNT=0CRIT_COUNT=0# Fetch DB NameDB_NAME=$(sqlplus -s / as sysdba <<EOFSET HEADING OFF FEEDBACK OFFSELECT name FROM v\$database;EXIT;EOF)# HTML Headerecho "<html><head><style>body { font-family: Arial; }table { border-collapse: collapse; width: 100%; }th, td { border: 1px solid #ddd; padding: 8px; }th { background-color: #f2f2f2; }.ok { color: green; font-weight: bold; }.warn { color: orange; font-weight: bold; }.crit { color: red; font-weight: bold; }.summary { font-size: 16px; margin-bottom: 10px; }</style></head><body>" > $LOG_FILEecho "<h2>EBS Health Check Report</h2>" >> $LOG_FILEecho "<p><b>Instance:</b> $INST | <b>DB:</b> $DB_NAME | <b>Timestamp:</b> $DATE</p>" >> $LOG_FILEecho "<div class='summary'><b>Summary:</b> OK: <span class='ok'>0</span> | WARN: <span class='warn'>0</span> | CRIT: <span class='crit'>0</span></div>" >> $LOG_FILE# -------------------------------# 1. EBS Login Page# -------------------------------echo "<h3>EBS Login Page</h3>" >> $LOG_FILE#echo "<p>URL: $EBS_URL$EBS_URL</a></p>" >> $LOG_FILEstatus=$(curl -s -o /dev/null -w "%{http_code}" $EBS_URL)if [ "$status" -eq 200 ]; thenecho "<p class='ok'>Login Page Accessible (URL: $EBS_URL)</p>" >> $LOG_FILE((OK_COUNT++))elseecho "<p class='crit'>Login Page DOWN (URL: $EBS_URL, HTTP Status: $status)</p>" >> $LOG_FILE((CRIT_COUNT++))fi# -------------------------------# 2. Concurrent Managers + Pending Requests# -------------------------------echo "<h3>Concurrent Managers (Actual vs Target Processes)</h3><table><tr><th>Manager</th><th>Node</th><th>Actual</th><th>Target</th><th>Status</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s apps/$APPS_PWD@$TNS_ALIAS <<EOFSET HEADING OFF FEEDBACK OFFSELECT b.user_concurrent_queue_name || '|' || a.target_node || '|' || a.running_processes || '|' || a.max_processes || '|' ||DECODE(b.control_code,'D', 'Deactivating','E', 'Deactivated','N', 'Node unavailable','A', 'Activating','X', 'Terminated','T', 'Terminating','V', 'Verifying','O', 'Suspending','P', 'Suspended','Q', 'Resuming','R', 'Restarting', 'Running')FROM apps.fnd_concurrent_queues a, apps.fnd_concurrent_queues_vl bWHERE a.concurrent_queue_id = b.concurrent_queue_idAND a.max_processes != 0ORDER BY a.max_processes DESC;EXIT;EOF)IFS=$'\n'for line in $output; domgr=$(echo "$line" | cut -d'|' -f1)node=$(echo "$line" | cut -d'|' -f2)actual=$(echo "$line" | cut -d'|' -f3)target=$(echo "$line" | cut -d'|' -f4)status=$(echo "$line" | cut -d'|' -f5)# Highlight red if actual != targetif [[ "$actual" =~ ^[0-9]+$ ]] && [[ "$target" =~ ^[0-9]+$ ]] && [ "$actual" -ne "$target" ]; thencolor="crit"; ((CRIT_COUNT++))elsecolor="ok"; ((OK_COUNT++))fiecho "<tr><td>$mgr</td><td>$node</td><td class='$color'>$actual</td><td>$target</td><td>$status</td></tr>" >> $LOG_FILEdoneecho "</table>" >> $LOG_FILE# -------------------------------# 3. Workflow Mailer & Service Components# -------------------------------echo "<h3>Workflow Mailer & Service Components</h3><table><tr><th>Component</th><th>Status</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s apps/$APPS_PWD@$TNS_ALIAS <<EOFSET HEADING OFF FEEDBACK OFFSELECT component_name||'|'||component_statusFROM fnd_svc_componentsWHERE component_name IN ('Workflow Notification Mailer','Workflow Agent Listener','Workflow Deferred Agent Listener');EXIT;EOF)for line in $output; docomp=$(echo "$line" | cut -d'|' -f1)status=$(echo "$line" | cut -d'|' -f2)color="ok"if [ "$status" != "RUNNING" ]; then color="crit"; ((CRIT_COUNT++)); else ((OK_COUNT++)); fiecho "<tr><td>$comp</td><td class='$color'>$status</td></tr>" >> $LOG_FILEdoneecho "</table>" >> $LOG_FILE# -------------------------------# 4. RAC Node Status# -------------------------------echo "<h3>RAC Node Status</h3><table><tr><th>Instance</th><th>Status</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s / as sysdba <<EOFSET HEADING OFF FEEDBACK OFFSELECT instance_name||'|'||status FROM gv\$instance;EXIT;EOF)for line in $output; doinst=$(echo "$line" | cut -d'|' -f1)status=$(echo "$line" | cut -d'|' -f2)color="ok"if [ "$status" != "OPEN" ]; then color="crit"; ((CRIT_COUNT++)); else ((OK_COUNT++)); fiecho "<tr><td>$inst</td><td class='$color'>$status</td></tr>" >> $LOG_FILEdoneecho "</table>" >> $LOG_FILE# -------------------------------# 5. Tablespace Usage (MAX USED PERCENTAGE >= 70)# -------------------------------echo "<h3>Tablespace Usage (MAX USED PERCENTAGE >= 70)</h3><table border='1'><tr><th>Tablespace</th><th>Auto Ext</th><th>Max Size (MB)</th><th>Free Size (MB)</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s apps/$APPS_PWD@$TNS_ALIAS <<EOFSET HEADING OFF FEEDBACK OFF PAGESIZE 999 LINESIZE 400SELECT tablespace_name||'|'||auto_ext||'|'||max_ts_size||'|'||free_ts_sizeFROM (SELECT df.tablespace_name tablespace_name,max(df.autoextensible) auto_ext,round(df.maxbytes / (1024 * 1024), 2) max_ts_size,round(sum(fs.bytes) / (1024 * 1024), 2) free_ts_size,round((df.bytes - sum(fs.bytes)) / (df.maxbytes) * 100, 2) max_ts_pct_usedFROM dba_free_space fs,(select tablespace_name,sum(bytes) bytes,sum(decode(maxbytes, 0, bytes, maxbytes)) maxbytes,max(autoextensible) autoextensiblefrom dba_data_filesgroup by tablespace_name) dfWHERE fs.tablespace_name (+) = df.tablespace_nameGROUP BY df.tablespace_name, df.bytes, df.maxbytesUNION ALLSELECT df.tablespace_name tablespace_name,max(df.autoextensible) auto_ext,round(df.maxbytes / (1024 * 1024), 2) max_ts_size,round(sum(fs.bytes) / (1024 * 1024), 2) free_ts_size,round((sum(fs.bytes)) / (df.maxbytes) * 100, 2) max_ts_pct_usedFROM (select tablespace_name, bytes_used bytesfrom V\$temp_space_headergroup by tablespace_name, bytes_free, bytes_used) fs,(select tablespace_name,sum(bytes) bytes,sum(decode(maxbytes, 0, bytes, maxbytes)) maxbytes,max(autoextensible) autoextensiblefrom dba_temp_filesgroup by tablespace_name) dfWHERE fs.tablespace_name (+) = df.tablespace_nameGROUP BY df.tablespace_name, df.bytes, df.maxbytes) WHERE max_ts_pct_used >= 70ORDER BY max_ts_pct_used DESC;EXIT;EOF)if [ -z "$output" ]; thenecho "<tr><td colspan='4' class='ok'>No Data</td></tr>" >> $LOG_FILEelsefor line in $output; dots=$(echo "$line" | cut -d'|' -f1)auto_ext=$(echo "$line" | cut -d'|' -f2)max_size=$(echo "$line" | cut -d'|' -f3)free_size=$(echo "$line" | cut -d'|' -f4)# Sanitize and check free sizefree_clean=$(echo "$free_size" | sed 's/[^0-9.]//g')if [ -z "$free_clean" ]; then free_clean=0; fiif (( $(echo "$free_clean < 500" | bc -l) )); thencolor="crit"; ((CRIT_COUNT++))elif (( $(echo "$free_clean < 1024" | bc -l) )); thencolor="warn"; ((WARN_COUNT++))elsecolor="ok"; ((OK_COUNT++))fiecho "<tr><td>$ts</td><td>$auto_ext</td><td>$max_size</td><td class='$color'>$free_size</td></tr>" >> $LOG_FILEdonefiecho "</table>" >> $LOG_FILE# -------------------------------# 6 Blocking Sessions (Apps User, PDB Level)# -------------------------------echo "<h3>Blocking Sessions (Including RAC & PDB)</h3><table border='1'><tr><th>Blocking Status</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s apps/$APPS_PWD@$TNS_ALIAS <<EOFSET HEADING OFF FEEDBACK OFF LINESIZE 200COL blocking_status FOR A120SELECT s1.username || '@' || s1.machine|| ' ( SID=' || s1.sid || ' ) is blocking '|| s2.username || '@' || s2.machine|| ' ( SID=' || s2.sid || ' ) ' AS blocking_statusFROM gv\$lock l1, gv\$session s1, gv\$lock l2, gv\$session s2WHERE s1.sid=l1.sid AND s2.sid=l2.sidAND l1.block=1 AND l2.request > 0AND l1.id1 = l2.id1AND l1.id2 = l2.id2;EXIT;EOF)if [ -z "$output" ]; thenecho "<tr><td class='ok'>No Blocking Sessions</td></tr>" >> $LOG_FILE((OK_COUNT++))elsefor line in $output; doecho "<tr><td class='crit'>$line</td></tr>" >> $LOG_FILE((CRIT_COUNT++))donefiecho "</table>" >> $LOG_FILE# -------------------------------# 7. Expired Users# -------------------------------echo "<h3>Expired Users</h3><table><tr><th>User</th><th>Status</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s / as sysdba <<EOFSET HEADING OFF FEEDBACK OFFSELECT username||'|'||account_status FROM dba_users WHERE account_status LIKE '%EXPIRED%';EXIT;EOF)for line in $output; douser=$(echo "$line" | cut -d'|' -f1)status=$(echo "$line" | cut -d'|' -f2)echo "<tr><td>$user</td><td class='warn'>$status</td></tr>" >> $LOG_FILE((WARN_COUNT++))doneecho "</table>" >> $LOG_FILE# -------------------------------# 8. Alert Log Errors (Last 24 hrs)# -------------------------------echo "<h3>Alert Log Errors (Last 24 hrs)</h3><table border='1'><tr><th>Error</th></tr>" >> $LOG_FILEoutput=$(sqlplus -s / as sysdba <<EOFSET HEADING OFF FEEDBACK OFFSELECT message_text FROM X\$DBGALERTEXT WHERE originating_timestamp > SYSDATE-1 AND message_text LIKE 'ORA-%';EXIT;EOF)if [ -z "$output" ]; thenecho "<tr><td class='ok'>No Data</td></tr>" >> $LOG_FILEelsefor line in $output; doif echo "$line" | grep -q "ORA-00600\|ORA-07445"; thencolor="crit"; ((CRIT_COUNT++))elsecolor="warn"; ((WARN_COUNT++))fiecho "<tr><td class='$color'>$line</td></tr>" >> $LOG_FILEdonefiecho "</table>" >> $LOG_FILE# -------------------------------# 9. Database Backup Status (Last 1 day)# -------------------------------echo "<h3>Database Backup Status</h3>" >> $LOG_FILEbackup_status=$(sqlplus -s / as sysdba <<EOFSET HEADING OFF FEEDBACK OFFSELECT COUNT(*) FROM v\$rman_backup_job_details WHERE start_time > SYSDATE-1 AND status='COMPLETED';EXIT;EOF)# Trim spacesbackup_status=$(echo "$backup_status" | xargs)if [ "$backup_status" -gt 0 ]; thenecho "<p class='ok'>Backup Completed in Last 24 hrs</p>" >> $LOG_FILE((OK_COUNT++))elseecho "<p class='crit'>No Backup Completed in Last 24 hrs</p>" >> $LOG_FILE((CRIT_COUNT++))fiecho "</table>" >> $LOG_FILE# -------------------------------# Overall Health Indicator# -------------------------------if [ "$CRIT_COUNT" -gt 5 ]; thenhealth="<span class='crit'>CRITICAL</span>"elif [ "$CRIT_COUNT" -ge 1 ] && [ "$CRIT_COUNT" -le 5 ]; thenhealth="<span class='warn'>WARNING</span>"elsehealth="<span class='ok'>HEALTHY</span>"fised -i "1i <h3>Overall Health: $health</h3>" $LOG_FILE# Update Summarysed -i "s/OK: <span class='ok'>0<\/span>/OK: <span class='ok'>$OK_COUNT<\/span>/; s/WARN: <span class='warn'>0<\/span>/WARN: <span class='warn'>$WARN_COUNT<\/span>/; s/CRIT: <span class='crit'>0<\/span>/CRIT: <span class='crit'>$CRIT_COUNT<\/span>/" $LOG_FILE# HTML Footerecho "</body></html>" >> $LOG_FILE# -------------------------------# Send Email using sendmail# -------------------------------{echo "Subject: $MAIL_SUBJECT"echo "To: $MAIL_TO"echo "Content-Type: text/html"echo ""cat "$LOG_FILE"} | /usr/sbin/sendmail -t

Post a Comment
Post a Comment