Skip to content

Zoho Integration Log Analysis Guide

Overview

This guide provides administrators with technical knowledge the tools and techniques to analyze goportalbackend logs to determine:

  1. Whether a call was successfully notified to Zoho CRM
  2. Whether a call recording was successfully uploaded to Zoho CRM

All logs related to Zoho notifications and recording uploads now include the call_id field, making it possible to track the complete lifecycle of a call using only the call ID. This allows you to trace every notification event and recording upload attempt for a specific call.

Tracing Complete Call Lifecycle by Call ID

The most efficient way to analyze Zoho integration status for a call is to filter logs by the call ID. All relevant logs now include the call_id field in structured logging format, allowing you to trace the entire call lifecycle.

Quick Call Lifecycle Trace

## Replace CALL_ID with the actual call ID
CALL_ID="2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

## Get all Zoho-related logs for this call
journalctl -u goportalbackend | grep "callID=$CALL_ID\|call_id=$CALL_ID" | grep -E "(zoho|Zoho|ZOHO)"

Complete Call Lifecycle Analysis Script

#!/bin/bash
## Save as trace_call_lifecycle.sh

CALL_ID="$1"

if [ -z "$CALL_ID" ]; then
    echo "Usage: $0 <call_id>"
    exit 1
fi

echo "=========================================="
echo "Complete Call Lifecycle Trace for: $CALL_ID"
echo "=========================================="
echo ""

## Extract all logs containing this call ID
ALL_LOGS=$(journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID")

echo "=== CALL CREATION & INITIAL PROCESSING ==="
echo "$ALL_LOGS" | grep -E "(CHANNEL_CREATE|Processing.*CHANNEL_CREATE)" | head -10
echo ""

echo "=== RINGING NOTIFICATIONS ==="
echo "Outbound ringing attempts:"
echo "$ALL_LOGS" | grep -E "(Processing Outbound CHANNEL_CREATE|Sending ringing notification to Zoho)" | head -5
echo ""
echo "Ringing notification results:"
echo "$ALL_LOGS" | grep -E "(Sent ringing notification|Could not notify.*ringing)" | head -5
echo ""
echo "Ringing notification responses from Zoho:"
echo "$ALL_LOGS" | grep -E "Response after sending a call notify \[ringing\]" | head -5
echo ""

echo "=== ANSWERED NOTIFICATIONS ==="
echo "Answered notification attempts:"
echo "$ALL_LOGS" | grep -E "(CHANNEL_ANSWER|Could not notify.*answered)" | head -5
echo ""
echo "Answered notification responses from Zoho:"
echo "$ALL_LOGS" | grep -E "Response after sending a call notify \[answered\]" | head -5
echo ""

echo "=== CALL ENDED NOTIFICATIONS ==="
echo "Call end attempts:"
echo "$ALL_LOGS" | grep -E "(CHANNEL_DESTROY|Could not notify.*call.*event)" | head -5
echo ""
echo "Call end notification responses from Zoho:"
echo "$ALL_LOGS" | grep -E "Response after sending a call notify \[ended\]|Response after sending a call notify \[invalid\]|Response after sending a call notify \[busy\]" | head -5
echo ""

echo "=== RECORDING UPLOAD PROCESS ==="
echo "Recording upload initiation:"
echo "$ALL_LOGS" | grep -E "zoho uri update: Event name is ChannelDestroy" | head -1
echo ""
echo "Recording search process:"
echo "$ALL_LOGS" | grep -E "(about to update voice URI|Could not get recording)" | head -5
echo ""
echo "Recording upload results:"
echo "$ALL_LOGS" | grep -E "(Successfully updated voice URI|Recording URI uploaded|Failed to update voice URI|Could not upload the recording URI)" | head -5
echo ""

echo "=== ALL ERRORS FOR THIS CALL ==="
echo "$ALL_LOGS" | grep -E "(Could not notify|Failed to|error|Error)" | head -10
echo ""

echo "=== SUMMARY ==="
RINGING_SENT=$(echo "$ALL_LOGS" | grep -c "Sent ringing notification to Zoho with callID: $CALL_ID")
RINGING_RESPONSE=$(echo "$ALL_LOGS" | grep -c "Response after sending a call notify \[ringing\].*call_id=$CALL_ID")
ANSWERED_RESPONSE=$(echo "$ALL_LOGS" | grep -c "Response after sending a call notify \[answered\].*call_id=$CALL_ID")
ENDED_RESPONSE=$(echo "$ALL_LOGS" | grep -c "Response after sending a call notify \[ended\].*call_id=$CALL_ID")
RECORDING_SUCCESS=$(echo "$ALL_LOGS" | grep -c -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO).*call_id=$CALL_ID")
RECORDING_FAILED=$(echo "$ALL_LOGS" | grep -c -E "(Failed to update voice URI|Could not upload the recording URI).*call_id=$CALL_ID")

echo "Ringing notifications sent: $RINGING_SENT"
echo "Ringing responses received: $RINGING_RESPONSE"
echo "Answered responses received: $ANSWERED_RESPONSE"
echo "Ended responses received: $ENDED_RESPONSE"
echo "Recording upload successful: $RECORDING_SUCCESS"
echo "Recording upload failed: $RECORDING_FAILED"
echo ""

if [ "$RINGING_SENT" -gt 0 ] && [ "$RINGING_RESPONSE" -gt 0 ] && [ "$ANSWERED_RESPONSE" -gt 0 ] && [ "$ENDED_RESPONSE" -gt 0 ] && [ "$RECORDING_SUCCESS" -gt 0 ]; then
    echo "✓ STATUS: Complete - All notifications and recording upload successful"
elif [ "$RECORDING_FAILED" -gt 0 ]; then
    echo "✗ STATUS: Partial - Notifications sent but recording upload failed"
elif [ "$ENDED_RESPONSE" -eq 0 ]; then
    echo "⚠ STATUS: Incomplete - Call may still be in progress or ended notification failed"
else
    echo "⚠ STATUS: Unknown - Check logs above for details"
fi

Usage:

chmod +x trace_call_lifecycle.sh
./trace_call_lifecycle.sh 2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

One-Line Complete Trace

## Replace CALL_ID with the actual call ID
CALL_ID="2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

## Get all Zoho-related events for this call in chronological order
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Processing|Sending|Sent|Response after sending|Could not notify|zoho uri update|voice URI|recording)" | \
  sort

Filtering by Call ID in Structured Logs

Since all logs use structured logging with callID or call_id fields, you can use more precise filtering:

CALL_ID="2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

## Find all notification attempts
journalctl -u goportalbackend | grep "callID=$CALL_ID" | grep -E "(Sending|Processing)"

## Find all notification responses
journalctl -u goportalbackend | grep "call_id=$CALL_ID" | grep "Response after sending"

## Find all errors
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -E "(Could not|Failed|Error|error)"

## Find recording upload status
journalctl -u goportalbackend | grep "call_id=$CALL_ID" | grep -E "(zoho uri update|voice URI|recording)"

Key Log Fields for Call ID Tracking

All logs now include the callID or call_id field. Here are the key log messages you can filter:

Log Message Contains Call ID Field Purpose
Processing Outbound CHANNEL_CREATE event callID Call creation
Processing Inbound CHANNEL_CREATE event callID Call creation
Sending ringing notification to Zoho callID Ringing notification attempt
Sent ringing notification to Zoho with callID: Text includes callID Ringing notification success
Could not notify to zoho about the outbound call ringing event callID Ringing notification failure
Could not notify to zoho about the inbound call ringing event callID Ringing notification failure
Could not notify to zoho about the outbound call answered event callID Answered notification failure
Could not notify to zoho about the inbound call answered event callID Answered notification failure
Could not notify to zoho about the outbound call event callID Call end notification failure
Could not notify to zoho about the inbound call event callID Call end notification failure
Could not notify to zoho about the click to dial invalid error event callID Click-to-dial error
Could not notify to zoho about the click to dial error event callID Click-to-dial error
Could not notify to zoho about the call notify event callID Call notify error
Response after sending a call notify call_id Zoho API response
zoho uri update: Event name is ChannelDestroy call_id Recording upload initiation
about to update voice URI in Zoho call_id Recording found, ready to upload
Successfully updated voice URI in Zoho call_id Recording upload success
Failed to update voice URI in Zoho call_id Recording upload failure
Could not upload the recording URI to zoho call_id Recording upload failure
Recording URI uploaded to ZOHO call_id Recording upload success

Note: All error logs now include the callID field in structured format, making it easy to trace issues for specific calls. Use grep -E "callID=<call_id>|call_id=<call_id>" to find all related logs for a call.

Timeline View of Call Events

#!/bin/bash
## Save as call_timeline.sh - Shows events in chronological order

CALL_ID="$1"

if [ -z "$CALL_ID" ]; then
    echo "Usage: $0 <call_id>"
    exit 1
fi

echo "Timeline for Call ID: $CALL_ID"
echo "================================"
echo ""

journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Processing|Sending|Sent|Response|zoho uri update|Could not|Failed|Successfully)" | \
  awk '{
    # Extract timestamp and message
    match($0, /time="([^"]+)"/, time_match)
    if (time_match[1] != "") {
        print time_match[1] " | " $0
    } else {
        print $0
    }
  }' | sort

Usage:

chmod +x call_timeline.sh
./call_timeline.sh 2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

Prerequisites

  • Access to the server where goportalbackend is running
  • Basic knowledge of command-line tools (grep, awk, sed, jq)
  • Access to log files (typically /var/log/goportalbackend/ or journald logs)
  • Understanding of call IDs, account IDs, and user extensions

Log File Locations

Systemd Journal

## View recent logs
journalctl -u goportalbackend -f

## View logs for a specific date
journalctl -u goportalbackend --since "2025-10-30 10:00:00" --until "2025-10-30 11:00:00"

Log Files (if using file-based logging)

## Typical locations
/var/log/goportalbackend/goportalbackend.log
/var/log/goportalbackend/goportalbackend.log.*

Understanding Call Notifications to Zoho

Call Notification Flow

Call notifications are sent to Zoho at different stages: 1. Ringing - When a call starts ringing 2. Answered - When a call is answered 3. Ended/Busy/Invalid/etc. - When a call ends with various states

Key Log Patterns for Call Notifications

1. Successful Call Notification

Pattern: Sent ringing notification to Zoho with callID:

## Search for successful ringing notifications
grep "Sent ringing notification to Zoho with callID:" /var/log/goportalbackend/*.log

## With journald
journalctl -u goportalbackend | grep "Sent ringing notification to Zoho with callID:"

Example log entry:

time="2025-10-30 18:56:23" level=info msg="Sent ringing notification to Zoho with callID: 2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

2. Successful Call State Notification

Pattern: Response after sending a call notify

## Find all call notify responses
grep "Response after sending a call notify" /var/log/goportalbackend/*.log

## Filter by call state (ringing, answered, ended, etc.)
grep "Response after sending a call notify \[ringing\]" /var/log/goportalbackend/*.log
grep "Response after sending a call notify \[answered\]" /var/log/goportalbackend/*.log
grep "Response after sending a call notify \[ended\]" /var/log/goportalbackend/*.log

Example log entry:

level=info msg="Response after sending a call notify [ringing] request to ZOHO" 
response="{success SUCCESS}" call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

3. Failed Call Notification

Pattern: Could not notify to zoho

## Find all failed notifications
grep "Could not notify to zoho" /var/log/goportalbackend/*.log

## Filter by call direction
grep "Could not notify to zoho about the outbound" /var/log/goportalbackend/*.log
grep "Could not notify to zoho about the inbound" /var/log/goportalbackend/*.log

## Filter by call state
grep "Could not notify to zoho.*ringing" /var/log/goportalbackend/*.log
grep "Could not notify to zoho.*answered" /var/log/goportalbackend/*.log

Example log entry:

level=error msg="Could not notify to zoho about the outbound call ringing event for the [2256] user. [network error]"

4. Filtered Events (Not Notified)

Pattern: Event was filtered and not stored in calls map

## Find filtered events
grep "Event was filtered and not stored in calls map" /var/log/goportalbackend/*.log
grep "CC Event was filtered and not stored in calls map" /var/log/goportalbackend/*.log

Example log entry:

level=info msg="readMessage: Event was filtered and not stored in calls map, skipping Zoho notifications" 
event_name=CHANNEL_CREATE caller_id=1234 callee_id=5678

Complete Call Notification Analysis

Analyze a Specific Call by Call ID

Recommended Method (using structured log fields):

## Replace CALL_ID with the actual call ID
CALL_ID="2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

## Check if call was notified at all stages using structured fields
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Sent ringing|Response after sending|Could not notify|Processing)"

## Alternative: search in log text (for older log format)
journalctl -u goportalbackend | grep "$CALL_ID" | grep -E "(Sent ringing|Response after sending|Could not notify)"

Example Output:

Processing Outbound CHANNEL_CREATE event for ringing notification callID=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
Sending ringing notification to Zoho with real callID callID=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
Sent ringing notification to Zoho with callID: 2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
Response after sending a call notify [ringing] request to ZOHO call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
Response after sending a call notify [answered] request to ZOHO call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
Response after sending a call notify [ended] request to ZOHO call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

Check Notification Status for a Specific Time Range

## Set your time range
START_TIME="2025-10-30 10:00:00"
END_TIME="2025-10-30 11:00:00"

## Extract all call notifications in the time range
journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
  grep -E "(Sent ringing|Response after sending|Could not notify)" | \
  awk '{print $1, $2, $NF}'

Count Successful vs Failed Notifications

## Count successful notifications
journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c "Response after sending a call notify.*SUCCESS"

## Count failed notifications
journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c "Could not notify to zoho"

## Calculate success rate
TOTAL=$(journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c "Response after sending a call notify")
SUCCESS=$(journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c "Response after sending a call notify.*SUCCESS")
RATE=$(echo "scale=2; $SUCCESS * 100 / $TOTAL" | bc)
echo "Success rate: $RATE%"

Understanding Recording Uploads to Zoho

Recording Upload Flow

Recordings are uploaded to Zoho after a call ends (CHANNEL_DESTROY event). The process: 1. Wait 1 second after call ends 2. Search for recording by CallID, then by filename, then by InteractionID 3. Generate voice URI with authorization token 4. Upload URI to Zoho via PhoneBridge API

Key Log Patterns for Recording Uploads

1. Recording Upload Initiation

Pattern: zoho uri update: Event name is ChannelDestroy

## Find when recording upload process starts
grep "zoho uri update: Event name is ChannelDestroy" /var/log/goportalbackend/*.log

## With journald
journalctl -u goportalbackend | grep "zoho uri update: Event name is ChannelDestroy"

Example log entry:

level=info msg="zoho uri update: Event name is ChannelDestroy, starting process to upload the recording URI to zoho" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 account_id=b02d27af637452b70ac6abbd8385f491

2. Recording Search Process

Pattern: about to update voice URI in Zoho

## Find when recording is found and ready to upload
grep "about to update voice URI in Zoho" /var/log/goportalbackend/*.log

Example log entry:

level=info msg="about to update voice URI in Zoho" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
recording_id=202510-l6mp2dy4iKvK4rQu9SRM 
voice_uri="https://lab.fonouc.com/api/v2/config/crm/zoho/integration/recordings/..."

3. Successful Recording Upload

Pattern: Successfully updated voice URI in Zoho OR zoho uri update: Recording URI uploaded to ZOHO

## Find successful uploads
grep -E "(Successfully updated voice URI in Zoho|zoho uri update: Recording URI uploaded to ZOHO)" /var/log/goportalbackend/*.log

## With journald
journalctl -u goportalbackend | grep -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)"

Example log entry:

level=info msg="Successfully updated voice URI in Zoho" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
recording_id=202510-l6mp2dy4iKvK4rQu9SRM 
voice_uri="https://..."

Alternative success pattern:

level=info msg="zoho uri update: Recording URI uploaded to ZOHO" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
account_id=b02d27af637452b70ac6abbd8385f491 duration=1.094651197s

4. Failed Recording Upload

Pattern: Failed to update voice URI in Zoho OR Could not upload the recording URI to zoho

## Find failed uploads
grep -E "(Failed to update voice URI in Zoho|Could not upload the recording URI to zoho)" /var/log/goportalbackend/*.log

## With journald
journalctl -u goportalbackend | grep -E "(Failed to update voice URI|Could not upload the recording URI)"

Example log entry:

level=error msg="Failed to update voice URI in Zoho" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
recording_id=202510-l6mp2dy4iKvK4rQu9SRM 
error="could not update the voicemail uri: API error"

Alternative error pattern:

level=error msg="ZOHO uri update: Could not upload the recording URI to zoho" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
account_id=b02d27af637452b70ac6abbd8385f491 error="..."

5. Recording Not Found

Pattern: could not get recording

## Find cases where recording couldn't be found
grep "could not get recording" /var/log/goportalbackend/*.log

## More specific patterns
grep "Could not get recording by filename from CDR" /var/log/goportalbackend/*.log
grep "could not get recording for callID.*after all search attempts" /var/log/goportalbackend/*.log

Example log entry:

level=error msg="Could not get recording by filename from CDR" 
call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 
recording_filename=recording.wav error="..."

Complete Recording Upload Analysis

Analyze Recording Upload for a Specific Call

Recommended Method (using structured log fields):

## Replace CALL_ID with the actual call ID
CALL_ID="2cd0ec68-58c2-48f7-8220-3a1e8ad9b170"

## Check recording upload status using structured fields
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(zoho uri update|voice URI|recording|Could not upload|Failed to update)"

Example Output:

zoho uri update: Event name is ChannelDestroy, starting process to upload the recording URI to zoho call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
about to update voice URI in Zoho call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170 recording_id=202510-l6mp2dy4iKvK4rQu9SRM
Successfully updated voice URI in Zoho call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170
zoho uri update: Recording URI uploaded to ZOHO call_id=2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

Check Recording Upload Status for a Specific Time Range

## Set your time range
START_TIME="2025-10-30 10:00:00"
END_TIME="2025-10-30 11:00:00"

## Extract all recording upload attempts
journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
  grep -E "(zoho uri update|voice URI|recording)" | \
  awk '{print $1, $2, $NF}'

Count Successful vs Failed Recording Uploads

## Count successful uploads
journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)"

## Count failed uploads
journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c -E "(Failed to update voice URI|Could not upload the recording URI)"

## Calculate success rate
TOTAL=$(journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c "zoho uri update: Event name is ChannelDestroy")
SUCCESS=$(journalctl -u goportalbackend --since "2025-10-30" | \
  grep -c -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)")
RATE=$(echo "scale=2; $SUCCESS * 100 / $TOTAL" | bc)
echo "Recording upload success rate: $RATE%"

Combined Analysis: Complete Call Lifecycle

Analyze Both Notification and Recording for a Specific Call

#!/bin/bash
## Save as analyze_call.sh

CALL_ID="$1"

if [ -z "$CALL_ID" ]; then
    echo "Usage: $0 <call_id>"
    exit 1
fi

echo "=== Analysis for Call ID: $CALL_ID ==="
echo ""

echo "--- Call Notifications ---"
echo "Ringing notifications:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -E "(Sent ringing|Response after sending.*ringing)" | head -5

echo ""
echo "Answered notifications:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -E "(Response after sending.*answered)" | head -5

echo ""
echo "Ended notifications:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -E "(Response after sending.*ended)" | head -5

echo ""
echo "Failed notifications:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep "Could not notify" | head -5

echo ""
echo "--- Recording Upload ---"
echo "Upload initiation:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep "zoho uri update: Event name is ChannelDestroy" | head -1

echo ""
echo "Upload status:"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -E "(Successfully updated voice URI|Recording URI uploaded|Failed to update|Could not upload)" | head -5

echo ""
echo "--- Summary ---"
NOTIFICATION_COUNT=$(journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -c "Response after sending.*SUCCESS")
RECORDING_SUCCESS=$(journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -c -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)")
RECORDING_FAILED=$(journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -c -E "(Failed to update voice URI|Could not upload the recording URI)")

echo "Call notifications sent: $NOTIFICATION_COUNT"
if [ "$RECORDING_SUCCESS" -gt 0 ]; then
    echo "Recording upload: SUCCESS"
elif [ "$RECORDING_FAILED" -gt 0 ]; then
    echo "Recording upload: FAILED"
else
    echo "Recording upload: NOT ATTEMPTED or IN PROGRESS"
fi

Usage:

chmod +x analyze_call.sh
./analyze_call.sh 2cd0ec68-58c2-48f7-8220-3a1e8ad9b170

Analyze Multiple Calls by Account ID

#!/bin/bash
## Save as analyze_account.sh

ACCOUNT_ID="$1"
START_TIME="${2:-2025-10-30 00:00:00}"
END_TIME="${3:-2025-10-30 23:59:59}"

if [ -z "$ACCOUNT_ID" ]; then
    echo "Usage: $0 <account_id> [start_time] [end_time]"
    exit 1
fi

echo "=== Analysis for Account: $ACCOUNT_ID ==="
echo "Time range: $START_TIME to $END_TIME"
echo ""

## Extract all call IDs for this account
CALL_IDS=$(journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
  grep "account_id=$ACCOUNT_ID" | \
  grep -oP 'call_id=\K[a-f0-9-]+' | \
  sort -u)

TOTAL_CALLS=$(echo "$CALL_IDS" | wc -l)
echo "Total calls found: $TOTAL_CALLS"
echo ""

SUCCESSFUL_NOTIFICATIONS=0
FAILED_NOTIFICATIONS=0
SUCCESSFUL_RECORDINGS=0
FAILED_RECORDINGS=0

for CALL_ID in $CALL_IDS; do
    NOTIF_COUNT=$(journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
      grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -c "Response after sending.*SUCCESS")
    if [ "$NOTIF_COUNT" -gt 0 ]; then
        SUCCESSFUL_NOTIFICATIONS=$((SUCCESSFUL_NOTIFICATIONS + 1))
    else
        FAILED_NOTIFICATIONS=$((FAILED_NOTIFICATIONS + 1))
    fi

    if journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
      grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -q -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)"; then
        SUCCESSFUL_RECORDINGS=$((SUCCESSFUL_RECORDINGS + 1))
    elif journalctl -u goportalbackend --since "$START_TIME" --until "$END_TIME" | \
      grep -E "callID=$CALL_ID|call_id=$CALL_ID" | grep -q -E "(Failed to update voice URI|Could not upload the recording URI)"; then
        FAILED_RECORDINGS=$((FAILED_RECORDINGS + 1))
    fi
done

echo "=== Results ==="
echo "Call Notifications:"
echo "  Successful: $SUCCESSFUL_NOTIFICATIONS"
echo "  Failed: $FAILED_NOTIFICATIONS"
echo ""
echo "Recording Uploads:"
echo "  Successful: $SUCCESSFUL_RECORDINGS"
echo "  Failed: $FAILED_RECORDINGS"
echo "  Not attempted: $((TOTAL_CALLS - SUCCESSFUL_RECORDINGS - FAILED_RECORDINGS))"

Usage:

chmod +x analyze_account.sh
./analy_account.sh b02d27af637452b70ac6abbd8385f491 "2025-10-30 10:00:00" "2025-10-30 11:00:00"

Advanced Analysis Techniques

Using jq for JSON Log Analysis

If your logs are in JSON format:

## Parse JSON logs and extract call notification status
cat goportalbackend.log | jq -r 'select(.msg | contains("Response after sending a call notify")) | 
  {time: .time, call_id: .call_id, state: .state, success: .response}'

## Extract recording upload status
cat goportalbackend.log | jq -r 'select(.msg | contains("zoho uri update")) | 
  {time: .time, call_id: .call_id, status: .msg}'

Creating a Monitoring Dashboard

#!/bin/bash
## Save as zoho_monitor.sh - Run periodically (e.g., every 5 minutes)

LOG_FILE="/tmp/zoho_status_$(date +%Y%m%d_%H%M%S).txt"

echo "=== Zoho Integration Status ===" > "$LOG_FILE"
echo "Generated: $(date)" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"

## Last hour statistics
SINCE_TIME="1 hour ago"

echo "--- Last Hour Statistics ---" >> "$LOG_FILE"
TOTAL_CALLS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c "Response after sending a call notify")
SUCCESS_CALLS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c "Response after sending.*SUCCESS")
FAILED_CALLS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c "Could not notify to zoho")

TOTAL_RECORDINGS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c "zoho uri update: Event name is ChannelDestroy")
SUCCESS_RECORDINGS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c -E "(Successfully updated voice URI|Recording URI uploaded to ZOHO)")
FAILED_RECORDINGS=$(journalctl -u goportalbackend --since "$SINCE_TIME" | grep -c -E "(Failed to update voice URI|Could not upload the recording URI)")

echo "Call Notifications:" >> "$LOG_FILE"
echo "  Total: $TOTAL_CALLS" >> "$LOG_FILE"
echo "  Successful: $SUCCESS_CALLS" >> "$LOG_FILE"
echo "  Failed: $FAILED_CALLS" >> "$LOG_FILE"
if [ "$TOTAL_CALLS" -gt 0 ]; then
    RATE=$(echo "scale=2; $SUCCESS_CALLS * 100 / $TOTAL_CALLS" | bc)
    echo "  Success Rate: $RATE%" >> "$LOG_FILE"
fi

echo "" >> "$LOG_FILE"
echo "Recording Uploads:" >> "$LOG_FILE"
echo "  Total: $TOTAL_RECORDINGS" >> "$LOG_FILE"
echo "  Successful: $SUCCESS_RECORDINGS" >> "$LOG_FILE"
echo "  Failed: $FAILED_RECORDINGS" >> "$LOG_FILE"
if [ "$TOTAL_RECORDINGS" -gt 0 ]; then
    RATE=$(echo "scale=2; $SUCCESS_RECORDINGS * 100 / $TOTAL_RECORDINGS" | bc)
    echo "  Success Rate: $RATE%" >> "$LOG_FILE"
fi

echo "" >> "$LOG_FILE"
echo "--- Recent Errors (Last 10) ---" >> "$LOG_FILE"
journalctl -u goportalbackend --since "$SINCE_TIME" | \
  grep -E "(Could not notify|Failed to update|Could not upload)" | \
  tail -10 >> "$LOG_FILE"

cat "$LOG_FILE"

Common Issues and Troubleshooting

Issue: Call Not Notified to Zoho

Symptoms: - No log entries for "Sent ringing notification" or "Response after sending" - Log shows "Event was filtered and not stored"

Possible Causes: 1. Event was filtered due to duplicate detection 2. User doesn't have Zoho integration enabled 3. Call was internal (extension to extension) without Zoho sync

Check:

## Find why call was filtered
grep "<call_id>" /var/log/goportalbackend/*.log | grep -E "(filtered|skipping Zoho)"

Issue: Recording Not Uploaded

Symptoms: - Log shows "Could not get recording" errors - No "Successfully updated voice URI" log entry

Possible Causes: 1. Recording not found by CallID, filename, or InteractionID 2. User doesn't have Zoho integration enabled 3. Recording file doesn't exist

Check:

## Find recording search attempts
grep "<call_id>" /var/log/goportalbackend/*.log | grep -E "(recording|Could not get recording)"

Issue: Partial Notification (Some Events Missing)

Symptoms: - Ringing notification sent but no answered notification - Answered notification sent but no ended notification

Possible Causes: 1. Network issues during call 2. Zoho API temporary unavailability 3. Call ended before certain events could be processed

Check:

## Find all notification attempts for a call
grep "<call_id>" /var/log/goportalbackend/*.log | grep -E "(Sent|Response after sending|Could not notify)"

Quick Reference Cheat Sheet

## === TRACE COMPLETE CALL LIFECYCLE BY CALL ID (RECOMMENDED) ===
CALL_ID="your-call-id-here"

## Get all Zoho-related events for a call
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Processing|Sending|Sent|Response|zoho uri update|Could not|Failed|Successfully)"

## === CHECK IF CALL WAS NOTIFIED (replace CALL_ID) ===
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Sent ringing|Response after sending)"

## === CHECK IF RECORDING WAS UPLOADED (replace CALL_ID) ===
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Successfully updated voice URI|Recording URI uploaded)"

## === FIND ALL FAILED NOTIFICATIONS TODAY ===
journalctl -u goportalbackend --since today | grep -E "callID=|call_id=" | \
  grep "Could not notify to zoho"

## === FIND ALL FAILED RECORDING UPLOADS TODAY ===
journalctl -u goportalbackend --since today | grep -E "callID=|call_id=" | \
  grep -E "(Failed to update voice URI|Could not upload the recording URI)"

## === GET CALL NOTIFICATION SUCCESS RATE FOR TODAY ===
TOTAL=$(journalctl -u goportalbackend --since today | \
  grep -E "callID=|call_id=" | grep -c "Response after sending a call notify")
SUCCESS=$(journalctl -u goportalbackend --since today | \
  grep -E "callID=|call_id=" | grep -c "Response after sending.*SUCCESS")
echo "Success rate: $(echo "scale=2; $SUCCESS * 100 / $TOTAL" | bc)%"

Complete Call Lifecycle Trace by Call ID

The most comprehensive way to analyze a call is to use the complete trace script:

## Trace complete lifecycle (see script above)
./trace_call_lifecycle.sh <call_id>

This script will show: - All notification attempts (ringing, answered, ended) - All notification responses from Zoho - Recording upload initiation and results - All errors for the call - Summary status

Conclusion

This guide provides comprehensive tools for analyzing Zoho integration logs. All logs now include the callID or call_id field, making it possible to track the complete lifecycle of any call using only the call ID.

Key Improvements

  1. Complete Call Tracking: All Zoho-related logs include the call ID, allowing you to trace every notification and recording upload attempt for a specific call
  2. Structured Logging: Error logs use structured fields (callID, call_id) making them easy to filter and analyze
  3. Easy Troubleshooting: With a call ID, you can quickly identify all Zoho integration events for that call

Quick Start

To trace a complete call lifecycle, simply use:

CALL_ID="your-call-id-here"
journalctl -u goportalbackend | grep -E "callID=$CALL_ID|call_id=$CALL_ID" | \
  grep -E "(Processing|Sending|Sent|Response|zoho uri update|Could not|Failed|Successfully)"

Or use the comprehensive script:

./trace_call_lifecycle.sh <call_id>

Use the scripts and commands provided to:

  1. Verify call notifications - Ensure calls are being sent to Zoho at all stages
  2. Verify recording uploads - Ensure recordings are successfully uploaded after calls end
  3. Troubleshoot issues - Identify why specific calls or recordings failed
  4. Monitor health - Track success rates and identify patterns

For additional support, refer to the goportalbackend source code or contact the development team.