#!/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) ### VERSION="0.1.1" RELEASE_DATE="2024-06-18" 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" DEFAULT_NORMAL_TEXT="\033[0m" DEFAULT_IMPORTANT_TEXT="\033[1m" # 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} NORMAL_TEXT=${NORMAL_TEXT:-$DEFAULT_NORMAL_TEXT} IMPORTANT_TEXT=${IMPORTANT_TEXT:-$DEFAULT_IMPORTANT_TEXT} ### DB queries ## conference related db_conferences_all_formatted_template=" SELECT DISTINCT c.jitsi_component, (SELECT ce.time FROM conference_events ce WHERE ce.conference_id = c.conference_id AND ce.conference_event = 'conference expired') AS start, (SELECT ce.time FROM conference_events ce WHERE ce.conference_id = c.conference_id AND ce.conference_event = 'conference created') AS end, c.conference_id, c.conference_name, (SELECT COUNT(pe.participant_id) FROM participant_events pe WHERE pe.event_type = 'participant joining' AND pe.event_param = c.conference_id) AS participants, name_counts.name_count, c.conference_host FROM conferences c JOIN ( SELECT conference_name, COUNT(*) AS name_count FROM conferences GROUP BY conference_name ) AS name_counts ON c.conference_name = name_counts.conference_name JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE (ce.time >= '%s 00:00:00' AND ce.time <= '%s 23:59:59') ORDER BY c.id;" db_conference_by_id_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE c.conference_id = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" db_conference_by_name_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE c.conference_name = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" ## participant related db_participants_all_template=" SELECT DISTINCT p.jitsi_component, p.endpoint_id, p.conference_id FROM participants p JOIN participant_events pe ON p.endpoint_id = pe.participant_id WHERE pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59' ORDER BY p.id;" db_conference_by_participant_id_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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 p.endpoint_id = '%s' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE participant_id = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" db_participant_by_conference_id_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE ce.conference_id = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" db_participant_by_conference_name_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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 LIKE '%%%s%%' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE c.conference_name LIKE '%%%s%%' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" db_participant_by_stats_id_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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 pe.event_type = 'stats_id' AND pe.event_param LIKE '%%%s%%' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE event_type = 'stats_id' AND event_param LIKE '%%%s%%' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" db_participant_by_ip_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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 pe.event_type = 'pair selected' AND pe.event_param = '%s' AND (pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59') UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE event_type = 'pair selected' AND event_param = '%s' AND (event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59') ORDER BY pe.time;" ## jitsi component related # we use "jitsi_component = %s" (without quotes) # to re-use the query for all components ("jitsi_component = jitsi_component") # for specific component the single quotes are added upon loading the template db_jitsi_components_template=" SELECT jitsi_component, loglevel, time, component_id, event_type, event_param FROM jitsi_components WHERE jitsi_component = %s AND (time >= '%s 00:00:00' AND time <= '%s 23:59:59') ORDER BY time;" ## time period related db_events_by_period_template=" SELECT pe.time, c.conference_id, c.conference_name, c.conference_host, pe.loglevel, pe.event_type, p.endpoint_id AS participant_id, 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 pe.time >= '%s 00:00:00' AND pe.time <= '%s 23:59:59' UNION SELECT ce.time AS event_time, c.conference_id, c.conference_name, c.conference_host, ce.loglevel, ce.conference_event AS event_type, NULL AS participant_id, ce.conference_param AS event_param FROM conferences c LEFT JOIN conference_events ce ON c.conference_id = ce.conference_id WHERE event_time >= '%s 00:00:00' AND event_time <= '%s 23:59:59' ORDER BY pe.time;" help="Usage: $0 [OPTION] Options: --conference|-c [conference ID or name] - show specific conference(s), all of empty --participant|-p [participant endpoint ID, conference ID, conference name, participant IP, or participant stats ID] - show specific participant(s), all if empty --jitsi-component|-j [jvb|jicofo] - show service level events --time|-t - show stats for a time interval; can be use separately ot together with -c, -p, or -j --verbose|-v - show more details, when available --silent|-s - show less details, more suitable for scripting --help|-h - show this help message --version|-V - show version" version="JILO Jitsi Logs Observer command line client jilo-cli_${VERSION}_${RELEASE_DATE} version $VERSION released on $RELEASE_DATE" time_formats="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:" ### # First we check for requirements check_requirements() { # required programs, anything non-bash - edit as needed # deb packages - sqlite3, util-linux (column) local required_programs=("sqlite3" "column") 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. $time_formats" >&2 exit 1 fi time_range_specified=true } # we have two timestamps in format YYYY-MM-DD HH:MM:SS.sss # calculate and return the durtion in format HH:MM:SS calculate_duration() { start=$(date -d "$1" +"%s") end=$(date -d "$2" +"%s") duration_seconds=$((end - start)) hours=$((duration_seconds / 3600)) duration_seconds_remain=$((duration_seconds % 3600)) minutes=$((duration_seconds_remain / 60)) seconds=$((duration_seconds_remain % 60)) # add leading zeroes duration=$(printf "%02d:%02d:%02d" $hours $minutes $seconds) } ### commandline options conference_arg="" conference_option=false participant_arg="" participant_option=false component_arg="" component_option=false from_time="0000-00-00" until_time="9999-12-31" time_option=false time_range_specified=false # display help if no arguments if [[ $# -eq 0 ]]; then echo -e "$help" exit 0 fi # then check all the options while [[ $# -gt 0 ]]; do case "$1" in -c | --conference ) conference_option=true if [[ -n "$2" && "$2" != -* ]]; then conference_arg="$2" shift 2 else shift fi ;; -p | --participant) participant_option=true if [[ -n "$2" && "$2" != -* ]]; then participant_arg="$2" shift 2 else shift fi ;; -j | --jitsi-component) component_option=true if [[ -n "$2" && "$2" != -* ]]; then component_arg="$2" shift 2 else shift fi ;; -t | --time) time_option=true if [[ -n "$2" && "$2" != -* ]]; then parse_time_range "$2" shift 2 else echo "Option -t needs a time range argument. $time_formats" >&2 exit 1 fi ;; -v | --verbose) verbose=true shift ;; -s | --silent) silent=true shift ;; -h | --help) echo -e "$help" exit 0 ;; -V | --version) echo -e "$version" exit 0 ;; *) echo "Invalid option: $1" >&2 echo -e "$help" exit 1 ;; esac done if [[ "$conference_option" == true ]]; then # the argument to "--conference" can be either ID or name if [[ -n "$conference_arg" ]]; then # check for conferences match within a time period (or all if not period given) db_conferences_id=$(printf "$db_conference_by_id_template" "$conference_arg" "$from_time" "$until_time" "$conference_arg" "$from_time" "$until_time") mapfile -t conferences_id < <(db_query "$db_conferences_id") db_conferences_name=$(printf "$db_conference_by_name_template" "$conference_arg" "$from_time" "$until_time" "$conference_arg" "$from_time" "$until_time") mapfile -t conferences_name < <(db_query "$db_conferences_name") # we check if the argument to "--conference" is a conference ID # conference ID is unique, so we show that conference if [[ "${#conferences_id[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nConferences with ID matching \"$IMPORTANT_TEXT$conference_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${conferences_id[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$IMPORTANT_TEXT$conference_id$NORMAL_TEXT\t$conference_name\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' # 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 [[ "${#conferences_name[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nConferences with names matching \"$IMPORTANT_TEXT$conference_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output="time\tconf ID\tconf name\tconf host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${conferences_name[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$conference_id\t$IMPORTANT_TEXT$conference_name$NORMAL_TEXT\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' # nothing found for neither conference ID or name else if [[ "$silent" != true ]]; then echo "No match found for \"$conference_arg\"" if [[ "$time_range_specified" == true ]]; then echo "and time period $from_time - $until_time" fi fi fi exit 0 else # if no argument is given, we show all the conferences db_conferences_all=$(printf "$db_conferences_all_formatted_template" "$from_time" "$until_time") mapfile -t conference_array < <(db_query "$db_conferences_all") # we only format the outrput if there are conferences to show if [[ "${#conference_array[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nAll conferences" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$IMPORTANT_TEXT$from_time - $until_time$NORMAL_TEXT\"" fi header+="\n" echo -e "$header" output="component\tduration\tconference ID\tconference name\tparticipants\tname count\tconference host\n" fi # prepare the formatted rows for row in "${conference_array[@]}"; do IFS='|' read -r jitsi_component end start conference_id conference_name participants name_count conference_host <<< "$row" calculate_duration "$start" "$end" output+="$jitsi_component\t$duration\t$conference_id\t$conference_name\t$participants\t$name_count\t$conference_host\n" done # output echo -e "$output" | column -t -s $'\t' else if [[ "$silent" != true ]]; then echo -n "No conferences found" if [[ "$time_range_specified" == true ]]; then echo -n " for the time period \"$from_time - $until_time\"" fi echo "." fi fi exit 0 fi elif [[ "$participant_option" == true ]]; then # the argument to "--participant" can be endpointID, conferenceID, conference name, startsID, IP address # check for participants match within a time period (or all if period not given) # we check for all ot them and show the matches ## FIXME - we don't catch the case with no results found at all, no message is displayed if no results ## FIXME if [[ -n "$participant_arg" ]]; then db_participants_endpoint=$(printf "$db_conference_by_participant_id_template" "$participant_arg" "$from_time" "$until_time" "$participant_arg" "$from_time" "$until_time") mapfile -t participants_endpoint < <(db_query "$db_participants_endpoint") db_participants_conference=$(printf "$db_participant_by_conference_id_template" "$participant_arg" "$from_time" "$until_time" "$participant_arg" "$from_time" "$until_time") mapfile -t participants_conference < <(db_query "$db_participants_conference") db_participants_conference_name=$(printf "$db_participant_by_conference_name_template" "$participant_arg" "$from_time" "$until_time" "$participant_arg" "$from_time" "$until_time") mapfile -t participants_conference_name < <(db_query "$db_participants_conference_name") db_participants_statsid=$(printf "$db_participant_by_stats_id_template" "$participant_arg" "$from_time" "$until_time" "$participant_arg" "$from_time" "$until_time") mapfile -t participants_statsid < <(db_query "$db_participants_statsid") db_participants_ip=$(printf "$db_participant_by_ip_template" "$participant_arg" "$from_time" "$until_time" "$participant_arg" "$from_time" "$until_time") mapfile -t participants_ip < <(db_query "$db_participants_ip") # match for participant endpoint_id if [[ "${#participants_endpoint[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nParticipants with ID matching \"$IMPORTANT_TEXT$participant_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${participants_endpoint[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$conference_id\t$conference_name\t$conference_host\t$loglevel\t$IMPORTANT_TEXT$participant_id$NORMAL_TEXT\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' fi # match for conference_id the participant was in if [[ "${#participants_conference[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nParticipants in conferences with ID matching \"$IMPORTANT_TEXT$participant_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output+="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${participants_conference[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$IMPORTANT_TEXT$conference_id$NORMAL_TEXT\t$conference_name\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' fi # match for conference_name the participant was in if [[ "${#participants_conference_name[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nParticipants in conferences with name that include the string \"$IMPORTANT_TEXT$participant_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output+="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${participants_conference_name[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$conference_id\t$IMPORTANT_TEXT$conference_name$NORMAL_TEXT\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' fi # match for participant stats_id if [[ "${#participants_statsid[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nParticipants with stats ID that include the string \"$IMPORTANT_TEXT$participant_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output+="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${participants_statsid[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$conference_id\t$conference_name\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$IMPORTANT_TEXT$event_param$NORMAL_TEXT\n" done # output echo -e "$output" | column -t -s $'\t' fi # match for participant IP if [[ "${#participants_ip[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nParticipants with IP address matching \"$IMPORTANT_TEXT$participant_arg$NORMAL_TEXT\"" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output+="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${participants_ip[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$time\t$conference_id\t$conference_name\t$conference_host\t$loglevel\t$participant_id\t$event_type\t$IMPORTANT_TEXT$event_param$NORMAL_TEXT\n" done # output echo -e "$output" | column -t -s $'\t' fi exit 0 else # if no argument is given, we show all the participants db_participants_all=$(printf "$db_participants_all_template" "$from_time" "$until_time") mapfile -t participant_array < <(db_query "$db_participants_all") # we only format the outrput if there are conferences to show if [[ "${#participant_array[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nAll participants" if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$IMPORTANT_TEXT$from_time - $until_time$NORMAL_TEXT\"" fi header+="\n" echo -e "$header" output+="component\tparticipant ID\tconference ID\n" fi # prepare the formatted rows for row in "${participant_array[@]}"; do IFS='|' read -r jitsi_component endpoint_id conference_id <<< "$row" output+="$jitsi_component\t$endpoint_id\t$conference_id\n" done # output echo -e "$output" | column -t -s $'\t' else if [[ "$silent" != true ]]; then echo -n "No participants found" if [[ "$time_range_specified" == true ]]; then echo -n " for the time period \"$from_time - $until_time\"" fi echo "." fi fi exit 0 fi elif [[ "$component_option" == true ]]; then # argument for "--jitsi-component | -j" can be "jvb", "jicofo" if [[ -n "$component_arg" ]]; then case "$component_arg" in jvb) jitsi_component="'JVB'" ;; jicofo) jitsi_component="'JICOFO'" ;; *) # we have a component events search, but an unknown component string # exiting with error, it's not a recognized option argument echo "Invalid option: $component_arg" >&2 echo -e "$help" exit 1 ;; esac header="\nJitsi components events for \"$IMPORTANT_TEXT$jitsi_component$NORMAL_TEXT\"" else jitsi_component="jitsi_component" header="\nJitsi components events for \"$IMPORTANT_TEXT all components$NORMAL_TEXT\"" fi db_jitsi_components=$(printf "$db_jitsi_components_template" "$jitsi_component" "$from_time" "$until_time") mapfile -t jitsi_components < <(db_query "$db_jitsi_components") output="" # prepare the header if [[ "$silent" != true ]]; then if [[ "$time_range_specified" == true ]]; then header+=" for the time period \"$from_time - $until_time\"" fi header+="\n" echo -e "$header" output+="jitsi_component\tloglevel\ttime\tcomponent ID\tevent\tparameter\n" fi # prepare the formatted rows for row in "${jitsi_components[@]}"; do IFS='|' read -r jitsi_component loglevel time component_id event_type event_param <<< "$row" output+="$jitsi_component\t$loglevel\t$time\t$component_id\t$event_type\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' elif [[ "$time_option" == true ]]; then if [[ "$time_range_specified" == true ]]; then db_events_time=$(printf "$db_events_by_period_template" "$from_time" "$until_time" "$from_time" "$until_time") mapfile -t events_array < <(db_query "$db_events_time") if [[ "${#events_array[@]}" -gt 0 ]]; then output="" # prepare the header if [[ "$silent" != true ]]; then header="\nEvents in the period \"$IMPORTANT_TEXT$from_time - $until_time$NORMAL_TEXT\"\n" output="time\tconference ID\tconference name\tconference host\tloglevel\tparticipant ID\tevent\tparameter\n" echo -e "$header" fi # prepare the formatted rows for row in "${events_array[@]}"; do IFS='|' read -r time conference_id conference_name conference_host loglevel event_type participant_id event_param <<< "$row" output+="$IMPORTANT_TEXT$time$NORMAL_TEXT\t$conference_id\t$conference_name\t$conference_host\t$loglevel\t$event_type\t$participant_id\t$event_param\n" done # output echo -e "$output" | column -t -s $'\t' else if [[ "$silent" != true ]]; then echo -n "No events found" if [[ "$time_range_specified" == true ]]; then echo -n " for the time period \"$from_time - $until_time\"" fi echo "." fi fi exit 0 fi fi