Play Session Monitoring¶
Play sessions are records of subscribers watching channels. Catena automatically registers each stream opening and saves detailed session information for monitoring, analytics, and debugging.
What is a Play Session¶
A play session is a period of time when a subscriber watches a specific channel. Each session contains information about who, what, when, and from where they watched.
Session lifecycle:
Stream opening → Active viewing → Stream closing
(openedAt) (active: true) (closedAt)
What is recorded:
- Who is watching: subscriberId, token
- What is being watched: channelId, channelName, programId
- When: openedAt, closedAt, updatedAt (timestamps)
- From where: IP address, userAgent (player/device)
- How much: bytes (data transferred), session duration
- Status: active (session open or closed)
Applications:
- Real-time monitoring — who is watching channels now
- Problem debugging — why subscriber can't watch channel
- Viewing analytics — popular channels, viewing time
- Billing — traffic consumption calculation
- Security — anomaly detection (one token from different IPs)
- Statistics — reports for content owners
Play Session Structure¶
Main Fields¶
Identifiers:
- sessionId — unique session ID
- Format: base64-encoded Snowflake ID
- Example:
sessKl9SW3AAAE.
-
Generated when opening stream
-
subscriberId — ID of subscriber watching channel
- Link to user account
-
Example:
sKl9SW3AAAE.
-
channelId — ID of channel being watched
-
Example:
chKl9SW3AAAE.
-
channelName — technical channel name
- More convenient for debugging than ID
-
Example:
sport1
,news-hd
-
programId — program ID (if watching from archive)
- Null for live viewing
-
Example:
prKl9SW3AAAE.
-
portalId — portal ID
- Data isolation between portals
- Example:
pKl9SW3AAAE.
Timestamps:
- openedAt — Unix timestamp of session opening
- When subscriber started watching
-
Example:
1714233600
(April 28, 2024, 10:00:00 UTC) -
closedAt — Unix timestamp of session closing
- When stream was stopped
- Null for active sessions
-
Example:
1714237200
-
updatedAt — Unix timestamp of last update
- Updated periodically during viewing
- Used to determine "dead" connections
Network information:
- ip — subscriber's IP address
- Example:
192.168.1.100
,2001:db8::1
-
Used for geolocation and anomaly detection
-
userAgent — player User-Agent string
- Identifies device and application
- Examples:
VLC/3.0.16
Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36
Catena/1.0 (Android 11; Samsung SM-G991B)
Statistics:
- active — session activity flag
true
— session open, viewing in progress-
false
— session closed, viewing finished -
bytes — data transferred in bytes
- Updated during viewing
- Example:
5242880000
(5 GB) -
Used for traffic billing
-
token — subscriber's playback token
- Used by streaming server for authorization
- Example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Device:
- deviceId — device identifier
- If app sends device ID
- Example:
device_android_samsung_s21
- Helps track number of devices per subscriber
Getting Session List¶
Basic Request¶
Get list of all sessions:
curl -X GET https://your-catena-domain.com/tv-management/api/v1/play-sessions \
-H "X-Auth-Token: your-api-key"
Response:
{
"sessions": [
{
"sessionId": "sessKl9SW3AAAE.",
"subscriberId": "sKl9SW3AAAE.",
"channelId": "chKl9SW3AAAE.",
"channelName": "sport1",
"programId": null,
"portalId": "pKl9SW3AAAE.",
"openedAt": 1714233600,
"closedAt": null,
"updatedAt": 1714237200,
"active": true,
"bytes": 1073741824,
"ip": "192.168.1.100",
"userAgent": "Catena/1.0 (Android 11)",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"deviceId": "device_123"
},
{
"sessionId": "sessKl9SW3AAAB.",
"subscriberId": "sKl9SW3AAAB.",
"channelId": "chKl9SW3AAAB.",
"channelName": "news-hd",
"programId": null,
"portalId": "pKl9SW3AAAE.",
"openedAt": 1714230000,
"closedAt": 1714233600,
"updatedAt": 1714233600,
"active": false,
"bytes": 524288000,
"ip": "10.0.0.50",
"userAgent": "VLC/3.0.16",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"deviceId": null
}
],
"next": "cursor-for-next-page"
}
Pagination¶
For large data volumes, cursor-based pagination is used:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?cursor=cursor-for-next-page" \
-H "X-Auth-Token: your-api-key"
Recommendations:
- Process data page by page
- Use filters to reduce volume
- For periodic monitoring, query only active sessions
Session Filtering¶
By Subscriber¶
Get all sessions for specific subscriber:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?subscriberId=sKl9SW3AAAE." \
-H "X-Auth-Token: your-api-key"
Applications:
- View specific user history
- Debug subscriber issues
- Analyze viewing patterns
Multiple subscribers:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?subscriberId=sKl9SW3AAAE.&subscriberId=sKl9SW3AAAB." \
-H "X-Auth-Token: your-api-key"
By Channel¶
Get all sessions for specific channel:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?channelId=chKl9SW3AAAE." \
-H "X-Auth-Token: your-api-key"
Applications:
- Determine channel popularity
- Analyze channel load peaks
- Debug specific channel issues
Multiple channels:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?channelId=chKl9SW3AAAE.&channelId=chKl9SW3AAAB." \
-H "X-Auth-Token: your-api-key"
By Activity Status¶
Only active sessions (who is watching now):
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?active=true" \
-H "X-Auth-Token: your-api-key"
Only completed sessions (history):
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?active=false" \
-H "X-Auth-Token: your-api-key"
Applications:
- active=true — real-time monitoring
- active=false — history analysis, report building
By Time¶
Sessions opened after specific time:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?opened_at_gte=1714233600" \
-H "X-Auth-Token: your-api-key"
Sessions opened before specific time:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?opened_at_lt=1714320000" \
-H "X-Auth-Token: your-api-key"
Sessions in time interval:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?opened_at_gte=1714233600&opened_at_lt=1714320000" \
-H "X-Auth-Token: your-api-key"
Applications:
- Analyze views for specific period
- Build time-based graphs
- Identify peak hours
Converting dates to Unix timestamp:
# Current date/time
date +%s
# Result: 1714233600
# Specific date (GNU date)
date -d "2024-04-28 10:00:00" +%s
# macOS
date -j -f "%Y-%m-%d %H:%M:%S" "2024-04-28 10:00:00" +%s
Combined Filters¶
Active sessions for specific subscriber:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?subscriberId=sKl9SW3AAAE.&active=true" \
-H "X-Auth-Token: your-api-key"
Channel sessions for last 24 hours:
# Current time minus 24 hours
TIMESTAMP_24H_AGO=$(date -d '24 hours ago' +%s)
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?channelId=chKl9SW3AAAE.&opened_at_gte=$TIMESTAMP_24H_AGO" \
-H "X-Auth-Token: your-api-key"
Typical Use Cases¶
Scenario 1: Real-time Monitoring¶
Task: Display dashboard with current viewers
Solution:
#!/bin/bash
# realtime-dashboard.sh
API_URL="https://catena.example.com/tv-management/api/v1"
API_KEY="your-api-key"
while true; do
# Get active sessions
RESPONSE=$(curl -s -X GET "$API_URL/play-sessions?active=true" \
-H "X-Auth-Token: $API_KEY")
# Total viewers
TOTAL_VIEWERS=$(echo $RESPONSE | jq '.sessions | length')
# Top-5 popular channels
TOP_CHANNELS=$(echo $RESPONSE | jq -r '.sessions | group_by(.channelName) |
map({channel: .[0].channelName, viewers: length}) |
sort_by(.viewers) | reverse | .[0:5]')
clear
echo "=== Current Viewers ==="
echo "Total: $TOTAL_VIEWERS"
echo ""
echo "Top channels:"
echo "$TOP_CHANNELS" | jq -r '.[] | "\(.channel): \(.viewers) viewers"'
sleep 10
done
Python version with Prometheus metrics:
import requests
import time
from prometheus_client import Gauge, start_http_server
# Metrics
active_sessions = Gauge('catena_active_sessions', 'Number of active sessions')
channel_viewers = Gauge('catena_channel_viewers', 'Viewers per channel', ['channel'])
API_URL = "https://catena.example.com/tv-management/api/v1"
API_KEY = "your-api-key"
def update_metrics():
response = requests.get(
f"{API_URL}/play-sessions?active=true",
headers={"X-Auth-Token": API_KEY}
)
sessions = response.json()['sessions']
# Update total count
active_sessions.set(len(sessions))
# Count by channels
channels = {}
for session in sessions:
channel = session['channelName']
channels[channel] = channels.get(channel, 0) + 1
# Update channel metrics
for channel, count in channels.items():
channel_viewers.labels(channel=channel).set(count)
if __name__ == '__main__':
# Start HTTP server for Prometheus
start_http_server(8000)
while True:
update_metrics()
time.sleep(30)
Scenario 2: Subscriber Issue Debugging¶
Task: Subscriber complains they can't watch channel
Debugging steps:
- Check subscriber's active sessions:
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?subscriberId=sKl9SW3AAAE.&active=true" \
-H "X-Auth-Token: your-api-key"
Analysis:
- If no sessions — authorization or network issue
- If session exists — check updatedAt
(recently updated?)
- Check IP and userAgent — match subscriber's device?
- Check recent session history:
# Last 1 hour
TIMESTAMP_1H_AGO=$(date -d '1 hour ago' +%s)
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/play-sessions?subscriberId=sKl9SW3AAAE.&opened_at_gte=$TIMESTAMP_1H_AGO" \
-H "X-Auth-Token: your-api-key"
What to look for: - Frequent reconnections (many short sessions) - Low data transfer (streaming issues) - Different IP addresses (subscriber switching networks)
- Check if subscriber can watch specific channel:
# Check subscriptions
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/subscribers/sKl9SW3AAAE." \
-H "X-Auth-Token: your-api-key" \
| jq '.packages'
# Check which packages have this channel
curl -X GET "https://your-catena-domain.com/tv-management/api/v1/channels/chKl9SW3AAAE." \
-H "X-Auth-Token: your-api-key" \
| jq '.packages'
Best Practices¶
Periodic Data Collection¶
Recommendations:
- Active sessions: poll every 30-60 seconds for monitoring
- History: collect once daily for analysis
- Archiving: move old data (>30 days) to cold storage
Example cron jobs:
# Every minute — monitor active sessions
*/1 * * * * /usr/local/bin/monitor-active-sessions.sh
# Every hour — collect statistics
0 * * * * /usr/local/bin/collect-hourly-stats.sh
# Daily at 01:00 — generate reports
0 1 * * * /usr/local/bin/generate-daily-report.sh
Query Optimization¶
Use filters to reduce data volume:
# BAD — get all sessions
curl -X GET "$API_URL/play-sessions"
# GOOD — only active
curl -X GET "$API_URL/play-sessions?active=true"
# BETTER — active from last hour
TIMESTAMP_1H=$(date -d '1 hour ago' +%s)
curl -X GET "$API_URL/play-sessions?active=true&opened_at_gte=$TIMESTAMP_1H"
Troubleshooting¶
Sessions Not Created¶
Problem: Subscribers watching but sessions don't appear in API
Possible causes:
- Streaming server not integrated with Management API
- Incorrect webhook configuration on streaming server
- Network issues between servers
Solution:
- Check streaming server (Flussonic) configuration
- Ensure webhook configured for Management API
- Check streaming server logs for errors
Sessions Not Closing¶
Problem: Sessions remain active after viewing stopped
Causes:
- Subscriber closed app without proper stream stop
- Network connection lost
- Streaming server didn't send closing webhook
Solution:
- Sessions have timeout (usually 5-10 minutes of inactivity)
- Check
updatedAt
field — if not updated recently, session is "dead" - Configure automatic cleanup of "stuck" sessions
See Also¶
- Subscriber Management — creating and configuring accounts
- Channel Management — setting up TV channels
- Operations Log — system action audit
- Portal Management — data isolation between portals