The script for this is below, simple run it from the Caching server:
Apple Script : check_requests.sh
#!/bin/bash
# Output file in current directory
OUTPUT_FILE="ios_cache_report.html"
# Get current timestamp
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
# Get log data
LOG_DATA=$(log show --predicate 'subsystem == "com.apple.AssetCache"' --info --last 2h)
# Process logs to get statistics
TOTAL_IOS_SERVED=$(echo "$LOG_DATA" | grep -E "Served all.*?(ipa|MobileAsset_SoftwareUpdate)" | tail -n 1 | grep -oE "Since server start.*?MB|GB" | grep -oE "[0-9.]+ [MG]B")
TOTAL_IOS_CACHE=$(echo "$LOG_DATA" | grep -E "Served all.*?(ipa|MobileAsset_SoftwareUpdate)" | tail -n 1 | grep -oE "from cache, [0-9.]+ [MG]B" | grep -oE "[0-9.]+ [MG]B")
TOTAL_IOS_INTERNET=$(echo "$LOG_DATA" | grep -E "Served all.*?(ipa|MobileAsset_SoftwareUpdate)" | tail -n 1 | grep -oE "from Internet, [0-9.]+ [MG]B" | grep -oE "[0-9.]+ [MG]B")
# Extract iOS and IPA requests
REQUESTS=$(echo "$LOG_DATA" | awk '
BEGIN { FS="[[:space:]]+"; OFS="|" }
/Received GET request.*\.ipa|Received GET request.*MobileAsset_SoftwareUpdate/ {
for(i=1;i<=NF;i++) {
if($i ~ /^#/) {
id = substr($i, 2)
time = $1
# Get full URL path
for(j=i;j<=NF;j++) {
if($j == "for") {
path = $(j+1)
for(k=j+2;k<=NF;k++) {
path = path " " $k
}
}
}
# Store the request info
print time, id, path, "pending", "no"
}
}
}
/Served all/ {
for(i=1;i<=NF;i++) {
if($i ~ /^#/) {
id = substr($i, 2)
size = ""
cached = "no"
speed = "0"
for(j=i;j<=NF;j++) {
if($j == "all") {
size = $(j+1) " " $(j+2)
}
if($j ~ /cache,/ && $(j-1) != "0") {
cached = "yes"
}
}
if(size != "") {
print time, id, path, size, cached
}
}
}
}' | sort -t'|' -k1,1r | uniq)
# Generate HTML report
cat > "$OUTPUT_FILE" << HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iOS Asset Cache Report</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
max-width: 1400px;
margin: 0 auto;
padding: 20px;
background: #f5f5f7;
color: #1d1d1f;
}
.header {
margin-bottom: 30px;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-title {
flex: 1;
}
.header-time {
font-size: 14px;
color: #86868b;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.stat-card h3 {
margin: 0 0 10px 0;
color: #86868b;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #1d1d1f;
margin-bottom: 5px;
}
.stat-detail {
font-size: 12px;
color: #86868b;
}
.requests-container {
background: white;
border-radius: 10px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
padding: 20px;
overflow-x: auto;
}
.requests-table {
width: 100%;
border-collapse: collapse;
}
.requests-table th {
text-align: left;
padding: 12px;
border-bottom: 1px solid #e6e6e6;
color: #86868b;
font-weight: 500;
white-space: nowrap;
}
.requests-table td {
padding: 12px;
border-bottom: 1px solid #e6e6e6;
}
.badge {
display: inline-block;
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.badge-cache {
background: #e8f5e9;
color: #2e7d32;
}
.badge-internet {
background: #e3f2fd;
color: #1976d2;
}
.badge-ipa {
background: #fff3e0;
color: #e65100;
}
.badge-ios {
background: #f3e5f5;
color: #7b1fa2;
}
.request-id {
font-family: ui-monospace, monospace;
font-size: 0.9em;
color: #666;
}
.timestamp {
font-family: ui-monospace, monospace;
color: #666;
white-space: nowrap;
}
.path-cell {
max-width: 400px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.refresh-time {
color: #86868b;
font-size: 14px;
margin-top: 20px;
text-align: right;
}
</style>
</head>
<body>
<div class="header">
<div class="header-title">
<h1>iOS Asset Cache Report</h1>
<p>Monitoring IPA and iOS Software Updates</p>
</div>
<div class="header-time">
Report generated: $TIMESTAMP
</div>
</div>
<div class="stats-grid">
<div class="stat-card">
<h3>Total iOS Assets Served</h3>
<div class="stat-value">$TOTAL_IOS_SERVED</div>
<div class="stat-detail">Combined IPA and iOS update traffic</div>
</div>
<div class="stat-card">
<h3>From Cache</h3>
<div class="stat-value">$TOTAL_IOS_CACHE</div>
<div class="stat-detail">Bandwidth saved from local cache</div>
</div>
<div class="stat-card">
<h3>From Internet</h3>
<div class="stat-value">$TOTAL_IOS_INTERNET</div>
<div class="stat-detail">Downloaded from Apple servers</div>
</div>
</div>
<div class="requests-container">
<table class="requests-table">
<thead>
<tr>
<th>Time</th>
<th>Request ID</th>
<th>Type</th>
<th>Path</th>
<th>Size</th>
<th>Source</th>
</tr>
</thead>
<tbody>
HTML
# Add request rows to HTML
echo "$REQUESTS" | grep -v "pending" | while IFS='|' read -r time id path size cached; do
# Determine asset type
if [[ $path == *".ipa"* ]]; then
asset_type="IPA"
type_badge="badge-ipa"
elif [[ $path == *"MobileAsset_SoftwareUpdate"* ]]; then
asset_type="iOS Update"
type_badge="badge-ios"
else
continue
fi
cat >> "$OUTPUT_FILE" << ROW
<tr>
<td class="timestamp">$(echo "$time" | cut -d' ' -f2)</td>
<td class="request-id">$id</td>
<td><span class="badge $type_badge">$asset_type</span></td>
<td class="path-cell">$path</td>
<td>$size</td>
<td>
<span class="badge ${cached:+badge-cache}${cached:-badge-internet}">
${cached:+Cache}${cached:-Internet}
</span>
</td>
</tr>
ROW
done
# Complete HTML file
cat >> "$OUTPUT_FILE" << HTML
</tbody>
</table>
</div>
</body>
</html>
HTML
# Open the report in default browser
open "$OUTPUT_FILE" 2>/dev/null || echo "Report generated at: $OUTPUT_FILE"
Phone Log Analysis
If you wish to check the phone, as you have no access to the server, then you need to get a application like HTTP Catcher which you can find here
When this is installed, start the application which will setup a VPN connection to monitor all the data sent from your phone, then simply download an App Store application and when you review the log within the application you will see an entry like this:
Note : Behind the red box you will get the internal IP of your MacOS caching server, rather than the Apple CDN address:
This them proves you are downloading your data from the local MacOS server and not from the Internet.