diff --git a/docker-compose.yml b/docker-compose.yml index eb639a4e38..6d37b7eff8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,6 +136,13 @@ services: - RESOLUTION_MIN - RESOLUTION_WIDTH - RESOLUTION_WIDTH_MIN + - RTCSTATS_ENABLED + - RTCSTATS_STORE_LOGS + - RTCSTATS_POLL_INTERVAL + - RTCSTATS_SEND_SDP + - RTCSTATS_URL_BASE + - RTC_VISUALIZER_URL_BASE + - RTC_VISUALIZER_PATH - START_AUDIO_MUTED - START_AUDIO_ONLY - START_SILENT diff --git a/env.example b/env.example index 07eae6a766..2d90ce065b 100644 --- a/env.example +++ b/env.example @@ -82,6 +82,21 @@ TZ=UTC # Set etherpad-lite public URL, including /p/ pad path fragment (uncomment to enable) #ETHERPAD_PUBLIC_URL=https://etherpad.my.domain/p/ +# +# rtcstats integration +# + +# Enable rtcstats analytics (uncomment to enable) +#RTCSTATS_ENABLED=true + +# Send the console logs to the rtcstats server +#RTCSTATS_STORE_LOGS=true + +# The interval at which rtcstats will poll getStats, defaults to 10000ms. +#RTCSTATS_POLL_INTERVAL=10000 + +# Send the SDP to the rtcstats server +#RTCSTATS_SEND_SDP=true # # Whiteboard integration diff --git a/log-analyser/grafana-provisioning/dashboards/rtcstats.json b/log-analyser/grafana-provisioning/dashboards/rtcstats.json new file mode 100644 index 0000000000..d9b54c7b06 --- /dev/null +++ b/log-analyser/grafana-provisioning/dashboards/rtcstats.json @@ -0,0 +1,666 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "session count" + }, + "properties": [ + { + "id": "displayName", + "value": "Session Count" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "error count" + }, + "properties": [ + { + "id": "displayName", + "value": "Session Error Count" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "increase(rtcstats_session_count[$__range])", + "format": "time_series", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "session count", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(rtcstats_session_error_count[$__range])", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "error count", + "useBackend": false + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "left", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "displayName", + "value": "websocket connections" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "displayName", + "value": "websocket connections error" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "rtcstats_websocket_connections", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "rate(rtcstats_websocket_connection_error[$__rate_interval])", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Websocket Connection", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "rtcstats" + }, + "properties": [ + { + "id": "displayName", + "value": "rtcstats client" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "jvb" + }, + "properties": [ + { + "id": "displayName", + "value": "jvb" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "jicofo" + }, + "properties": [ + { + "id": "displayName", + "value": "jicofo" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "jibri" + }, + "properties": [ + { + "id": "displayName", + "value": "jibri" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "jigasi" + }, + "properties": [ + { + "id": "displayName", + "value": "jigasi" + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "unknown" + }, + "properties": [ + { + "id": "displayName", + "value": "unknown" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(rtcstats_dump_size_bytes_count[$__rate_interval])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "rtcstats", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "increase(jvb_dump_size_bytes_count[$__rate_interval])", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "jvb", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "editorMode": "code", + "expr": "increase(jicofo_dump_size_bytes_count[$__rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "jicofo" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "editorMode": "code", + "expr": "increase(jibri_dump_size_bytes_count[$__rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "jibri" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "editorMode": "code", + "expr": "increase(jigasi_dump_size_bytes_count[$__rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "jigasi" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "editorMode": "code", + "expr": "increase(unknown_dump_size_bytes_count[$__rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "unknown" + } + ], + "title": "Dump Size Bytes Count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "d301145e-8c4e-4027-bf6e-43e81f095020" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "rtcstats_disk_queue_size", + "format": "time_series", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Disk Queue Size", + "type": "timeseries" + } + ], + "refresh": "30s", + "schemaVersion": 38, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "rtcstats", + "uid": "e4e8c548-c977-4f95-bc91-995d0a757f8e", + "version": 2, + "weekStart": "" +} diff --git a/rtcstats.yml b/rtcstats.yml new file mode 100644 index 0000000000..27421f9fd9 --- /dev/null +++ b/rtcstats.yml @@ -0,0 +1,31 @@ +services: + + rtcstats-server: + image: jitsi/rtcstats-server + restart: ${RESTART_POLICY:-unless-stopped} + expose: + - '3000' + - '8095' + env_file: + - ./rtcstats/.env + - ./rtcstats/rtcstats-server/.env + networks: + meet.jitsi: + aliases: + - rtcstats-server.meet.jitsi + + + rtc-visualizer: + image: jitsi/rtcstats-visualizer + restart: ${RESTART_POLICY:-unless-stopped} + expose: + - '8087' + volumes: + - ./rtcstats/rtc-visualizer/.data:/rtc-visualizer/.data + env_file: + - ./rtcstats/.env + - ./rtcstats/rtc-visualizer/.env + networks: + meet.jitsi: + aliases: + - rtc-visualizer.meet.jitsi diff --git a/rtcstats/README.md b/rtcstats/README.md new file mode 100644 index 0000000000..d7c1e03103 --- /dev/null +++ b/rtcstats/README.md @@ -0,0 +1,83 @@ +# Meeting stats with rtcstats + +## Overview + +This project demonstrates how to use rtcstats with Jitsi Meet to gather detailed information about meeting quality and logs. + +## Getting Started + +### Setup + +1. **Update Jitsi Meet Docker Compose Configuration** + + Edit `.env` in your `docker-jitsi-meet` directory to enable rtcstats. + ``` + # + # rtcstats integration + # + + # Enable rtcstats analytics (uncomment to enable) + RTCSTATS_ENABLED=true + + # Send the console logs to the rtcstats server + RTCSTATS_STORE_LOGS=false + + # The interval at which rtcstats will poll getStats, defaults to 10000ms. + RTCSTATS_POLL_INTERVAL=10000 + + # Send the SDP to the rtcstats server + RTCSTATS_SEND_SDP=true + + ``` + +2. **Configure rtcstats** + + Copy the example environment files and edit them according to your environment. + ```shell + docker-jitsi-meet/rtcstats$ cp env.example .env + docker-jitsi-meet/rtcstats$ cp ./rtcstats-server/env.example ./rtcstats-server/.env + docker-jitsi-meet/rtcstats$ cp ./rtc-visualizer/env.example ./rtc-visualizer/.env + ``` + + Next, edit `rtc-visualizer/.data/users.json` to add your users. The default credential is `admin:CHANGE_ME`. + ```json + { + "Alice": "XXX", + "Bob": "YYY" + } + ``` + +4. **Run Docker Compose** + + From your `docker-jitsi-meet` directory, run the following command to start all services. + ```shell + docker compose -f docker-compose.yml -f rtcstats.yml up -d + ``` + + +## Usage + +1. **View RTC Visualizer** + + Open [https://localhost:8443/rtc-visualizer](https://localhost:8443/rtc-visualizer) (or `PUBLIC_URL/rtc-visualizer`) in your browser. + +## Monitoring with Prometheus + +1. **Update Prometheus Configuration** + + Add the rtcstats-server endpoint to `prometheus/prometheus.yml`. + ```yml + scrape_configs: + - job_name: "prometheus" + # ... other configurations + static_configs: + - targets: ["...","rtcstats-server:8095"] + ``` + +2. **Run Docker Compose** + + Restart your environment with the `prometheus.yml` and `grafana.yml` files to launch the monitoring services. + + ```shell + docker compose -f docker-compose.yml -f rtcstats.yml -f prometheus.yml -f grafana.yml up -d + ``` diff --git a/rtcstats/env.example b/rtcstats/env.example new file mode 100644 index 0000000000..146285cb09 --- /dev/null +++ b/rtcstats/env.example @@ -0,0 +1,23 @@ +# Set the service type. Can be "AWS" or "MongoDB". +RTCSTATS_SERVICE_TYPE=AWS + +# For AWS credentials +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_REGION= + +# For local S3 and DynamoDB +RTCSTATS_S3_ENDPOINT= +RTCSTATS_DYNAMODB_ENDPOINT= + +# DynamoDB Table for rtcstats +RTCSTATS_METADATA_TABLE=rtcstats-meta-table-local + +# S3 Bucket for rtcstats +RTCSTATS_S3_BUCKET=jitsi-micros-rtcstats-server + +# For MongoDB +#RTCSTATS_MONGODB_URI=mongodb://root:root@mongodb.meet.jitsi:27017 +#RTCSTATS_MONGODB_NAME=rtcstats-db +#RTCSTATS_METADATA_COLLECTION=rtcstats-meta-collection +#RTCSTATS_GRIDFS_BUCKET=rtcstats-dump-file-bucket diff --git a/rtcstats/localstack/README.md b/rtcstats/localstack/README.md new file mode 100644 index 0000000000..63f3f0f77a --- /dev/null +++ b/rtcstats/localstack/README.md @@ -0,0 +1,49 @@ +## Using Localstack + +This section describes how to use Localstack to test and verify your rtcstats setup. Localstack simulates AWS cloud services (like S3) on your local machine, allowing you to confirm that statistics are being saved correctly without needing an actual AWS account. + +### Setup + + +1. **Configure Network Alias for Custom S3 Bucket** + + If you are using a custom S3 bucket name, you must add it as a network alias in `localstack.yml`. This allows the rtcstats-server and rtc-visualizer to resolve the bucket's address to the Localstack container. + + Edit the `networks` section for the `localstack` service in `rtcstats/localstack/localstack.yml`: + ```yml + services: + + localstack: + # ... (other settings) + networks: + meet.jitsi: + aliases: + # - jitsi-micros-rtcstats-server.s3.localstack # Default example + - YOUR_RTCSTATS_S3_BUCKET.s3.localstack + ``` + **Note:** Replace `YOUR_RTCSTATS_S3_BUCKET` with the actual bucket name you defined in your environment variables. + + To enable the AWS SDK to make Virtual-Hosted-Style requests to S3, you need to also configure the endpoints in `rtcstats/.env` as follows: + ``` + RTCSTATS_S3_ENDPOINT=http://s3.localstack:4566 + RTCSTATS_DYNAMODB_ENDPOINT=http://localstack:4566 + ``` + +2. **Run Docker Compose with Localstack** + + From your `docker-jitsi-meet` directory, run the following command to start all services, including Jitsi Meet, rtcstats, and Localstack. + ```shell + docker compose -f docker-compose.yml -f rtcstats.yml -f ./rtcstats/localstack/localstack.yml up -d + ``` + + +### Troubleshooting + +- **502 Bad Gateway on RTC Visualizer** + + If you encounter a `502 Bad Gateway` error when accessing the RTC Visualizer, you may need to restart the `jitsi/web` container. + + Run the following command from your docker-jitsi-meet directory to resolve the issue: + ```shell + docker compose restart web + ``` diff --git a/rtcstats/localstack/localstack.yml b/rtcstats/localstack/localstack.yml new file mode 100644 index 0000000000..2ff40b7579 --- /dev/null +++ b/rtcstats/localstack/localstack.yml @@ -0,0 +1,38 @@ +services: + + rtcstats-setup: + image: jitsi/rtcstats-server + env_file: + - ./rtcstats/.env + entrypoint: /bin/sh + command: > + -c ' + node ./infra-samples/aws/create-dynamodb-table.js && + node ./infra-samples/aws/create-s3-bucket.js + ' + networks: + meet.jitsi: + depends_on: + - localstack + + + localstack: + container_name: localstack + image: localstack/localstack + ports: + - 4566:4566 + env_file: + - ./rtcstats/.env + environment: + # LocalStack configuration: https://docs.localstack.cloud/references/configuration/ + - SERVICES=s3,dynamodb + - DEBUG=${DEBUG:-1} + - AWS_ACCESS_KEY_ID=dummy + - AWS_SECRET_ACCESS_KEY=dummy + - AWS_DEFAULT_REGION=us-east-1 + - AWS_DEFAULT_OUTPUT=json + - AWS_ENDPOINT_URL=http://localstack:4566 + networks: + meet.jitsi: + aliases: + - jitsi-micros-rtcstats-server.s3.localstack diff --git a/rtcstats/mongodb/.gitignore b/rtcstats/mongodb/.gitignore new file mode 100644 index 0000000000..8fce603003 --- /dev/null +++ b/rtcstats/mongodb/.gitignore @@ -0,0 +1 @@ +data/ diff --git a/rtcstats/mongodb/README.md b/rtcstats/mongodb/README.md new file mode 100644 index 0000000000..7ff61a82fe --- /dev/null +++ b/rtcstats/mongodb/README.md @@ -0,0 +1,29 @@ +## Using MongoDB + +This section describes how to use MongoDB for rtcstats. + +### Setup + + +1. **Configure Environment Variables** + + Edit the MongoDB environment variables in `rtcstats/.env`: + ``` + # Set the service type. Can be "AWS" or "MongoDB". + RTCSTATS_SERVICE_TYPE=MongoDB + + ... + + # For MongoDB + RTCSTATS_MONGODB_URI=mongodb://root:root@mongodb.meet.jitsi:27017 + RTCSTATS_MONGODB_NAME=rtcstats-db + RTCSTATS_METADATA_COLLECTION=rtcstats-meta-collection + RTCSTATS_GRIDFS_BUCKET=rtcstats-dump-file-bucket + ``` + +2. **Run Docker Compose with MongoDB** + + From your `docker-jitsi-meet` directory, run the following command to start all services, including Jitsi Meet, rtcstats, and Localstack. + ```shell + docker compose -f docker-compose.yml -f rtcstats.yml -f ./rtcstats/mongodb/mongodb.yml up -d + ``` \ No newline at end of file diff --git a/rtcstats/mongodb/mongodb.yml b/rtcstats/mongodb/mongodb.yml new file mode 100644 index 0000000000..82280f70f1 --- /dev/null +++ b/rtcstats/mongodb/mongodb.yml @@ -0,0 +1,13 @@ +services: + + mongodb: + image: mongo + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: root + volumes: + - ./rtcstats/mongodb/data:/data/db + networks: + meet.jitsi: + aliases: + - mongodb.meet.jitsi diff --git a/rtcstats/rtc-visualizer/.data/users.json b/rtcstats/rtc-visualizer/.data/users.json new file mode 100644 index 0000000000..7d39d45c58 --- /dev/null +++ b/rtcstats/rtc-visualizer/.data/users.json @@ -0,0 +1,3 @@ +{ + "admin": "CHANGE_ME" +} diff --git a/rtcstats/rtc-visualizer/env.example b/rtcstats/rtc-visualizer/env.example new file mode 100644 index 0000000000..4ebf920e77 --- /dev/null +++ b/rtcstats/rtc-visualizer/env.example @@ -0,0 +1,5 @@ +# rtc-visualizer +#RTCSTATS_FILES_ENDPOINT= +#RTCSTATS_JWT_PUBLIC_KEY= +#RTCSTATS_JWT_EGHT_PUBLIC_KEY= +USERS_FILE=.data/users.json diff --git a/rtcstats/rtcstats-server/env.example b/rtcstats/rtcstats-server/env.example new file mode 100644 index 0000000000..9a320a240a --- /dev/null +++ b/rtcstats/rtcstats-server/env.example @@ -0,0 +1,37 @@ +# rtcstats-server: server config +#RTCSTATS_LOG_LEVEL +#RTCSTATS_ENVIRONMENT +#RTCSTATS_KEYPATH=./certs/key.pem +#RTCSTATS_CERTPATH=./certs/cert.pem +#RTCSTATS_TEMPPATH=temp +RTCSTATS_HTTPS=false +#RTCSTATS_SKIP_LOAD_BALANCER_IP +#RTCSTATS_JSON_CONSOLE_LOG + +# rtcstats-server: amplitude +# RTCSTATS_AMPLITUDE_KEY= + +# rtcstats-server: firehose +#RTCSTATS_FIREHOSE_AWS_REGION +#RTCSTATS_FIREHOSE_MEETING_STREAM +#RTCSTATS_FIREHOSE_PC_STREAM +#RTCSTATS_FIREHOSE_TRACKS_STREAM +#RTCSTATS_FIREHOSE_E2E_PING_STREAM +#RTCSTATS_FIREHOSE_FACE_LANDMARKS_STREAM +#RTCSTATS_FIREHOSE_MEETING_EVENT_STREAM + +# rtcstats-server: s3 +#RTCSTATS_S3_ACCESSKEYID +#RTCSTATS_S3_SECRETACCESSKEY +RTCSTATS_S3_AWS_REGION=us-east-1 +RTCSTATS_S3_USEIAMAUTH=true +#RTCSTATS_S3_SIGNEDLINKEXPIRATIONSEC + +# rtcstats-server: webhooks +#RTCSTATS_WEBHOOK_ENDPOINT +#RTCSTATS_JWT_AUDIENCE +#RTCSTATS_JWT_ISSUER + +# rtcstats-server: secretmanager +#RTCSTATS_AWS_SECRET_REGION +#RTCSTATS_JWT_SECRET_ID diff --git a/web/rootfs/defaults/meet.conf b/web/rootfs/defaults/meet.conf index a0cd384a63..42f8a30771 100644 --- a/web/rootfs/defaults/meet.conf +++ b/web/rootfs/defaults/meet.conf @@ -9,6 +9,10 @@ {{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}} {{ $XMPP_BOSH_URL_BASE := .Env.XMPP_BOSH_URL_BASE | default "http://xmpp.meet.jitsi:5280" -}} {{ $CORS_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN := .Env.CORS_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN | default "*" }} +{{ $RTCSTATS_ENABLED := .Env.RTCSTATS_ENABLED | default "false" | toBool -}} +{{ $RTCSTATS_URL_BASE := .Env.RTCSTATS_URL_BASE | default "http://rtcstats-server.meet.jitsi:3000" -}} +{{ $RTC_VISUALIZER_URL_BASE := .Env.RTC_VISUALIZER_URL_BASE | default "http://rtc-visualizer.meet.jitsi:8087" -}} +{{ $RTC_VISUALIZER_PATH := .Env.RTC_VISUALIZER_PATH | default "rtc-visualizer" -}} server_name _; @@ -136,6 +140,36 @@ location ^~ /etherpad/ { } {{ end }} +{{ if $RTCSTATS_ENABLED }} +# rtcstats websockets +location = /rtcstats-ws/ { + tcp_nodelay on; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-For $remote_addr; + + proxy_pass {{ $RTCSTATS_URL_BASE }}/; +} + +# rtc-visualizer +location = /{{ $RTC_VISUALIZER_PATH }} { + return 301 $scheme://$http_host$request_uri/; +} + +location ^~ /{{ $RTC_VISUALIZER_PATH }}/ { + tcp_nodelay on; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-For $remote_addr; + + proxy_pass {{ $RTC_VISUALIZER_URL_BASE }}/; +} +{{ end }} + {{ if .Env.WHITEBOARD_COLLAB_SERVER_URL_BASE }} # whiteboard (excalidraw-backend) location = /socket.io/ { diff --git a/web/rootfs/defaults/settings-config.js b/web/rootfs/defaults/settings-config.js index d4de628122..c0564c822e 100644 --- a/web/rootfs/defaults/settings-config.js +++ b/web/rootfs/defaults/settings-config.js @@ -33,6 +33,7 @@ {{ $ENABLE_JAAS_COMPONENTS := .Env.ENABLE_JAAS_COMPONENTS | default "0" | toBool }} {{ $HIDE_PREJOIN_DISPLAY_NAME := .Env.HIDE_PREJOIN_DISPLAY_NAME | default "false" | toBool -}} {{ $PUBLIC_URL := .Env.PUBLIC_URL | default "https://localhost:8443" -}} +{{ $PUBLIC_URL_DOMAIN := .Env.PUBLIC_URL | default "https://localhost:8443" | trimPrefix "https://" | trimSuffix "/" -}} {{ $RESOLUTION := .Env.RESOLUTION | default "720" -}} {{ $RESOLUTION_MIN := .Env.RESOLUTION_MIN | default "180" -}} {{ $RESOLUTION_WIDTH := .Env.RESOLUTION_WIDTH | default "1280" -}} @@ -68,6 +69,10 @@ {{ $CODEC_ORDER_JVB_MOBILE := .Env.CODEC_ORDER_JVB_MOBILE | default "[\"VP8\", \"VP9\", \"H264\", \"AV1\"]" -}} {{ $CODEC_ORDER_P2P := .Env.CODEC_ORDER_JVB | default "[\"AV1\", \"VP9\", \"VP8\", \"H264\"]" -}} {{ $CODEC_ORDER_P2P_MOBILE := .Env.CODEC_ORDER_JVB_MOBILE | default "[\"VP8\", \"VP9\", \"H264\", \"AV1\"]" -}} +{{ $RTCSTATS_ENABLED := .Env.RTCSTATS_ENABLED | default "false" | toBool -}} +{{ $RTCSTATS_STORE_LOGS := .Env.RTCSTATS_STORE_LOGS | default "false" | toBool -}} +{{ $RTCSTATS_POLL_INTERVAL := .Env.RTCSTATS_POLL_INTERVAL | default 10000 -}} +{{ $RTCSTATS_SEND_SDP := .Env.RTCSTATS_SEND_SDP | default "false" | toBool -}} // Video configuration. // @@ -216,6 +221,15 @@ config.localRecording = { config.analytics = {}; +{{ if $RTCSTATS_ENABLED -}} +// RTCStats configuration. +config.analytics.rtcstatsEnabled = true; +config.analytics.rtcstatsStoreLogs = {{ $RTCSTATS_STORE_LOGS }}; +config.analytics.rtcstatsEndpoint = 'wss://{{ $PUBLIC_URL_DOMAIN }}/rtcstats-ws'; +config.analytics.rtcstatsPollInterval = {{ $RTCSTATS_POLL_INTERVAL }}; +config.analytics.rtcstatsSendSdp = {{ $RTCSTATS_SEND_SDP }}; +{{ end -}} + {{ if .Env.AMPLITUDE_ID -}} // The Amplitude APP Key: config.analytics.amplitudeAPPKey = '{{ .Env.AMPLITUDE_ID }}';