388 lines
14 KiB
Bash
388 lines
14 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
###
|
|
# JItsi Log Observer - command line interface
|
|
#
|
|
# Bash script for Jitsi Meet components (Videobridge, Jicofo, etc.) logs parsing
|
|
# Command line interface (jilo-cli)
|
|
###
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" #"
|
|
|
|
### Configuration file (overrides default configs)
|
|
CONFIG_FILE="$SCRIPT_DIR/jilo.conf"
|
|
|
|
### Default configuration
|
|
|
|
# Default database type (sqlite, mysql|mariadb)
|
|
DEFAULT_DB_TYPE="sqlite"
|
|
# Default SQLite database file
|
|
DEFAULT_DB="$SCRIPT_DIR/jilo.db"
|
|
# Default MySQL/MariaDB configuration
|
|
DEFAULT_MYSQL_HOST="localhost"
|
|
DEFAULT_MYSQL_USER="jilo"
|
|
DEFAULT_MYSQL_PASS="jilopass"
|
|
DEFAULT_MYSQL_DB="jilo_db"
|
|
|
|
# Load configurations from the config file if it exists
|
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
source "$CONFIG_FILE"
|
|
fi
|
|
|
|
# use default values if not overriden by config file
|
|
DB=${DB:-$DEFAULT_DB}
|
|
DB_TYPE=${DB_TYPE:-$DEFAULT_DB_TYPE}
|
|
MYSQL_HOST=${MYSQL_HOST:-$DEFAULT_MYSQL_HOST}
|
|
MYSQL_USER=${MYSQL_USER:-$DEFAULT_MYSQL_USER}
|
|
MYSQL_PASS=${MYSQL_PASS:-$DEFAULT_MYSQL_PASS}
|
|
MYSQL_DB=${MYSQL_DB:-$DEFAULT_MYSQL_DB}
|
|
|
|
###
|
|
|
|
# DB queries
|
|
db_stats_conferences_all_template="SELECT * FROM conferences;"
|
|
db_stats_conferences_name_template="SELECT * FROM conferences WHERE conference_name='%s';"
|
|
db_stats_conferences_id_template="SELECT * FROM conferences WHERE conference_id='%s';"
|
|
|
|
db_stats_conference_events_template="SELECT * FROM conference_events WHERE conference_id='%s';"
|
|
db_stats_participant_events_template="SELECT * FROM participant_events WHERE event_param='%s';"
|
|
|
|
db_stats_conference_by_id_template="
|
|
SELECT DISTINCT
|
|
c.conference_id,
|
|
c.conference_name,
|
|
c.conference_host,
|
|
COALESCE(ce.time, pe.time) AS event_time,
|
|
ce.loglevel AS conference_loglevel,
|
|
ce.conference_event,
|
|
ce.conference_param,
|
|
p.endpoint_id,
|
|
pe.time AS participant_time,
|
|
pe.loglevel AS participant_loglevel,
|
|
pe.event_type,
|
|
pe.event_param
|
|
FROM
|
|
conferences c
|
|
LEFT JOIN
|
|
conference_events ce ON c.conference_id = ce.conference_id
|
|
LEFT JOIN
|
|
participants p ON c.conference_id = p.conference_id
|
|
LEFT JOIN
|
|
participant_events pe ON p.endpoint_id = pe.participant_id
|
|
WHERE
|
|
c.conference_id = '%s'
|
|
ORDER BY
|
|
event_time;"
|
|
|
|
db_stats_conference_by_name_template="
|
|
SELECT DISTINCT
|
|
c.conference_id,
|
|
c.conference_name,
|
|
c.conference_host,
|
|
COALESCE(ce.time, pe.time) AS event_time,
|
|
ce.loglevel AS conference_loglevel,
|
|
ce.conference_event,
|
|
ce.conference_param,
|
|
p.endpoint_id,
|
|
pe.time AS participant_time,
|
|
pe.loglevel AS participant_loglevel,
|
|
pe.event_type,
|
|
pe.event_param
|
|
FROM
|
|
conferences c
|
|
LEFT JOIN
|
|
conference_events ce ON c.conference_id = ce.conference_id
|
|
LEFT JOIN
|
|
participants p ON c.conference_id = p.conference_id
|
|
LEFT JOIN
|
|
participant_events pe ON p.endpoint_id = pe.participant_id
|
|
WHERE
|
|
c.conference_name = '%s'
|
|
ORDER BY
|
|
event_time;"
|
|
|
|
db_stats_conferences_time_template="SELECT * FROM conferences WHERE start >= '%s' AND end <= '%s';"
|
|
|
|
db_stats_participants_all_template="SELECT * FROM participants;"
|
|
db_stats_participants_conference_template="SELECT * FROM participants WHERE conference_id='%s';"
|
|
db_stats_participants_event_template="SELECT * FROM participants WHERE event_type LIKE '%%%s%%';"
|
|
db_stats_participants_endpoint_template="SELECT * FROM participants WHERE endpoint_id='%s';"
|
|
db_stats_participants_statsid_template="SELECT * FROM participants WHERE stats_id LIKE '%%%s%%';"
|
|
db_stats_participants_ip_template="SELECT * FROM participants WHERE participant_ip='%s';"
|
|
|
|
|
|
help="Usage:
|
|
$0 [OPTION]
|
|
Options:
|
|
--conference|-c [conference ID or name] - show specific conference(s), all of empty
|
|
--participant|-p [conference ID, participant IP, or word from the event type or stats ID] - show specific participant(s), all if empty
|
|
--time|-t - show stats for a time interval"
|
|
|
|
###
|
|
|
|
# First we check for requirements
|
|
check_requirements() {
|
|
# required programs, anything non-bash - edit as needed
|
|
# deb packages - sqlite3
|
|
local required_programs=("sqlite3")
|
|
local requirements_missing=''
|
|
for program in "${required_programs[@]}"; do
|
|
if ! command -v "$program" &> /dev/null; then
|
|
requirements_missing+="$program, "
|
|
fi
|
|
done
|
|
if [[ "$requirements_missing" != '' ]]; then
|
|
requirements_missing=${requirements_missing::-2}
|
|
echo "Error: $requirements_missing - not found. Please install to proceed."
|
|
exit 1
|
|
fi
|
|
}
|
|
check_requirements
|
|
|
|
###
|
|
|
|
# DB functions for Sqlite3 and for MySQL/MariaDB
|
|
|
|
# execute a query and return the result
|
|
db_query() {
|
|
local query=$1
|
|
if [[ "$DB_TYPE" == "sqlite" ]]; then
|
|
sqlite3 "$DB" "$query"
|
|
elif [[ "$DB_TYPE" == "mysql" || "$DB_TYPE" == "mariadb" ]]; then
|
|
mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p "$MYSQL_PASS" -D "$MYSQL_DB" -se "$query"
|
|
else
|
|
echo "Error: unknown database type $DB_TYPE."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
### input parameters parsing
|
|
|
|
# time parameters
|
|
parse_time_range() {
|
|
local time_range="$1"
|
|
|
|
## exact times
|
|
# exact date given (YYYY-MM-DD)
|
|
if [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})$ ]]; then
|
|
from_time="${BASH_REMATCH[0]}"
|
|
until_time="${BASH_REMATCH[0]}"
|
|
# exact month given (YYYY-MM)
|
|
elif [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2})$ ]]; then
|
|
from_time="${BASH_REMATCH[0]}-01"
|
|
until_time="${BASH_REMATCH[0]}-31"
|
|
# exact year given (YYYY)
|
|
elif [[ "$time_range" =~ ^([0-9]{4})$ ]]; then
|
|
from_time="${BASH_REMATCH[0]}-01-01"
|
|
until_time="${BASH_REMATCH[0]}-12-31"
|
|
|
|
## exact periods
|
|
# from date to date
|
|
elif [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2}):([0-9]{4})-([0-9]{2})-([0-9]{2})$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
|
|
until_time="${BASH_REMATCH[4]}-${BASH_REMATCH[5]}-${BASH_REMATCH[6]}"
|
|
# from month to month
|
|
elif [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2}):([0-9]{4})-([0-9]{2})$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-01"
|
|
until_time="${BASH_REMATCH[3]}-${BASH_REMATCH[4]}-31"
|
|
# from year to year
|
|
elif [[ "$time_range" =~ ^([0-9]{4}):([0-9]{4})$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-01-01"
|
|
until_time="${BASH_REMATCH[2]}-12-31"
|
|
|
|
## only end time given
|
|
# from begining until date (:YYYY-MM-DD)
|
|
elif [[ "$time_range" =~ ^:([0-9]{4})-([0-9]{2})-([0-9]{2})$ ]]; then
|
|
from_time="0000-01-01"
|
|
until_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
|
|
# from begining until month (:YYYY-MM)
|
|
elif [[ "$time_range" =~ ^:([0-9]{4})-([0-9]{2})$ ]]; then
|
|
from_time="0000-01-01"
|
|
until_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-31"
|
|
# from begining until year (:YYYY)
|
|
elif [[ "$time_range" =~ ^:([0-9]{4})$ ]]; then
|
|
from_time="0000-01-01"
|
|
until_time="${BASH_REMATCH[0]}-12-31"
|
|
|
|
## only start time given
|
|
# from date until end (YYYY-MM-DD:)
|
|
elif [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2}):$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
|
|
until_time="9999-12-31"
|
|
# from month until end (YYYY-MM:)
|
|
elif [[ "$time_range" =~ ^([0-9]{4})-([0-9]{2}):$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-01"
|
|
until_time="9999-12-31"
|
|
# from year until end (YYYY:)
|
|
elif [[ "$time_range" =~ ^([0-9]{4}):$ ]]; then
|
|
from_time="${BASH_REMATCH[1]}-01-01"
|
|
until_time="9999-12-31"
|
|
|
|
else
|
|
echo -e "Invalid time range. Expected formats:
|
|
- exact times
|
|
YYYY-MM-DD, YYYY-MM, YYYY
|
|
- exact periods
|
|
YYYY-MM-DD:YYYY-MM-DD, YYYY-MM:YYYY-MM, YYYY:YYYY
|
|
- from begining to given time
|
|
:YYYY-MM-DD, :YYYY-MM, :YYYY
|
|
- from given time until end
|
|
YYYY-MM-DD:, YYYY-MM:, YYYY:" >&2
|
|
exit 1
|
|
fi
|
|
|
|
time_range_specified=true
|
|
}
|
|
|
|
### commandline options
|
|
|
|
cmd=""
|
|
conference_arg=""
|
|
participant_arg=""
|
|
from_time=""
|
|
until_time=""
|
|
time_range_specified=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-c | --conference )
|
|
cmd="--conference"
|
|
if [[ -n "$2" && "$2" != -* ]]; then
|
|
conference_arg="$2"
|
|
shift 2
|
|
else
|
|
shift
|
|
fi
|
|
;;
|
|
-p | --participant)
|
|
cmd="--participant"
|
|
if [[ -n "$2" && "$2" != -* ]]; then
|
|
participant_arg="$2"
|
|
shift 2
|
|
else
|
|
shift
|
|
fi
|
|
;;
|
|
-t | --time)
|
|
cmd="--time"
|
|
if [[ -n "$2" && "$2" != -* ]]; then
|
|
parse_time_range "$2"
|
|
shift 2
|
|
else
|
|
echo "Option -t needs time range argument in format 'from-time - until-time', YYYY-MM-DD - YYYY-MM-DD" >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
-h | --help)
|
|
echo -e "$help"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Invalid option: $1" >&2
|
|
echo -e "$help"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
case "$cmd" in
|
|
|
|
--conference)
|
|
# the argument to "--conference" can be either ID or name
|
|
if [[ -n "$conference_arg" ]]; then
|
|
|
|
db_stats_conferences_id=$(printf "$db_stats_conferences_id_template" "$conference_arg")
|
|
stats_conferences_id=$(db_query "$db_stats_conferences_id")
|
|
|
|
db_stats_conferences_name=$(printf "$db_stats_conferences_name_template" "$conference_arg")
|
|
stats_conferences_name=$(db_query "$db_stats_conferences_name")
|
|
|
|
# we check if the argument to "--conference" is a conference ID
|
|
# conference ID is unique, so we show that conference
|
|
if [[ -n "$stats_conferences_id" ]]; then
|
|
db_stats_conference=$(printf "$db_stats_conference_by_id_template" "$conference_arg")
|
|
mapfile -t stats_conference_array < <(db_query "$db_stats_conference")
|
|
|
|
current_conference=""
|
|
for row in "${stats_conference_array[@]}"; do
|
|
IFS='|' read -r conference_id conference_name conference_host conference_time loglevel conference_event conference_param endpoint_id participant_time loglevel event_type event_param <<< "$row"
|
|
|
|
if [[ -z "$current_conference" ]]; then
|
|
current_conference="$conference_name"
|
|
echo "$conference_time | $conference_id | $conference_name | $conference_host | $loglevel | Conference created"
|
|
fi
|
|
|
|
if [[ -n "$conference_event" ]]; then
|
|
echo "$participant_time | $conference_id | $conference_name | $conference_host | $loglevel | $endpoint_id | $event_type | $event_param"
|
|
fi
|
|
done
|
|
echo "$conference_time | $conference_id | $conference_name | $conference_host | $loglevel | Conference Ended"
|
|
|
|
# then we check if the argument to "--conference" is a conference name
|
|
# if so, we show all matching conferences (conference names are not unique)
|
|
elif [[ -n "$stats_conferences_name" ]]; then
|
|
db_stats_conference=$(printf "$db_stats_conference_by_name_template" "$conference_arg")
|
|
mapfile -t stats_conference_array < <(db_query "$db_stats_conference")
|
|
|
|
current_conference=""
|
|
for row in "${stats_conference_array[@]}"; do
|
|
IFS='|' read -r conference_id conference_name conference_host conference_time loglevel conference_event conference_param endpoint_id participant_time loglevel event_type event_param <<< "$row"
|
|
|
|
if [[ -z "$current_conference" ]]; then
|
|
current_conference="$conference_name"
|
|
echo "$conference_time | $conference_id | $conference_name | $conference_host | $loglevel | Conference created"
|
|
fi
|
|
|
|
if [[ -n "$conference_event" ]]; then
|
|
echo "$participant_time | $conference_id | $conference_name | $conference_host | $loglevel | $endpoint_id | $event_type | $event_param"
|
|
fi
|
|
done
|
|
echo "$conference_time | $conference_id | $conference_name | $conference_host | $loglevel | Conference Ended"
|
|
|
|
# nothing found for neither conference ID or name
|
|
else
|
|
echo "No match found for \"$conference_arg\""
|
|
fi
|
|
exit 0
|
|
else
|
|
# if no argument is given, we show all the conferences
|
|
db_stats_conferences_all=$(printf "$db_stats_conferences_all_template")
|
|
db_query "$db_stats_conferences_all"
|
|
exit 0
|
|
fi
|
|
;;
|
|
|
|
--participant)
|
|
if [[ -n "$participant_arg" ]]; then
|
|
db_stats_participants_conference=$(printf "$db_stats_participants_conference_template" "$participant_arg")
|
|
db_query "$db_stats_participants_conference"
|
|
db_stats_participants_event=$(printf "$db_stats_participants_event_template" "$participant_arg")
|
|
db_query "$db_stats_participants_event"
|
|
db_stats_participants_endpoint=$(printf "$db_stats_participants_endpoint_template" "$participant_arg")
|
|
db_query "$db_stats_participants_endpoint"
|
|
db_stats_participants_statsid=$(printf "$db_stats_participants_statsid_template" "$participant_arg")
|
|
db_query "$db_stats_participants_statsid"
|
|
db_stats_participants_ip=$(printf "$db_stats_participants_ip_template" "$participant_arg")
|
|
db_query "$db_stats_participants_ip"
|
|
exit 0
|
|
else
|
|
db_stats_participants_all=$(printf "$db_stats_participants_all_template" )
|
|
db_query "$db_stats_participants_all"
|
|
exit 0
|
|
fi
|
|
;;
|
|
|
|
--time)
|
|
if [[ "$time_range_specified" == true ]]; then
|
|
db_stats_conferences_time=$(printf "$db_stats_conferences_time_template" "$from_time" "$until_time")
|
|
db_query "$db_stats_conferences_time"
|
|
exit 0
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
echo -e "$help"
|
|
exit 1
|
|
;;
|
|
esac
|